Skip to content

Commit

Permalink
improve declare module 'three' placements
Browse files Browse the repository at this point in the history
  • Loading branch information
bbohlender committed Nov 3, 2024
1 parent 4ddbccb commit f7ae334
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 98 deletions.
47 changes: 46 additions & 1 deletion packages/pointer-events/src/event.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { BaseEvent, Face, Object3D, Quaternion, Ray, Vector2, Vector3 } from 'three'
import { Intersection as ThreeIntersection } from './intersections/index.js'
import { Pointer } from './pointer.js'
import { getObjectListeners } from './utils.js'
import type { Camera, IntersectionEvent, Intersection } from '@react-three/fiber/dist/declarations/src/core/events.js'
import { HtmlEvent, Properties } from './html-event.js'

Expand Down Expand Up @@ -268,3 +267,49 @@ function emitPointerEventRec(baseEvent: PointerEvent<NativeEvent>, currentObject
}
emitPointerEventRec(baseEvent, currentObject.parent)
}

const r3fEventToHandlerMap: Record<keyof PointerEventsMap, string> = {
click: 'onClick',
contextmenu: 'onContextMenu',
dblclick: 'onDoubleClick',
pointercancel: 'onPointerCancel',
pointerdown: 'onPointerDown',
pointerenter: 'onPointerEnter',
pointerleave: 'onPointerLeave',
pointermove: 'onPointerMove',
pointerout: 'onPointerOut',
pointerover: 'onPointerOver',
pointerup: 'onPointerUp',
wheel: 'onWheel',
}

export const listenerNames = Object.keys(r3fEventToHandlerMap)

declare module 'three' {
interface Object3D {
_listeners?: Record<string, Array<(event: unknown) => void> | undefined>
}
}

function getObjectListeners<E>(
object: Object3D,
forEvent: keyof PointerEventsMap,
): Array<(event: E) => void> | undefined {
if (object._listeners != null && forEvent in object._listeners) {
return object._listeners[forEvent]
}

//R3F compatibility
let handler: ((e: any) => void) | undefined
if (object.isVoidObject && forEvent === 'click' && object.parent?.__r3f != null) {
handler = object.parent.__r3f.root.getState().onPointerMissed
}
if (object.__r3f != null) {
handler = object.__r3f.handlers[r3fEventToHandlerMap[forEvent]]
}

if (handler == null) {
return undefined
}
return [handler]
}
38 changes: 38 additions & 0 deletions packages/pointer-events/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,41 @@
import type { Root } from '@react-three/fiber/dist/declarations/src/core/renderer.js'
import type { AllowedPointerEvents, AllowedPointerEventsType } from './pointer.js'

declare module 'three' {
interface Object3D {
__r3f?: {
eventCount: number
handlers: Record<string, ((e: any) => void) | undefined>
root: Root['store']
}
/**
* undefined and true means the transformation is ready
* false means transformation is not ready
*/
transformReady?: boolean

/**
* @default parent.pointerEvents ?? this.defaultPointerEvents
*/
pointerEvents?: AllowedPointerEvents
/**
* @default "listener"
*/
defaultPointerEvents?: AllowedPointerEvents
/**
* @default "all"
*/
pointerEventsType?: AllowedPointerEventsType
/**
* @default 0
* sorted by highest number first
* (just like a higher renderOrder number will result in rendering over the previous - if depthTest is false)
*/
pointerEventsOrder?: number
isVoidObject?: boolean
}
}

export * from './pointer.js'
export * from './event.js'
export * from './intersections/index.js'
Expand Down
23 changes: 22 additions & 1 deletion packages/pointer-events/src/intersections/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Plane, Intersection as ThreeIntersection, Object3D, Vector3, Ray, Quaternion } from 'three'
import { Intersection, IntersectionOptions } from './index.js'
import { AllowedPointerEventsType, Pointer, type AllowedPointerEvents } from '../pointer.js'
import { hasObjectListeners } from '../utils.js'
import { getVoidObject, VoidObjectCollider } from './intersector.js'
import { listenerNames } from '../event.js'

export function computeIntersectionWorldPlane(target: Plane, intersection: Intersection, object: Object3D): boolean {
const normal = intersection.normal ?? intersection.face?.normal
Expand Down Expand Up @@ -103,6 +103,27 @@ export function intersectPointerEventTargets(
}
}

