// Pointer events carry the pointer position in three coordinate frames, // resolved per node as the event bubbles: // - clientX/clientY - the window frame. // - localX/localY - the frame of the node whose handler is running, its whole // transform chain undone. Exact even when the pointer is not over the node: // after a pointer down, moves route along the frozen down path and keep // reporting true locals (a fast drag cannot escape the chip below). // - parentX/parentY - the frame of the node's path parent, which is the frame // the node's own x/y props live in. // The drag idiom needs no transform math in the app: take the grab offset from // localX/localY at pointer down, place with parentX/parentY - offset during // moves. The surface here is rotated and scaled to prove the point - the chip // still tracks the pointer exactly. Keying the grab by pointerId keeps // concurrent touches (each routed along its own down path) independent. import { render, createSignal } from "@solidrt/core" function App() { let [pos, setPos] = createSignal({ x: 40, y: 40 }) let grab: { pointer: number; dx: number; dy: number } | null = null return ( { if (grab) return grab = { pointer: e.pointerId, dx: e.localX, dy: e.localY } }} onPointerMove={(e) => { if (!grab || e.pointerId !== grab.pointer) return setPos({ x: e.parentX - grab.dx, y: e.parentY - grab.dy }) }} onPointerUp={() => { grab = null }} > drag me ) } render(() => )