Skip to content

Commit 24e3ad8

Browse files
committed
fix mobile
1 parent bd91259 commit 24e3ad8

File tree

3 files changed

+103
-61
lines changed

3 files changed

+103
-61
lines changed

app.js

Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -158,18 +158,87 @@ removeBtn.addEventListener('click', () => {
158158
}
159159
});
160160

161-
// --- Mobile UI Toggles ---
161+
// --- Mobile UI Drawer Logic ---
162162
const controlPanel = document.getElementById('control-panel');
163-
const panelToggle = document.getElementById('panel-toggle');
164-
const closePanel = document.getElementById('close-panel');
163+
const dragHandle = document.querySelector('.drag-handle');
165164

166-
panelToggle.addEventListener('click', () => {
167-
controlPanel.classList.add('open');
168-
});
165+
let startY = 0;
166+
let currentY = 0;
167+
let isDragging = false;
168+
let panelHeight = 0;
169169

170-
closePanel.addEventListener('click', () => {
171-
controlPanel.classList.remove('open');
172-
});
170+
function setPanelTranslate(y) {
171+
controlPanel.style.transform = `translateY(${y}px)`;
172+
}
173+
174+
function updatePanelState(isOpen) {
175+
controlPanel.classList.toggle('open', isOpen);
176+
controlPanel.style.transform = ''; // Clear inline styles to let CSS take over
177+
}
178+
179+
// Gesture Handling
180+
function onTouchStart(e) {
181+
if (window.innerWidth > 768) return;
182+
183+
// Only allow dragging from handle or header area to avoid conflict with content scroll
184+
const touchY = e.touches[0].clientY;
185+
const panelRect = controlPanel.getBoundingClientRect();
186+
187+
// Check if touch is in the top portion of the panel
188+
if (touchY - panelRect.top > 80) return;
189+
190+
startY = touchY;
191+
panelHeight = panelRect.height;
192+
isDragging = true;
193+
controlPanel.style.transition = 'none'; // Instant feedback
194+
}
195+
196+
function onTouchMove(e) {
197+
if (!isDragging) return;
198+
199+
const touchY = e.touches[0].clientY;
200+
const deltaY = touchY - startY;
201+
202+
// Calculate new position
203+
// If open (translateY = 0), deltaY > 0 moves down (closing)
204+
// If closed (translateY = height - 60), deltaY < 0 moves up (opening)
205+
const isCurrentlyOpen = controlPanel.classList.contains('open');
206+
const baseTranslate = isCurrentlyOpen ? 0 : (panelHeight - 60);
207+
let newTranslate = baseTranslate + deltaY;
208+
209+
// Bounds: don't push too high or too low
210+
newTranslate = Math.max(0, Math.min(newTranslate, panelHeight - 60));
211+
212+
setPanelTranslate(newTranslate);
213+
currentY = newTranslate;
214+
215+
// Prevent background scrolling
216+
if (e.cancelable) e.preventDefault();
217+
}
218+
219+
function onTouchEnd() {
220+
if (!isDragging) return;
221+
isDragging = false;
222+
controlPanel.style.transition = ''; // Restore smooth CSS transition
223+
224+
const isCurrentlyOpen = controlPanel.classList.contains('open');
225+
const threshold = panelHeight * 0.3; // 30% of height needed to toggle
226+
227+
if (isCurrentlyOpen) {
228+
// Closing: if moved more than 30% down, close it
229+
updatePanelState(currentY < threshold);
230+
} else {
231+
// Opening: if moved more than 30% up from closed state
232+
const closedPos = panelHeight - 60;
233+
updatePanelState(currentY < closedPos - threshold);
234+
}
235+
}
236+
237+
// Attach listeners to the panel itself for broad hit area,
238+
// filtered by onTouchStart's position check
239+
controlPanel.addEventListener('touchstart', onTouchStart, { passive: false });
240+
window.addEventListener('touchmove', onTouchMove, { passive: false });
241+
window.addEventListener('touchend', onTouchEnd);
173242

174243
// --- Drag and Drop ---
175244

index.html

Lines changed: 24 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -36,43 +36,30 @@
3636
z-index: 1000;
3737
width: 320px;
3838
backdrop-filter: blur(12px);
39-
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s;
39+
transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
4040
border: 1px solid rgba(255, 255, 255, 0.3);
41+
user-select: none;
42+
touch-action: none;
43+
/* Disable native scroll on the panel while dragging */
4144
}
4245

43-
/* Mobile Toggle Button */
44-
#panel-toggle {
45-
position: absolute;
46-
top: 20px;
47-
left: 20px;
48-
z-index: 999;
49-
background: #0078ff;
50-
color: white;
51-
border: none;
52-
border-radius: 50%;
53-
width: 48px;
54-
height: 48px;
46+
/* Drag Handle for Mobile */
47+
.drag-handle {
48+
width: 40px;
49+
height: 4px;
50+
background: #ccc;
51+
border-radius: 2px;
52+
margin: 0 auto 16px;
5553
display: none;
56-
align-items: center;
57-
justify-content: center;
58-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
59-
cursor: pointer;
54+
cursor: grab;
55+
flex-shrink: 0;
6056
}
6157

62-
/* Close Button for Mobile */
63-
#close-panel {
64-
position: absolute;
65-
top: 15px;
66-
right: 15px;
67-
display: none;
68-
background: none;
69-
border: none;
70-
color: #999;
71-
cursor: pointer;
72-
padding: 5px;
73-
width: auto;
58+
.drag-handle:active {
59+
cursor: grabbing;
7460
}
7561

62+
7663
h2 {
7764
margin-top: 0;
7865
font-size: 20px;
@@ -238,8 +225,8 @@
238225

239226
/* Mobile Specific Overrides */
240227
@media (max-width: 768px) {
241-
#panel-toggle {
242-
display: flex;
228+
.drag-handle {
229+
display: block;
243230
}
244231

245232
#control-panel {
@@ -248,19 +235,16 @@
248235
left: 0;
249236
width: 100%;
250237
border-radius: 24px 24px 0 0;
251-
transform: translateY(100%);
238+
transform: translateY(calc(100% - 60px));
239+
/* Peak of handle/header */
252240
box-sizing: border-box;
253-
padding-bottom: 40px;
254-
/* Space for home indicator */
241+
padding: 12px 24px 40px;
255242
}
256243

257244
#control-panel.open {
258-
transform: translateY(0);
245+
transform: translateY(0) !important;
259246
}
260247

261-
#close-panel {
262-
display: block;
263-
}
264248

265249
h2 {
266250
padding-right: 30px;
@@ -276,20 +260,9 @@
276260
<body>
277261
<div id="map"></div>
278262

279-
<button id="panel-toggle" title="Open Settings">
280-
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor">
281-
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" />
282-
</svg>
283-
</button>
284-
285263
<div id="control-panel" class="open">
286-
<button id="close-panel" title="Close Panel">
287-
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor">
288-
<path
289-
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" />
290-
</svg>
291-
</button>
292-
<h2>Scatterplot Controls</h2>
264+
<div class="drag-handle"></div>
265+
<h2>WebGPU Scatterplot Demo (deck.gl)</h2>
293266
<div class="input-group">
294267
<label for="point-count">Generate Points</label>
295268
<input type="text" id="point-count" placeholder="1,000,000" value="1,000,000" inputmode="numeric">

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"license": "MIT",
66
"type": "module",
77
"scripts": {
8-
"start": "vite --open",
8+
"start": "vite --open --host",
99
"start-local": "vite --config ../../vite.config.local.mjs",
1010
"build": "vite build"
1111
},

0 commit comments

Comments
 (0)