Skip to content

fix(location): enable pinch-to-zoom on venue floor plans - #263

Merged
francescarpi merged 2 commits into
mainfrom
fix/mapzoom
Nov 6, 2026
Merged

francescarpi merged 2 commits into
mainfrom
fix/mapzoom

Conversation

@francescarpi

Copy link
Copy Markdown
Collaborator

Problema

Los planos de la sede añadidos en #261 funcionaban con el ratón, pero en
móvil no hacían nada: al tocar la imagen con el dedo se ampliaba la
página entera (el zoom nativo del navegador) y las herramientas de zoom
no respondían.

El componente nunca tuvo soporte multitáctil. El script solo escuchaba
wheel y dblclick, ambos de ratón, mientras que el CSS ponía
touch-action: none sobre el viewport: se desactivaba el
comportamiento nativo del navegador sin sustituirlo. Además
pointerdown salía con if (zoom <= MIN_ZOOM) return, de modo que el
arrastre con un dedo siempre se descartaba porque el plano empieza al
100%.

Cambio

Reescrita la capa de gestos de src/components/FloorPlanLightbox.astro:

  • Pellizco con dos dedos: zoom continuo entre 1x y 4x, anclado en
    el punto medio entre los dedos.
  • Arrastre con un dedo: mueve el plano, con límites para no
    revelar zonas vacías.
  • Doble toque: alterna entre 100% y 200%, centrado en el punto
    tocado.
  • Los eventos se escuchan en window en lugar de usar
    setPointerCapture, que se comporta mal en iOS Safari en cuanto hay
    más de un dedo.
  • preventDefault() sobre los eventos táctiles multi-dedo para que el
    navegador no haga su propio zoom de página.

Se actualiza también el texto location.floorplans.hint en español,
inglés y catalán, que hasta ahora solo mencionaba la rueda del ratón.

Notas

  • El dblclick que Chrome sintetiza tras un doble toque se ignora
    cuando el evento viene de un toque: deshacía el zoom al 200% al
    instante.
  • La transformación es translate(-50%,-50%) translate(offset) scale(zoom),
    así que el offset va en píxeles de pantalla y no se escala con el zoom.
    El anclaje se calcula sobre esa base (deriva medida: 0.00px).
  • El desplazamiento se limita en los ejes donde el plano ya es mayor que
    el viewport, para que nunca quede un hueco negro en pantalla. En los
    ejes donde el plano es más pequeño se mueve libre, que es lo que
    permite conservar el ancla durante el pellizco.
  • Sin dependencias nuevas.

package.json: 1.17.28 → 1.17.29.

Verificación

  • pnpm build correcto y astro check sin errores ni avisos.
  • Probado con Chrome headless y multitáctil real por CDP sobre un
    viewport de móvil (390×844): pellizco, arrastre, doble toque, rueda,
    botones y ratón.

## Problema

Los planos de la sede añadidos en #261 funcionaban con el ratón, pero en
móvil no hacían nada: al tocar la imagen con el dedo se ampliaba la
página entera (el zoom nativo del navegador) y las herramientas de zoom
no respondían.

El componente nunca tuvo soporte multitáctil. El script solo escuchaba
`wheel` y `dblclick`, ambos de ratón, mientras que el CSS ponía
`touch-action: none` sobre el viewport: se desactivaba el
comportamiento nativo del navegador sin sustituirlo. Además
`pointerdown` salía con `if (zoom <= MIN_ZOOM) return`, de modo que el
arrastre con un dedo siempre se descartaba porque el plano empieza al
100%.

## Cambio

Reescrita la capa de gestos de `src/components/FloorPlanLightbox.astro`:

- **Pellizco con dos dedos**: zoom continuo entre 1x y 4x, anclado en
  el punto medio entre los dedos.
- **Arrastre con un dedo**: mueve el plano, con límites para no
  revelar zonas vacías.
- **Doble toque**: alterna entre 100% y 200%, centrado en el punto
  tocado.
- Los eventos se escuchan en `window` en lugar de usar
  `setPointerCapture`, que se comporta mal en iOS Safari en cuanto hay
  más de un dedo.
- `preventDefault()` sobre los eventos táctiles multi-dedo para que el
  navegador no haga su propio zoom de página.

Se actualiza también el texto `location.floorplans.hint` en español,
inglés y catalán, que hasta ahora solo mencionaba la rueda del ratón.

## Notas

- El `dblclick` que Chrome sintetiza tras un doble toque se ignora
  cuando el evento viene de un toque: deshacía el zoom al 200% al
  instante.
- La transformación es `translate(-50%,-50%) translate(offset) scale(zoom)`,
  así que el offset va en píxeles de pantalla y no se escala con el zoom.
  El anclaje se calcula sobre esa base (deriva medida: 0.00px).
- El desplazamiento se limita en los ejes donde el plano ya es mayor que
  el viewport, para que nunca quede un hueco negro en pantalla. En los
  ejes donde el plano es más pequeño se mueve libre, que es lo que
  permite conservar el ancla durante el pellizco.
- Sin dependencias nuevas.

`package.json`: `1.17.28` → `1.17.29`.
@francescarpi
francescarpi merged commit 58c4ada into main Nov 6, 2026
1 check passed
@francescarpi
francescarpi deleted the fix/mapzoom branch November 6, 2026 06:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant