Changeset 3866994 in Klonkt for src/assets
- Timestamp:
- 08/12/2026 10:00:38 PM (3 months ago)
- Parents:
- 5b6f93b
- File:
-
- 1 edited
-
src/assets/js/ward-sky.js (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/assets/js/ward-sky.js
r5b6f93b r3866994 254 254 } 255 255 256 /** De schaal binnen zijn grenzen. Eén plek, zodat wiel en pinch gelijk zijn. */ 257 _clampScale(s) { return Math.min(Math.max(s, 0.2), 2.5); } 258 259 /** 260 * Zoomen ROND een schermpunt, niet rond het canvas-midden: de wereld onder 261 * je vingers (of je muis) blijft staan, zodat de hemel zich als een kaart 262 * gedraagt in plaats van onder je weg te schuiven. 263 */ 264 _zoomAround(px, py, factor) { 265 const next = this._clampScale(this.scale * factor); 266 const cx = this.w / 2, cy = this.h / 2; 267 // Het wereldpunt onder (px,py) mag na de zoom op dezelfde plek blijven. 268 const worldX = (px - cx - this.panX) / this.scale; 269 const worldY = (py - cy - this.panY) / this.scale; 270 this.panX = px - cx - worldX * next; 271 this.panY = py - cy - worldY * next; 272 this.scale = next; 273 } 274 256 275 _wire() { 257 276 const c = this.canvas; 258 let dragging = false, lastX = 0, lastY = 0, moved = 0; 259 let pinch = null; 277 // Alle vingers die nu op de hemel liggen. Eén = pannen of tikken, twee = 278 // knijpen. Een Map want pointers komen en gaan in willekeurige volgorde. 279 const pts = new Map(); 280 let moved = 0; // hoeveel de ENE vinger bewoog (tik vs sleep) 281 let pinchDist = 0; // vingerafstand bij het begin van een knijp 282 let becamePinch = false; // ooit twee vingers? dan geen tik aan het eind 283 284 const local = (e) => { 285 const r = c.getBoundingClientRect(); 286 return { x: e.clientX - r.left, y: e.clientY - r.top }; 287 }; 288 const twoPointerState = () => { 289 const [a, b] = [...pts.values()]; 290 return { 291 dist: Math.hypot(a.x - b.x, a.y - b.y), 292 mx: (a.x + b.x) / 2, my: (a.y + b.y) / 2, 293 }; 294 }; 260 295 261 296 c.addEventListener('pointerdown', (e) => { 262 297 if (!this.interactive) return; 263 dragging = true; moved = 0;264 lastX = e.clientX; lastY = e.clientY;265 298 c.setPointerCapture(e.pointerId); 299 pts.set(e.pointerId, local(e)); 300 moved = 0; 301 if (pts.size === 2) { becamePinch = true; pinchDist = twoPointerState().dist; } 266 302 }); 303 267 304 c.addEventListener('pointermove', (e) => { 268 if (!this.interactive || !dragging) return; 269 const dx = e.clientX - lastX, dy = e.clientY - lastY; 270 moved += Math.abs(dx) + Math.abs(dy); 271 this.panX += dx; this.panY += dy; 272 lastX = e.clientX; lastY = e.clientY; 305 if (!this.interactive || !pts.has(e.pointerId)) return; 306 const prev = pts.get(e.pointerId); 307 const cur = local(e); 308 pts.set(e.pointerId, cur); 309 310 if (pts.size >= 2) { 311 // Knijpen: schaal volgt de verhouding van de vingerafstand, en we 312 // zoomen om het midden tussen de vingers. 313 const { dist, mx, my } = twoPointerState(); 314 if (pinchDist > 0 && dist > 0) { 315 this._zoomAround(mx, my, dist / pinchDist); 316 pinchDist = dist; 317 } 318 } else { 319 // Eén vinger: pannen. 320 const dx = cur.x - prev.x, dy = cur.y - prev.y; 321 moved += Math.abs(dx) + Math.abs(dy); 322 this.panX += dx; this.panY += dy; 323 } 273 324 }); 274 const end = (e) => { 275 if (!this.interactive || !dragging) return; 276 dragging = false; 277 // Nauwelijks bewogen? Dan was het een tik en geen sleep. 278 if (moved < 6) { 279 const r = c.getBoundingClientRect(); 280 const x = e.clientX - r.left; 281 const y = e.clientY - r.top; 325 326 const lift = (e) => { 327 if (!pts.has(e.pointerId)) return; 328 const cur = pts.get(e.pointerId); 329 pts.delete(e.pointerId); 330 // Nog één vinger over na een knijp: zijn afstand als nieuw ijkpunt, en 331 // niet meteen als tik tellen. 332 if (pts.size === 1) { pinchDist = 0; return; } 333 if (pts.size > 1) return; 334 335 // Laatste vinger los. Een tik alleen als er nooit geknepen is en de 336 // vinger nauwelijks bewoog. 337 if (!becamePinch && moved < 6) { 338 const { x, y } = cur; 282 339 const hit = nearestFace(x, y, this.spots, { 283 340 cx: this.w / 2, cy: this.h / 2, cell: CELL, scale: this.scale, 284 341 panX: this.panX, panY: this.panY, 285 342 }); 286 if (hit != null) { this.onPick?.(hit); return; } 287 // Geen gezicht? Dan misschien de (+): zelfde middelpunt als getekend, 288 // met een raakzone die meeschaalt zodat mikken bij elke zoom klopt. 289 const s2 = Math.min(Math.max(this.scale, 0.5), 1.6); 290 const d = Math.hypot(x - (this.w / 2 + this.panX), y - (this.h / 2 + this.panY)); 291 if (d <= 26 * s2) this.onNew?.(); 343 if (hit != null) { this.onPick?.(hit); } 344 else { 345 // Geen gezicht? Dan misschien de (+): zelfde middelpunt als getekend, 346 // met een raakzone die meeschaalt zodat mikken bij elke zoom klopt. 347 const s2 = Math.min(Math.max(this.scale, 0.5), 1.6); 348 const d = Math.hypot(x - (this.w / 2 + this.panX), y - (this.h / 2 + this.panY)); 349 if (d <= 26 * s2) this.onNew?.(); 350 } 292 351 } 293 };294 c.addEventListener('pointerup', end);295 c.addEventListener('pointer cancel', () => { dragging = false; });296 297 // Knijpen op een telefoon, wiel op een desktop; allebei zoomen om het 298 // midden, zodat de hemel zich als een kaart gedraagt.352 becamePinch = false; 353 }; 354 c.addEventListener('pointerup', lift); 355 c.addEventListener('pointercancel', (e) => { pts.delete(e.pointerId); if (pts.size < 2) pinchDist = 0; }); 356 357 // Het wiel op een desktop: zoomen om de muis, dezelfde weg als de pinch. 299 358 c.addEventListener('wheel', (e) => { 300 359 if (!this.interactive) return; 301 360 e.preventDefault(); 302 this.scale = Math.min(Math.max(this.scale * (e.deltaY < 0 ? 1.1 : 0.9), 0.2), 2.5); 361 const { x, y } = local(e); 362 this._zoomAround(x, y, e.deltaY < 0 ? 1.1 : 0.9); 303 363 }, { passive: false }); 304 364
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)