@pmndrs/pointer-events
Advanced tools
Comparing version 6.4.1 to 6.4.2
@@ -99,1 +99,7 @@ import { BaseEvent, Face, Object3D, Quaternion, Ray, Vector2, Vector3 } from 'three'; | ||
export declare function emitPointerEvent(event: PointerEvent<NativeEvent>): void; | ||
export declare const listenerNames: string[]; | ||
declare module 'three' { | ||
interface Object3D { | ||
_listeners?: Record<string, Array<(event: unknown) => void> | undefined>; | ||
} | ||
} |
import { Ray, Vector2, Vector3 } from 'three'; | ||
import { getObjectListeners } from './utils.js'; | ||
import { HtmlEvent } from './html-event.js'; | ||
@@ -185,1 +184,33 @@ const helperVector = new Vector3(); | ||
} | ||
const r3fEventToHandlerMap = { | ||
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); | ||
function getObjectListeners(object, forEvent) { | ||
if (object._listeners != null && forEvent in object._listeners) { | ||
return object._listeners[forEvent]; | ||
} | ||
//R3F compatibility | ||
let handler; | ||
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]; | ||
} |
@@ -1,2 +0,1 @@ | ||
import { Mesh } from 'three'; | ||
import { Pointer } from './pointer.js'; | ||
@@ -6,3 +5,2 @@ import { PointerEvent } from './event.js'; | ||
import { generateUniquePointerId } from './pointer/index.js'; | ||
import { getClosestUV } from './utils.js'; | ||
function htmlEventToCoords(element, e, target) { | ||
@@ -32,8 +30,6 @@ if (!(e instanceof globalThis.MouseEvent)) { | ||
} | ||
if (!(e.object instanceof Mesh)) { | ||
if (e.uv == null) { | ||
return target.set(0, 0); | ||
} | ||
getClosestUV(target, e.point, e.object); | ||
target.multiplyScalar(2).addScalar(-1); | ||
return target; | ||
return target.copy(e.uv).multiplyScalar(2).addScalar(-1); | ||
} | ||
@@ -40,0 +36,0 @@ export function forwardObjectEvents(fromPortal, getCamera, scene, options) { |
@@ -0,1 +1,36 @@ | ||
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'; | ||
@@ -7,2 +42,1 @@ export * from './event.js'; | ||
export * from './combine.js'; | ||
export { getClosestUV } from './utils.js'; |
@@ -7,2 +7,1 @@ export * from './pointer.js'; | ||
export * from './combine.js'; | ||
export { getClosestUV } from './utils.js'; |
@@ -1,4 +0,4 @@ | ||
import { Line3, Matrix4, Plane, Quaternion, Ray, Raycaster, Vector3, } from 'three'; | ||
import { Line3, Matrix4, Plane, Quaternion, Ray, Raycaster, Vector3, Mesh, Vector2, } from 'three'; | ||
import { computeIntersectionWorldPlane, getDominantIntersectionIndex, pushTimes, voidObjectIntersectionFromRay, } from './utils.js'; | ||
import { updateAndCheckWorldTransformation } from '../utils.js'; | ||
import { getClosestUV, updateAndCheckWorldTransformation } from '../utils.js'; | ||
const invertedMatrixHelper = new Matrix4(); | ||
@@ -8,2 +8,3 @@ const lineHelper = new Line3(); | ||
const rayHelper = new Ray(); | ||
const point2Helper = new Vector2(); | ||
const defaultLinePoints = [new Vector3(0, 0, 0), new Vector3(0, 0, 1)]; | ||
@@ -51,4 +52,9 @@ export class LinesIntersector { | ||
const pointOnFace = rayHelper.intersectPlane(planeHelper, new Vector3()) ?? point; | ||
let uv = intersection.uv; | ||
if (intersection.object instanceof Mesh && getClosestUV(point2Helper, point, intersection.object)) { | ||
uv = point2Helper.clone(); | ||
} | ||
return { | ||
...intersection, | ||
uv, | ||
pointOnFace, | ||
@@ -55,0 +61,0 @@ point, |
@@ -1,4 +0,4 @@ | ||
import { Matrix4, Plane, Quaternion, Raycaster, Vector3, Vector2, } from 'three'; | ||
import { Matrix4, Plane, Quaternion, Raycaster, Vector3, Vector2, Mesh, } from 'three'; | ||
import { computeIntersectionWorldPlane, getDominantIntersectionIndex, pushTimes, voidObjectIntersectionFromRay, } from './utils.js'; | ||
import { updateAndCheckWorldTransformation } from '../utils.js'; | ||
import { getClosestUV, updateAndCheckWorldTransformation } from '../utils.js'; | ||
const invertedMatrixHelper = new Matrix4(); | ||
@@ -9,2 +9,3 @@ const scaleHelper = new Vector3(); | ||
const planeHelper = new Plane(); | ||
const point2Helper = new Vector2(); | ||
export class RayIntersector { | ||
@@ -50,7 +51,13 @@ space; | ||
const pointOnFace = ray.intersectPlane(planeHelper, new Vector3()) ?? intersection.point; | ||
const point = ray.direction.clone().multiplyScalar(intersection.distance).add(ray.origin); | ||
let uv = intersection.uv; | ||
if (intersection.object instanceof Mesh && getClosestUV(point2Helper, point, intersection.object)) { | ||
uv = point2Helper.clone(); | ||
} | ||
return { | ||
...intersection, | ||
uv, | ||
object, | ||
pointOnFace, | ||
point: ray.direction.clone().multiplyScalar(intersection.distance).add(ray.origin), | ||
point, | ||
pointerPosition: ray.origin.clone(), | ||
@@ -131,4 +138,9 @@ pointerQuaternion: this.raycasterQuaternion.clone(), | ||
computeIntersectionWorldPlane(this.viewPlane, intersection, object); | ||
let uv = intersection.uv; | ||
if (intersection.object instanceof Mesh && getClosestUV(point2Helper, point, intersection.object)) { | ||
uv = point2Helper.clone(); | ||
} | ||
return { | ||
...intersection, | ||
uv, | ||
object, | ||
@@ -135,0 +147,0 @@ point, |
@@ -1,6 +0,7 @@ | ||
import { InstancedMesh, Matrix4, Mesh, Vector3, Sphere, Quaternion, Plane, } from 'three'; | ||
import { InstancedMesh, Matrix4, Mesh, Vector3, Sphere, Quaternion, Plane, Vector2, } from 'three'; | ||
import { computeIntersectionWorldPlane, getDominantIntersectionIndex, pushTimes } from './utils.js'; | ||
import { getVoidObject } from '../index.js'; | ||
import { updateAndCheckWorldTransformation } from '../utils.js'; | ||
import { getClosestUV, updateAndCheckWorldTransformation } from '../utils.js'; | ||
const scaleHelper = new Vector3(); | ||
const point2Helper = new Vector2(); | ||
export class SphereIntersector { | ||
@@ -51,2 +52,6 @@ space; | ||
const pointOnFace = planeHelper.projectPoint(this.fromPosition, new Vector3()); | ||
let uv = intersection.uv; | ||
if (intersection.object instanceof Mesh && getClosestUV(point2Helper, point, intersection.object)) { | ||
uv = point2Helper.clone(); | ||
} | ||
return { | ||
@@ -56,2 +61,3 @@ details: { | ||
}, | ||
uv, | ||
distance: intersection.distance, | ||
@@ -58,0 +64,0 @@ pointerPosition: this.fromPosition.clone(), |
import { Vector3 } from 'three'; | ||
import { hasObjectListeners } from '../utils.js'; | ||
import { getVoidObject, VoidObjectCollider } from './intersector.js'; | ||
import { listenerNames } from '../event.js'; | ||
export function computeIntersectionWorldPlane(target, intersection, object) { | ||
@@ -80,2 +80,22 @@ const normal = intersection.normal ?? intersection.face?.normal; | ||
} | ||
function hasObjectListeners({ _listeners, __r3f }) { | ||
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 }, object, pointerEvents, pointerEventsType, pointerEventsOrder) { | ||
@@ -82,0 +102,0 @@ if (options.filter?.(object, pointerEvents, pointerEventsType, pointerEventsOrder) === false) { |
@@ -15,24 +15,4 @@ import { Object3D, OrthographicCamera, PerspectiveCamera } from '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; | ||
} | ||
@@ -39,0 +19,0 @@ } |
import { Mesh, Object3D, 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 declare function updateAndCheckWorldTransformation({ transformReady, parent, matrix, matrixWorld }: Object3D): boolean; | ||
export declare function hasObjectListeners({ _listeners, __r3f }: Object3D): boolean; | ||
export declare function getObjectListeners<E>(object: Object3D, forEvent: keyof PointerEventsMap): Array<(event: E) => void> | undefined; | ||
export declare function getClosestUV(target: Vector2, point: Vector3, mesh: Mesh): void; | ||
export declare function getClosestUV(target: Vector2, point: Vector3, mesh: Mesh): boolean; |
@@ -15,54 +15,2 @@ import { BufferAttribute, Matrix4, Triangle, Vector2, Vector3 } from 'three'; | ||
} | ||
export function hasObjectListeners({ _listeners, __r3f }) { | ||
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(object, forEvent) { | ||
if (object._listeners != null && forEvent in object._listeners) { | ||
return object._listeners[forEvent]; | ||
} | ||
//R3F compatibility | ||
let handler; | ||
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 = { | ||
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(); | ||
@@ -80,3 +28,3 @@ const triangleHelper2 = new Triangle(); | ||
if (uv == null || !(uv instanceof BufferAttribute)) { | ||
return void target.set(0, 0); | ||
return false; | ||
} | ||
@@ -90,3 +38,3 @@ let clostestDistance; | ||
if (clostestDistance != null && distance >= clostestDistance) { | ||
return void target.set(0, 0); | ||
return; | ||
} | ||
@@ -100,6 +48,7 @@ clostestDistance = distance; | ||
if (clostestDistance == null) { | ||
return void target.set(0, 0); | ||
return false; | ||
} | ||
triangleHelper2.closestPointToPoint(localPointHelper, pointHelper); | ||
triangleHelper2.getInterpolation(pointHelper, aVec2Helper, bVec2Helper, cVec2Helper, target); | ||
return true; | ||
} | ||
@@ -106,0 +55,0 @@ function loopThroughTriangles(mesh, fn) { |
@@ -5,3 +5,3 @@ { | ||
"license": "SEE LICENSE IN LICENSE", | ||
"version": "6.4.1", | ||
"version": "6.4.2", | ||
"homepage": "https://github.com/pmndrs/xr", | ||
@@ -8,0 +8,0 @@ "author": "Bela Bohlender", |
102055
2448