/
events.ts
63 lines (59 loc) 路 2.48 KB
/
events.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import { UseBoundStore } from 'zustand'
import { RootState } from '../core/store'
import { EventManager, Events, createEvents, DomEvent } from '../core/events'
const DOM_EVENTS = {
onClick: ['click', false],
onContextMenu: ['contextmenu', false],
onDoubleClick: ['dblclick', false],
onWheel: ['wheel', true],
onPointerDown: ['pointerdown', true],
onPointerUp: ['pointerup', true],
onPointerLeave: ['pointerleave', true],
onPointerMove: ['pointermove', true],
onPointerCancel: ['pointercancel', true],
onLostPointerCapture: ['lostpointercapture', true],
} as const
/** Default R3F event manager for web */
export function createPointerEvents(store: UseBoundStore<RootState>): EventManager<HTMLElement> {
const { handlePointer } = createEvents(store)
return {
priority: 1,
enabled: true,
compute(event: DomEvent, state: RootState, previous?: RootState) {
// https://github.com/pmndrs/react-three-fiber/pull/782
// Events trigger outside of canvas when moved, use offsetX/Y by default and allow overrides
state.pointer.set((event.offsetX / state.size.width) * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1)
state.raycaster.setFromCamera(state.pointer, state.camera)
},
connected: undefined,
handlers: Object.keys(DOM_EVENTS).reduce(
(acc, key) => ({ ...acc, [key]: handlePointer(key) }),
{},
) as unknown as Events,
update: () => {
const { events, internal } = store.getState()
if (internal.lastEvent?.current && events.handlers) events.handlers.onPointerMove(internal.lastEvent.current)
},
connect: (target: HTMLElement) => {
const { set, events } = store.getState()
events.disconnect?.()
set((state) => ({ events: { ...state.events, connected: target } }))
Object.entries(events.handlers ?? []).forEach(([name, event]) => {
const [eventName, passive] = DOM_EVENTS[name as keyof typeof DOM_EVENTS]
target.addEventListener(eventName, event, { passive })
})
},
disconnect: () => {
const { set, events } = store.getState()
if (events.connected) {
Object.entries(events.handlers ?? []).forEach(([name, event]) => {
if (events && events.connected instanceof HTMLElement) {
const [eventName] = DOM_EVENTS[name as keyof typeof DOM_EVENTS]
events.connected.removeEventListener(eventName, event)
}
})
set((state) => ({ events: { ...state.events, connected: undefined } }))
}
},
}
}