(canvas: HTMLCanvasElement, initialGridArea: GridArea)
| 38 | const DEFAULT_TAP_MAX_TIME_MS = 500; |
| 39 | |
| 40 | export function createEventManager(canvas: HTMLCanvasElement, initialGridArea: GridArea): EventManager { |
| 41 | let disposed = false; |
| 42 | let gridArea = initialGridArea; |
| 43 | |
| 44 | const listeners: ListenerRegistry = { |
| 45 | mousemove: new Set<ChartGPUEventCallback>(), |
| 46 | click: new Set<ChartGPUEventCallback>(), |
| 47 | mouseleave: new Set<ChartGPUEventCallback>(), |
| 48 | }; |
| 49 | |
| 50 | let tapCandidate: TapCandidate | null = null; |
| 51 | let suppressNextLostPointerCaptureId: number | null = null; |
| 52 | |
| 53 | const toPayload = (e: PointerEvent): ChartGPUEventPayload | null => { |
| 54 | const rect = canvas.getBoundingClientRect(); |
| 55 | if (rect.width === 0 || rect.height === 0) return null; |
| 56 | |
| 57 | const x = e.clientX - rect.left; |
| 58 | const y = e.clientY - rect.top; |
| 59 | |
| 60 | const plotLeftCss = gridArea.left; |
| 61 | const plotTopCss = gridArea.top; |
| 62 | const plotWidthCss = rect.width - gridArea.left - gridArea.right; |
| 63 | const plotHeightCss = rect.height - gridArea.top - gridArea.bottom; |
| 64 | |
| 65 | const gridX = x - plotLeftCss; |
| 66 | const gridY = y - plotTopCss; |
| 67 | |
| 68 | const isInGrid = |
| 69 | gridX >= 0 && |
| 70 | gridX <= plotWidthCss && |
| 71 | gridY >= 0 && |
| 72 | gridY <= plotHeightCss; |
| 73 | |
| 74 | return { x, y, gridX, gridY, plotWidthCss, plotHeightCss, isInGrid, originalEvent: e }; |
| 75 | }; |
| 76 | |
| 77 | const emit = (eventName: ChartGPUEventName, e: PointerEvent): void => { |
| 78 | const payload = toPayload(e); |
| 79 | if (!payload) return; |
| 80 | |
| 81 | for (const cb of listeners[eventName]) cb(payload); |
| 82 | }; |
| 83 | |
| 84 | const clearTapCandidateIfMatches = (e: PointerEvent): void => { |
| 85 | if (!tapCandidate) return; |
| 86 | if (!e.isPrimary) return; |
| 87 | if (e.pointerId !== tapCandidate.pointerId) return; |
| 88 | tapCandidate = null; |
| 89 | }; |
| 90 | |
| 91 | const onPointerMove = (e: PointerEvent): void => { |
| 92 | if (disposed) return; |
| 93 | emit('mousemove', e); |
| 94 | }; |
| 95 | |
| 96 | const onPointerLeave = (e: PointerEvent): void => { |
| 97 | if (disposed) return; |
no outgoing calls
no test coverage detected