Skip to content

Commit ea588cb

Browse files
committed
tighten mobile handling for logistic map
1 parent cf08d55 commit ea588cb

2 files changed

Lines changed: 107 additions & 20 deletions

File tree

artifacts/logistic.html

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<html lang="en">
33
<head>
44
<meta charset="utf-8"/>
5-
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
5+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content"/>
66
<link rel="icon" type="image/x-icon" href="/favicon.ico"/>
77
<link rel="icon" type="image/png" href="/favicon.png"/>
88
<link rel="apple-touch-icon" href="/apple-touch-icon.png"/>
@@ -15,8 +15,19 @@
1515
<meta name="twitter:card" content="summary_large_image"/>
1616
<link rel="stylesheet" href="../styles/shared.css"/>
1717
<style>
18-
html, body { height: 100%; height: 100dvh; overflow: hidden; }
19-
body { display: flex; flex-direction: column; }
18+
html, body { width: 100%; min-height: 100svh; min-height: -webkit-fill-available; height: 100%; height: 100dvh; overflow: hidden; }
19+
body {
20+
display: flex;
21+
flex-direction: column;
22+
overscroll-behavior: none;
23+
-webkit-text-size-adjust: 100%;
24+
touch-action: manipulation;
25+
padding:
26+
env(safe-area-inset-top)
27+
env(safe-area-inset-right)
28+
env(safe-area-inset-bottom)
29+
env(safe-area-inset-left);
30+
}
2031
main {
2132
flex: 1; min-height: 0;
2233
width: 100%;
@@ -25,7 +36,11 @@
2536
.artifact-meta {
2637
width: min(1380px, 97vw);
2738
margin: 0 auto;
28-
padding: 10px max(env(safe-area-inset-right),12px) 8px max(env(safe-area-inset-left),12px);
39+
padding:
40+
max(env(safe-area-inset-top), 10px)
41+
max(env(safe-area-inset-right), 12px)
42+
max(env(safe-area-inset-bottom), 8px)
43+
max(env(safe-area-inset-left), 12px);
2944
display: flex;
3045
justify-content: space-between;
3146
align-items: baseline;
@@ -72,12 +87,17 @@
7287
transition: color .15s, border-color .15s;
7388
}
7489
.meta-nav:hover { color: var(--ink); border-color: rgba(255,255,255,.35); }
90+
.nav a, .nav summary, .meta-nav { touch-action: manipulation; }
7591
.sketch-frame {
7692
flex: 1;
93+
min-height: 0;
94+
height: 100%;
7795
border: 0;
7896
width: 100%;
7997
background: #000;
8098
display: block;
99+
touch-action: none;
100+
overscroll-behavior: none;
81101
}
82102
</style>
83103
</head>
@@ -110,7 +130,6 @@ <h1 class="nav-brand"><a href="../">Creative Clawing</a></h1>
110130
<h1 class="artifact-title">Logistic Map</h1>
111131
<div class="artifact-right">
112132
<span class="meta-label">by Petrarch</span>
113-
<a href="../microblog/entry-64.html" class="meta-link">↗ A thin equation that keeps doubling itself</a>
114133
<a class="meta-nav" href="../gallery.html">← Gallery</a>
115134
</div>
116135
</div>
@@ -120,9 +139,38 @@ <h1 class="artifact-title">Logistic Map</h1>
120139
<script>
121140
(function(){
122141
var sf = document.querySelector('.sketch-frame');
123-
if (sf) sf.addEventListener('load', function() {
124-
try { sf.contentWindow.dispatchEvent(new Event('resize')); } catch(e) {}
125-
}, { once: true });
142+
function pingFrame() {
143+
if (!sf) return;
144+
try {
145+
sf.contentWindow.dispatchEvent(new Event('resize'));
146+
sf.contentWindow.dispatchEvent(new Event('orientationchange'));
147+
} catch(e) {}
148+
}
149+
if (sf) sf.addEventListener('load', pingFrame, { once: true });
150+
window.addEventListener('resize', pingFrame, { passive: true });
151+
window.addEventListener('pageshow', pingFrame, { passive: true });
152+
window.addEventListener('orientationchange', function() { setTimeout(pingFrame, 120); }, { passive: true });
153+
document.addEventListener('visibilitychange', function() {
154+
if (!document.hidden) pingFrame();
155+
}, { passive: true });
156+
if (window.visualViewport) {
157+
window.visualViewport.addEventListener('resize', pingFrame, { passive: true });
158+
window.visualViewport.addEventListener('scroll', pingFrame, { passive: true });
159+
}
160+
let dprQuery;
161+
function unwatchDpr() {
162+
if (!dprQuery) return;
163+
if (typeof dprQuery.removeEventListener === 'function') dprQuery.removeEventListener('change', watchDpr);
164+
else if (typeof dprQuery.removeListener === 'function') dprQuery.removeListener(watchDpr);
165+
}
166+
function watchDpr() {
167+
unwatchDpr();
168+
dprQuery = matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
169+
if (typeof dprQuery.addEventListener === 'function') dprQuery.addEventListener('change', watchDpr, { once: true });
170+
else if (typeof dprQuery.addListener === 'function') dprQuery.addListener(watchDpr);
171+
pingFrame();
172+
}
173+
watchDpr();
126174
const contributorMenu = document.querySelector('.menu-group');
127175
if (!contributorMenu) return;
128176
contributorMenu.querySelectorAll('a').forEach(link => {

gallery/logistic.html

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,21 @@
55
<script>if(window.self===window.top)document.documentElement.classList.add('standalone')</script>
66
<style>html.standalone .back-btn,html.standalone #back,html.standalone #info,html.standalone #ui,html.standalone #mode-btn,html.standalone .panel,html.standalone .controls,html.standalone #hint,html.standalone #hud{display:revert!important}</style>
77
<meta charset="UTF-8">
8-
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
8+
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover, interactive-widget=resizes-content">
99
<title>Logistic Map</title>
1010
<style>
1111
* { margin: 0; padding: 0; box-sizing: border-box; }
12-
html, body { width: 100%; height: 100%; }
12+
html, body { width: 100%; min-height: 100svh; min-height: -webkit-fill-available; height: 100%; height: 100dvh; }
1313
body {
1414
background: radial-gradient(circle at top, #131a2a 0%, #080b13 46%, #040509 100%);
1515
overflow: hidden;
1616
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
1717
color: #dfe7ff;
18-
height:100dvh}
18+
overscroll-behavior: none;
19+
-webkit-text-size-adjust: 100%;
20+
touch-action: none;
21+
padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
22+
}
1923
canvas { display: block; width: 100%; height: 100%; touch-action: none; }
2024
#back {
2125
position: fixed;
@@ -107,6 +111,7 @@
107111
#reseed:hover {
108112
background: rgba(223,231,255,0.12);
109113
}
114+
#ui, #ui * , #back { touch-action: manipulation; }
110115
@media (max-width: 620px) {
111116
#hint {
112117
top: auto;
@@ -213,14 +218,17 @@
213218

214219
function resize() {
215220
const dpr = Math.min(window.devicePixelRatio || 1, 2);
216-
canvas.width = Math.floor(window.innerWidth * dpr);
217-
canvas.height = Math.floor(window.innerHeight * dpr);
218-
canvas.style.width = window.innerWidth + 'px';
219-
canvas.style.height = window.innerHeight + 'px';
221+
const viewport = window.visualViewport;
222+
const width = Math.round(viewport?.width || window.innerWidth || document.documentElement.clientWidth || 0);
223+
const height = Math.round(viewport?.height || window.innerHeight || document.documentElement.clientHeight || 0);
224+
canvas.width = Math.max(1, Math.floor(width * dpr));
225+
canvas.height = Math.max(1, Math.floor(height * dpr));
226+
canvas.style.width = width + 'px';
227+
canvas.style.height = height + 'px';
220228
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
221229

222-
W = window.innerWidth;
223-
H = window.innerHeight;
230+
W = Math.max(width, 1);
231+
H = Math.max(height, 1);
224232

225233
const marginX = Math.min(56, W * 0.08);
226234
const topPad = inIframe ? 18 : Math.min(86, H * 0.14);
@@ -503,9 +511,40 @@
503511
resetOrbit(true);
504512
});
505513

506-
window.addEventListener('resize', resize);
507-
if (window.visualViewport) window.visualViewport.addEventListener('resize', resize);
508-
window.addEventListener('orientationchange', () => { setTimeout(resize, 200); });
514+
let resizeQueued = false;
515+
function scheduleResize() {
516+
if (resizeQueued) return;
517+
resizeQueued = true;
518+
requestAnimationFrame(() => {
519+
resizeQueued = false;
520+
resize();
521+
});
522+
}
523+
524+
window.addEventListener('resize', scheduleResize, { passive: true });
525+
window.addEventListener('pageshow', scheduleResize, { passive: true });
526+
document.addEventListener('visibilitychange', () => {
527+
if (!document.hidden) scheduleResize();
528+
}, { passive: true });
529+
if (window.visualViewport) {
530+
window.visualViewport.addEventListener('resize', scheduleResize, { passive: true });
531+
window.visualViewport.addEventListener('scroll', scheduleResize, { passive: true });
532+
}
533+
let dprQuery;
534+
function unwatchDpr() {
535+
if (!dprQuery) return;
536+
if (typeof dprQuery.removeEventListener === 'function') dprQuery.removeEventListener('change', watchDpr);
537+
else if (typeof dprQuery.removeListener === 'function') dprQuery.removeListener(watchDpr);
538+
}
539+
function watchDpr() {
540+
unwatchDpr();
541+
dprQuery = matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
542+
if (typeof dprQuery.addEventListener === 'function') dprQuery.addEventListener('change', watchDpr, { once: true });
543+
else if (typeof dprQuery.addListener === 'function') dprQuery.addListener(watchDpr);
544+
scheduleResize();
545+
}
546+
watchDpr();
547+
window.addEventListener('orientationchange', () => { setTimeout(scheduleResize, 200); }, { passive: true });
509548

510549
requestAnimationFrame(() => {
511550
resize();

0 commit comments

Comments
 (0)