Skip to main content

Shared touch navigation

Pinch zoom, rotation, pitch and actual activity

Shared scripts use MapLibre-style names, with await for cross-thread calls:

await map.touchZoomRotate.enable();
await map.touchZoomRotate.disableRotation(); // Preserve zoom
await map.touchPitch.enable();
const enabled = await map.touchZoomRotate.isEnabled();
const active = await map.touchZoomRotate.isActive();
const policy = await map.sqs.gesturesState();

Both handlers expose enable/disable/isEnabled/isActive. touchZoomRotate also has enableRotation/disableRotation. Extra options currently reject. setZoomRate/setZoomThreshold, around:center options, one-finger double-tap dragging and inertia remain unsupported; full MapLibre gesture compatibility is not claimed. Names follow the public API; SqsMap implements its own recognizer.

Policy has six defaults: dragPan/scrollZoom/doubleClickZoom/keyboard/touchZoomRotate/touchPitch, plus independent keyboardRotation/touchRotation. gesturePolicy/touchGesturePolicy report shared controls; touchNavigation reports host input navigation. Active means actual recognized input, not enablement or camera animation. Release/cancel/disable/destruction clear activity; re-enabling does not resume held old contacts.

Browser main and Worker hosts support one-finger pan, two-finger distance zoom, angle rotation and near-horizontal parallel vertical dragging for pitch. Inputs coalesce by frame with at most two contacts and no invented inertia. Pitch requires Mercator/globe; touch targets are0–65 degrees. Planar zoom/rotation use the contact midpoint; globe rotation uses the current center. Complex terrain anchor behavior remains limited. Single taps publish shared click events; multi-contact release does not fabricate a single click.

Android development source includes optional AndroidTouchInput and platform-independent TouchInput. Applications supply controls/layer UI:

AndroidTouchInput input = new AndroidTouchInput(host);
mapView.setOnTouchListener(input); // Application-owned View
// On destruction: input.close(), detach the View listener, then host.closeAsync()

The adapter maps the actual View/frame rectangle to logical coordinates at the configured density. Input snapshots are copied; at most32 MOVE calls queue, while final cancellation remains admitted. Cancel/close clears recognition. Rotation disable preserves zoom; disable/enable never revives held contacts. Custom UI can call touch(TouchInput) directly. Coordinates assume the View drawing rectangle covers the map framebuffer. Native C shells still own physical recognition and report activity through gesture_input_json; automatic shell touch support is not invented.

The complete HTML includes four controls, handlers, data and credits. The same script controls native/browser hosts. Android sources are listed in the native manifest.

Local checks cover seven policy tests, eight shared script checks, four actual main/strictWorker×DPR1/2 touch cases and red pixels; AndroidAPI24/ARM64 JNI compile and15 real Linux JVM owner/input/tap-callback checks. Browser cases use fresh task pages to isolate touch device state. Android devices, desktop touch hardware, mobile GIS/iOS and formal releases remain separately verified.