function hasObjectListeners({ _listeners, __r3f }: Object3D): boolean {
if (__r3f != null && __r3f?.eventCount > 0) {
return true
}
if (_listeners == null) {
return false
}
const entries = Object.entries(_listeners)
const length = entries.length
for (let i = 0; i < length; i++) {
const entry = entries[i]
if (!listenerNames.includes(entry[0])) {
continue
}
if (entry[1] != null && entry[1].length > 0) {
return true
}
}
return false
}

function filterAndInteresct(
{ intersector, options }: Pointer,
object: Object3D,
Expand Down
20 changes: 0 additions & 20 deletions packages/pointer-events/src/pointer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,8 @@ export type AllowedPointerEventsType =

declare module 'three' {
interface Object3D {
_listeners?: Record<string, Array<(event: unknown) => void> | undefined>
/**
* @default parent.pointerEvents ?? this.defaultPointerEvents
*/
pointerEvents?: AllowedPointerEvents
/**
* @default "listener"
*/
defaultPointerEvents?: AllowedPointerEvents
/**
* @default "all"
*/
pointerEventsType?: AllowedPointerEventsType
/**
* @default 0
* sorted by highest number first
* (just like a higher renderOrder number will result in rendering over the previous - if depthTest is false)
*/
pointerEventsOrder?: number
[buttonsDownTimeKey]?: ButtonsTime
[buttonsClickTimeKey]?: ButtonsTime
isVoidObject?: boolean
}
}

Expand Down
76 changes: 0 additions & 76 deletions packages/pointer-events/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,5 @@
import { BufferAttribute, Matrix4, Mesh, Object3D, Triangle, Vector2, Vector3 } from 'three'
import { PointerEventsMap } from './event.js'
import type { Root } from '@react-three/fiber/dist/declarations/src/core/renderer.js'

declare module 'three' {
interface Object3D {
__r3f?: {
eventCount: number
handlers: Record<string, ((e: any) => void) | undefined>
root: Root['store']
}
/**
* undefined and true means the transformation is ready
* false means transformation is not ready
*/
transformReady?: boolean
}
}

export function updateAndCheckWorldTransformation({ transformReady, parent, matrix, matrixWorld }: Object3D): boolean {
if (transformReady === false) {
Expand All @@ -31,66 +15,6 @@ export function updateAndCheckWorldTransformation({ transformReady, parent, matr
return true
}

export function hasObjectListeners({ _listeners, __r3f }: Object3D): boolean {
if (__r3f != null && __r3f?.eventCount > 0) {
return true
}
if (_listeners == null) {
return false
}
const entries = Object.entries(_listeners)
const length = entries.length
for (let i = 0; i < length; i++) {
const entry = entries[i]
if (!listenerNames.includes(entry[0])) {
continue
}
if (entry[1] != null && entry[1].length > 0) {
return true
}
}
return false
}

export function getObjectListeners<E>(
object: Object3D,
forEvent: keyof PointerEventsMap,
): Array<(event: E) => void> | undefined {
if (object._listeners != null && forEvent in object._listeners) {
return object._listeners[forEvent]
}

//R3F compatibility
let handler: ((e: any) => void) | undefined
if (object.isVoidObject && forEvent === 'click' && object.parent?.__r3f != null) {
handler = object.parent.__r3f.root.getState().onPointerMissed
}
if (object.__r3f != null) {
handler = object.__r3f.handlers[r3fEventToHandlerMap[forEvent]]
}

if (handler == null) {
return undefined
}
return [handler]
}

const r3fEventToHandlerMap: Record<keyof PointerEventsMap, string> = {
click: 'onClick',
contextmenu: 'onContextMenu',
dblclick: 'onDoubleClick',
pointercancel: 'onPointerCancel',
pointerdown: 'onPointerDown',
pointerenter: 'onPointerEnter',
pointerleave: 'onPointerLeave',
pointermove: 'onPointerMove',
pointerout: 'onPointerOut',
pointerover: 'onPointerOver',
pointerup: 'onPointerUp',
wheel: 'onWheel',
}
const listenerNames = Object.keys(r3fEventToHandlerMap)

const triangleHelper1 = new Triangle()
const triangleHelper2 = new Triangle()
const aVec2Helper = new Vector2()
Expand Down

0 comments on commit f7ae334

Please sign in to comment.