New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@coconut-xr/xinteraction

Package Overview
Dependencies
Maintainers
2
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@coconut-xr/xinteraction - npm Package Compare versions

Comparing version 0.0.3 to 0.0.4

dist/react/forward-events.d.ts

14

dist/index.d.ts

@@ -1,2 +0,1 @@

import { Camera } from "@react-three/fiber";
import { Intersection, Object3D, Quaternion, Vector3 } from "three";

@@ -10,10 +9,2 @@ export type ObjectEventTypes = "press" | "release" | "cancel" | "select" | "move" | "enter" | "leave" | "wheel" | "losteventcapture";

export declare function isXIntersection(val: Intersection): val is XIntersection;
/**
*
* @param p1 point 1 in world coordinates
* @param p2 point 2 in world coordinates
* @param camera
*/
export declare function getDistanceSquaredInNDC(camera: Camera, p1: Vector3, p2: Vector3): number;
export declare function isDragDefault(camera: Camera, i1: XIntersection, i2: XIntersection): boolean;
export type EventDispatcher<E, I extends XIntersection> = {

@@ -32,3 +23,2 @@ [Key in ObjectEventTypes]: (object: Object3D, intersection: I, inputDeviceElementId?: number) => void;

protected getPressedElementIds: (intersection?: I) => Iterable<number>;
protected isDrag: (pressIntersection: I, currentIntersection: I) => boolean;
protected getInputDeviceTransformation: (position: Vector3, rotation: Quaternion) => void;

@@ -41,3 +31,3 @@ onIntersections?: ((intersections: ReadonlyArray<I>) => void) | undefined;

private objectInteractionStateMap;
constructor(inputDeviceId: number, dispatchPressAlways: boolean, eventDispatcher: EventDispatcher<E, I>, computeIntersections: (event: E, capturedEvents?: Map<Object3D, I>) => Array<I>, getPressedElementIds: (intersection?: I) => Iterable<number>, isDrag: (pressIntersection: I, currentIntersection: I) => boolean, getInputDeviceTransformation: (position: Vector3, rotation: Quaternion) => void, onIntersections?: ((intersections: ReadonlyArray<I>) => void) | undefined, filterIntersections?: ((intersections: Array<I>) => Array<I>) | undefined);
constructor(inputDeviceId: number, dispatchPressAlways: boolean, eventDispatcher: EventDispatcher<E, I>, computeIntersections: (event: E, capturedEvents?: Map<Object3D, I>) => Array<I>, getPressedElementIds: (intersection?: I) => Iterable<number>, getInputDeviceTransformation: (position: Vector3, rotation: Quaternion) => void, onIntersections?: ((intersections: ReadonlyArray<I>) => void) | undefined, filterIntersections?: ((intersections: Array<I>) => Array<I>) | undefined);
/**

@@ -54,3 +44,2 @@ * called when the input device receives a press, release, or move event

private updateElementStateMap;
private checkDrag;
private dispatchPress;

@@ -72,1 +61,2 @@ private dispatchRelease;

}
export * from "./intersections/index.js";

@@ -5,23 +5,4 @@ import { Object3D, Quaternion, Vector3 } from "three";

}
const p1Helper = new Vector3();
const p2Helper = new Vector3();
const inputSourcePositionHelper = new Vector3();
const inputSourceRotationHelper = new Quaternion();
/**
*
* @param p1 point 1 in world coordinates
* @param p2 point 2 in world coordinates
* @param camera
*/
export function getDistanceSquaredInNDC(camera, p1, p2) {
return p1Helper
.copy(p1)
.project(camera)
.distanceToSquared(p2Helper.copy(p2).project(camera));
}
const defaultDragDistanceSquared = 0.0001; //0.01
export function isDragDefault(camera, i1, i2) {
return (getDistanceSquaredInNDC(camera, i1.point, i2.point) >
defaultDragDistanceSquared);
}
const traversalIdSymbol = Symbol("traversal-id");

@@ -36,3 +17,2 @@ const emptySet = new Set();

getPressedElementIds;
isDrag;
getInputDeviceTransformation;

@@ -46,3 +26,3 @@ onIntersections;

objectInteractionStateMap = new Map();
constructor(inputDeviceId, dispatchPressAlways, eventDispatcher, computeIntersections, getPressedElementIds, isDrag, getInputDeviceTransformation, onIntersections, filterIntersections) {
constructor(inputDeviceId, dispatchPressAlways, eventDispatcher, computeIntersections, getPressedElementIds, getInputDeviceTransformation, onIntersections, filterIntersections) {
this.inputDeviceId = inputDeviceId;

@@ -53,3 +33,2 @@ this.dispatchPressAlways = dispatchPressAlways;

this.getPressedElementIds = getPressedElementIds;
this.isDrag = isDrag;
this.getInputDeviceTransformation = getInputDeviceTransformation;

@@ -99,3 +78,3 @@ this.onIntersections = onIntersections;

this.dispatchPress(eventObject, intersection, pressedElementIds, dispatchPressFor);
this.dispatchRelease(eventObject, intersection, interactionState, pressedElementIds, currentTime);
this.dispatchRelease(eventObject, intersection, interactionState, pressedElementIds);
this.updateElementStateMap(intersection, interactionState, pressedElementIds, dispatchPressFor, currentTime);

@@ -118,3 +97,3 @@ }

}
this.dispatchRelease(eventObject, intersection, interactionState, pressedElementIds, currentTime);
this.dispatchRelease(eventObject, intersection, interactionState, pressedElementIds);
this.eventDispatcher.leave(eventObject, intersection);

@@ -162,14 +141,4 @@ interactionState.lastLeftTime = currentTime;

}
else {
this.checkDrag(intersection, interactionState, pressedElementId, currentTime);
}
}
}
checkDrag(intersection, interactionState, pressedElementId, currentTime) {
const elementState = interactionState.elementStateMap.get(pressedElementId);
if (elementState != null &&
this.isDrag(elementState.lastPressEventIntersection, intersection)) {
elementState.lastDragTime = currentTime;
}
}
dispatchPress(eventObject, intersection, pressedElementIds, dispatchPressFor) {

@@ -183,3 +152,3 @@ for (const pressedElementId of pressedElementIds) {

}
dispatchRelease(eventObject, intersection, interactionState, pressedElementIds, currentTime) {
dispatchRelease(eventObject, intersection, interactionState, pressedElementIds) {
for (const releasedElementId of interactionState.lastPressedElementIds) {

@@ -189,3 +158,2 @@ if (pressedElementIds.has(releasedElementId)) {

}
this.checkDrag(intersection, interactionState, releasedElementId, currentTime);
//pressedElementId was not pressed this time

@@ -197,6 +165,4 @@ this.eventDispatcher.release(eventObject, intersection, releasedElementId);

(interactionState.lastLeftTime == null ||
interactionState.lastLeftTime < elementState.lastPressEventTime) &&
(elementState.lastDragTime == null ||
elementState.lastDragTime < elementState.lastPressEventTime)) {
//=> the object wasn't left and dragged since it was pressed last
interactionState.lastLeftTime < elementState.lastPressEventTime)) {
//=> the object wasn't left since it was pressed last
this.eventDispatcher.select(eventObject, intersection, releasedElementId);

@@ -291,1 +257,2 @@ }

}
export * from "./intersections/index.js";
import { Intersection, Object3D } from "three";
export declare function traverseUntilInteractable<T, R>(object: Object3D, isInteractable: (object: Object3D) => boolean, callback: (object: Object3D) => T, reduce: (prev: R, value: T) => R, initial: R): R;
export declare function isIntersectionNotClipped(intersection: Intersection): boolean;
export * from "./lines.js";
export * from "./ray.js";
export * from "./sphere.js";

@@ -25,1 +25,4 @@ import { Mesh } from "three";

}
export * from "./lines.js";
export * from "./ray.js";
export * from "./sphere.js";
import { Object3D, Quaternion, Vector3 } from "three";
import { EventDispatcher, XIntersection } from "../index.js";
import { ThreeEvent } from "@react-three/fiber";
export type XLinesIntersection = XIntersection & {

@@ -8,2 +9,2 @@ lineIndex: number;

export declare function intersectLinesFromCapturedEvents(from: Object3D, fromPosition: Vector3, fromRotation: Quaternion, linePoints: Array<Vector3>, capturedEvents: Map<Object3D, XLinesIntersection>): Array<XLinesIntersection>;
export declare function intersectLinesFromObject(from: Object3D, fromPosition: Vector3, fromRotation: Quaternion, linePoints: Array<Vector3>, on: Object3D, dispatcher: EventDispatcher<Event, XLinesIntersection>, filterClipped: boolean): Array<XLinesIntersection>;
export declare function intersectLinesFromObject(from: Object3D, fromPosition: Vector3, fromRotation: Quaternion, linePoints: Array<Vector3>, on: Object3D, dispatcher: EventDispatcher<ThreeEvent<Event>, XLinesIntersection>, filterClipped: boolean): Array<XLinesIntersection>;
import { Camera, Object3D, Quaternion, Vector2, Vector3 } from "three";
import { EventDispatcher, XIntersection } from "../index.js";
import { ThreeEvent } from "@react-three/fiber";
export type XCameraRayIntersection = XIntersection & {
distanceViewPlane: number;
};
export declare function intersectRayFromCapturedEvents(fromPosition: Vector3, fromRotation: Quaternion, capturedEvents: Map<Object3D, XIntersection>): Array<XIntersection>;
export declare function intersectRayFromCapturedEvents(fromPosition: Vector3, fromRotation: Quaternion, capturedEvents: Map<Object3D, XIntersection>, direction: Vector3): Array<XIntersection>;
export declare function intersectRayFromCameraCapturedEvents(camera: Camera, coords: Vector2, capturedEvents: Map<Object3D, XCameraRayIntersection>, worldPositionTarget: Vector3, worldQuaternionTarget: Quaternion): Array<XCameraRayIntersection>;
export declare function intersectRayFromObject(fromPosition: Vector3, fromRotation: Quaternion, on: Object3D, dispatcher: EventDispatcher<Event, XIntersection>, filterClipped: boolean): Array<XIntersection>;
export declare function intersectRayFromCamera(from: Camera, coords: Vector2, on: Object3D, dispatcher: EventDispatcher<Event, XCameraRayIntersection>, filterClipped: boolean, worldPositionTarget: Vector3, worldQuaternionTarget: Quaternion): Array<XCameraRayIntersection>;
export declare function intersectRayFromObject(fromPosition: Vector3, fromRotation: Quaternion, on: Object3D, dispatcher: EventDispatcher<ThreeEvent<Event>, XIntersection>, filterClipped: boolean, direction: Vector3): Array<XIntersection>;
export declare function intersectRayFromCamera(from: Camera, coords: Vector2, on: Object3D, dispatcher: EventDispatcher<ThreeEvent<Event>, XCameraRayIntersection>, filterClipped: boolean, worldPositionTarget: Vector3, worldQuaternionTarget: Quaternion): Array<XCameraRayIntersection>;

@@ -6,4 +6,4 @@ import { Plane, Raycaster, Vector3, } from "three";

const planeHelper = new Plane();
export function intersectRayFromCapturedEvents(fromPosition, fromRotation, capturedEvents) {
directionHelper.set(0, 0, 1).applyQuaternion(fromRotation);
export function intersectRayFromCapturedEvents(fromPosition, fromRotation, capturedEvents, direction) {
directionHelper.copy(direction).applyQuaternion(fromRotation);
return Array.from(capturedEvents).map(([capturedObject, intersection]) => {

@@ -24,4 +24,4 @@ return {

raycaster.setFromCamera(coords, camera);
worldPositionTarget.copy(raycaster.ray.origin);
worldQuaternionTarget.setFromUnitVectors(ZAXIS, raycaster.ray.direction);
camera.getWorldPosition(worldPositionTarget);
camera.getWorldQuaternion(worldQuaternionTarget);
camera.getWorldDirection(directionHelper);

@@ -44,5 +44,5 @@ return Array.from(capturedEvents).map(([capturedObject, intersection]) => {

}
export function intersectRayFromObject(fromPosition, fromRotation, on, dispatcher, filterClipped) {
export function intersectRayFromObject(fromPosition, fromRotation, on, dispatcher, filterClipped, direction) {
raycaster.ray.origin.copy(fromPosition);
raycaster.ray.direction.set(0, 0, 1).applyQuaternion(fromRotation);
raycaster.ray.direction.copy(direction).applyQuaternion(fromRotation);
let intersections = traverseUntilInteractable(on, dispatcher.hasEventHandlers.bind(dispatcher), (object) => raycaster.intersectObject(object, true).map((intersection) => Object.assign(intersection, {

@@ -58,7 +58,6 @@ inputDevicePosition: fromPosition.clone(),

}
const ZAXIS = new Vector3();
export function intersectRayFromCamera(from, coords, on, dispatcher, filterClipped, worldPositionTarget, worldQuaternionTarget) {
raycaster.setFromCamera(coords, from);
worldPositionTarget.copy(raycaster.ray.origin);
worldQuaternionTarget.setFromUnitVectors(ZAXIS, raycaster.ray.direction);
from.getWorldPosition(worldPositionTarget);
from.getWorldQuaternion(worldQuaternionTarget);
planeHelper.setFromNormalAndCoplanarPoint(from.getWorldDirection(directionHelper), raycaster.ray.origin);

@@ -65,0 +64,0 @@ let intersections = traverseUntilInteractable(on, dispatcher.hasEventHandlers.bind(dispatcher), (object) => raycaster.intersectObject(object, true).map((intersection) => Object.assign(intersection, {

import { Object3D, Vector3, Quaternion } from "three";
import { EventDispatcher, XIntersection } from "../index.js";
import { ThreeEvent } from "@react-three/fiber";
export type XSphereIntersection = XIntersection & {

@@ -10,2 +11,2 @@ /**

export declare function intersectSphereFromCapturedEvents(fromPosition: Vector3, fromRotation: Quaternion, capturedEvents: Map<Object3D, XSphereIntersection>): Array<XSphereIntersection>;
export declare function intersectSphereFromObject(fromPosition: Vector3, fromQuaternion: Quaternion, radius: number, on: Object3D, dispatcher: EventDispatcher<Event, XSphereIntersection>, filterClipped: boolean): Array<XSphereIntersection>;
export declare function intersectSphereFromObject(fromPosition: Vector3, fromQuaternion: Quaternion, radius: number, on: Object3D, dispatcher: EventDispatcher<ThreeEvent<Event>, XSphereIntersection>, filterClipped: boolean): Array<XSphereIntersection>;
import React from "react";
import { Vector3, Event } from "three";
import { XIntersection } from "../index.js";
import { XLinesIntersection } from "../intersections/lines.js";

@@ -15,4 +14,3 @@ import { InputDeviceFunctions } from "./index.js";

onClickMissed?: ((event: ThreeEvent<Event>) => void) | undefined;
isDrag?: ((i1: XIntersection, i2: XIntersection) => boolean) | undefined;
filterClipped?: boolean | undefined;
} & React.RefAttributes<InputDeviceFunctions>>;
/* eslint-disable react/display-name */
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, } from "react";
import { Quaternion, Vector3 } from "three";
import { EventTranslator, isDragDefault } from "../index.js";
import { EventTranslator } from "../index.js";
import { intersectLinesFromCapturedEvents, intersectLinesFromObject, } from "../intersections/lines.js";

@@ -11,3 +11,3 @@ import { R3FEventDispatcher } from "./index.js";

const worldRotationHelper = new Quaternion();
export const XCurvedPointer = forwardRef(({ id, points, onIntersections, filterIntersections, onClickMissed, onPointerDownMissed, onPointerUpMissed, isDrag: customIsDrag, filterClipped = true, }, ref) => {
export const XCurvedPointer = forwardRef(({ id, points, onIntersections, filterIntersections, onClickMissed, onPointerDownMissed, onPointerUpMissed, filterClipped = true, }, ref) => {
const objectRef = useRef(null);

@@ -20,5 +20,4 @@ const store = useStore();

const pressedElementIds = useMemo(() => new Set(), []);
const properties = useMemo(() => ({ points, customIsDrag, filterClipped }), []);
const properties = useMemo(() => ({ points, filterClipped }), []);
properties.points = points;
properties.customIsDrag = customIsDrag;
properties.filterClipped = filterClipped;

@@ -35,5 +34,3 @@ const translator = useMemo(() => new EventTranslator(id, false, dispatcher, (_, capturedEvents) => {

: intersectLinesFromCapturedEvents(objectRef.current, worldPositionHelper, worldRotationHelper, properties.points, capturedEvents);
}, () => pressedElementIds, (i1, i2) => properties.customIsDrag == null
? isDragDefault(store.getState().camera, i1, i2)
: properties.customIsDrag(i1, i2), (position, rotation) => {
}, () => pressedElementIds, (position, rotation) => {
if (objectRef.current == null) {

@@ -40,0 +37,0 @@ return;

@@ -6,3 +6,3 @@ import { Object3D, Event } from "three";

export declare const noEvents: () => EventManager<HTMLElement>;
export declare class R3FEventDispatcher<I extends XIntersection> implements EventDispatcher<Event, I> {
export declare class R3FEventDispatcher<I extends XIntersection> implements EventDispatcher<ThreeEvent<Event>, I> {
onPointerDownMissed?: ((event: ThreeEvent<Event>) => void) | undefined;

@@ -26,3 +26,3 @@ onPointerUpMissed?: ((event: ThreeEvent<Event>) => void) | undefined;

private createEvent;
bind(event: Event, eventTranslator: EventTranslator<Event, I>): void;
bind(event: ThreeEvent<Event>, eventTranslator: EventTranslator<ThreeEvent<Event>, I>): void;
hasEventHandlers(object: Object3D<Event>): boolean;

@@ -36,2 +36,3 @@ }

};
export * from "./forward-events.js";
export * from "./web-pointers.js";

@@ -38,0 +39,0 @@ export * from "./straight-pointer.js";

@@ -108,2 +108,3 @@ import { voidObject, } from "../index.js";

}
export * from "./forward-events.js";
export * from "./web-pointers.js";

@@ -110,0 +111,0 @@ export * from "./straight-pointer.js";

import { ThreeEvent } from "@react-three/fiber";
import React from "react";
import { Event } from "three";
import { XIntersection } from "../index.js";
import { InputDeviceFunctions } from "./index.js";
import { XSphereIntersection } from "../intersections/sphere.js";
export declare const XSphereCollider: React.ForwardRefExoticComponent<{

@@ -13,9 +13,8 @@ id: number;

} | undefined;
onIntersections?: ((intersections: ReadonlyArray<XIntersection>) => void) | undefined;
filterIntersections?: ((intersections: Array<XIntersection>) => Array<XIntersection>) | undefined;
onIntersections?: ((intersections: ReadonlyArray<XSphereIntersection>) => void) | undefined;
filterIntersections?: ((intersections: Array<XSphereIntersection>) => Array<XSphereIntersection>) | undefined;
onPointerDownMissed?: ((event: ThreeEvent<Event>) => void) | undefined;
onPointerUpMissed?: ((event: ThreeEvent<Event>) => void) | undefined;
onClickMissed?: ((event: ThreeEvent<Event>) => void) | undefined;
isDrag?: ((i1: XIntersection, i2: XIntersection) => boolean) | undefined;
filterClipped?: boolean | undefined;
} & React.RefAttributes<InputDeviceFunctions>>;

@@ -5,3 +5,3 @@ /* eslint-disable react/display-name */

import { Quaternion, Vector3 } from "three";
import { EventTranslator, isDragDefault } from "../index.js";
import { EventTranslator } from "../index.js";
import { R3FEventDispatcher } from "./index.js";

@@ -12,3 +12,3 @@ import { intersectSphereFromCapturedEvents, intersectSphereFromObject, } from "../intersections/sphere.js";

const worldRotationHelper = new Quaternion();
export const XSphereCollider = forwardRef(({ id, distanceElement, radius, onIntersections, filterIntersections, onClickMissed, onPointerDownMissed, onPointerUpMissed, isDrag: customIsDrag, filterClipped = true, }, ref) => {
export const XSphereCollider = forwardRef(({ id, distanceElement, radius, onIntersections, filterIntersections, onClickMissed, onPointerDownMissed, onPointerUpMissed, filterClipped = true, }, ref) => {
const objectRef = useRef(null);

@@ -21,6 +21,5 @@ const store = useStore();

dispatcher.onClickMissed = onClickMissed;
const properties = useMemo(() => ({ distanceElement, radius, customIsDrag, filterClipped }), []);
const properties = useMemo(() => ({ distanceElement, radius, filterClipped }), []);
properties.distanceElement = distanceElement;
properties.radius = radius;
properties.customIsDrag = customIsDrag;
properties.filterClipped = filterClipped;

@@ -53,5 +52,3 @@ const translator = useMemo(() => new EventTranslator(id, true, dispatcher, (_, capturedEvents) => {

return pressedElementIds;
}, (i1, i2) => properties.customIsDrag == null
? isDragDefault(store.getState().camera, i1, i2)
: properties.customIsDrag(i1, i2), (position, rotation) => {
}, (position, rotation) => {
if (objectRef.current == null) {

@@ -58,0 +55,0 @@ return;

import React from "react";
import { Event } from "three";
import { Vector3, Event } from "three";
import { XIntersection } from "../index.js";

@@ -14,3 +14,4 @@ import { InputDeviceFunctions } from "./index.js";

isDrag?: ((i1: XIntersection, i2: XIntersection) => boolean) | undefined;
direction?: Vector3 | undefined;
filterClipped?: boolean | undefined;
} & React.RefAttributes<InputDeviceFunctions>>;
/* eslint-disable react/display-name */
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, } from "react";
import { Quaternion, Vector3 } from "three";
import { EventTranslator, isDragDefault } from "../index.js";
import { EventTranslator } from "../index.js";
import { intersectRayFromCapturedEvents, intersectRayFromObject, } from "../intersections/ray.js";

@@ -11,3 +11,4 @@ import { R3FEventDispatcher } from "./index.js";

const worldRotationHelper = new Quaternion();
export const XStraightPointer = forwardRef(({ id, onIntersections, filterIntersections, onClickMissed, onPointerDownMissed, onPointerUpMissed, isDrag: customIsDrag, filterClipped = true, }, ref) => {
const ZAXIS = new Vector3();
export const XStraightPointer = forwardRef(({ id, onIntersections, filterIntersections, onClickMissed, onPointerDownMissed, onPointerUpMissed, filterClipped = true, direction = ZAXIS, }, ref) => {
const store = useStore();

@@ -20,5 +21,5 @@ const objectRef = useRef(null);

const pressedElementIds = useMemo(() => new Set(), []);
const properties = useMemo(() => ({ customIsDrag, filterClipped }), []);
properties.customIsDrag = customIsDrag;
const properties = useMemo(() => ({ filterClipped, direction }), []);
properties.filterClipped = filterClipped;
properties.direction = direction;
const translator = useMemo(() => new EventTranslator(id, false, dispatcher, (events, capturedEvents) => {

@@ -32,8 +33,6 @@ if (objectRef.current == null) {

? //no events captured -> compute intersections normally
intersectRayFromObject(worldPositionHelper, worldRotationHelper, store.getState().scene, dispatcher, properties.filterClipped)
intersectRayFromObject(worldPositionHelper, worldRotationHelper, store.getState().scene, dispatcher, properties.filterClipped, properties.direction)
: //events captured
intersectRayFromCapturedEvents(worldPositionHelper, worldRotationHelper, capturedEvents);
}, () => pressedElementIds, (i1, i2) => properties.customIsDrag == null
? isDragDefault(store.getState().camera, i1, i2)
: properties.customIsDrag(i1, i2), (position, rotation) => {
intersectRayFromCapturedEvents(worldPositionHelper, worldRotationHelper, capturedEvents, properties.direction);
}, () => pressedElementIds, (position, rotation) => {
if (objectRef.current == null) {

@@ -40,0 +39,0 @@ return;

import { ThreeEvent } from "@react-three/fiber";
import { XIntersection } from "../index.js";
import { Event } from "three";
import { XCameraRayIntersection } from "../intersections/ray.js";
export declare function XWebPointers({ onIntersections, filterIntersections, onClickMissed, onPointerDownMissed, onPointerUpMissed, isDrag: customIsDrag, filterClipped, }: {
export declare function XWebPointers({ filterClipped, filterIntersections, onClickMissed, onIntersections, onPointerDownMissed, onPointerUpMissed, }: {
onIntersections?: (id: number, intersections: ReadonlyArray<XCameraRayIntersection>) => void;
filterIntersections?: (intersections: Array<XCameraRayIntersection>) => Array<XCameraRayIntersection>;
filterIntersections?: (id: number, intersections: Array<XCameraRayIntersection>) => Array<XCameraRayIntersection>;
onPointerDownMissed?: (event: ThreeEvent<Event>) => void;
onPointerUpMissed?: (event: ThreeEvent<Event>) => void;
onClickMissed?: (event: ThreeEvent<Event>) => void;
isDrag?: (i1: XIntersection, i2: XIntersection) => boolean;
filterClipped?: boolean;
}): null;
import { useStore, useThree } from "@react-three/fiber";
import { Vector2 } from "three";
import { intersectRayFromCamera, intersectRayFromCameraCapturedEvents, } from "../intersections/ray.js";
import { useForwardEvents } from "./forward-events.js";
import { useEffect, useMemo } from "react";
import { EventTranslator, isDragDefault } from "../index.js";
import { R3FEventDispatcher } from "./index.js";
import { Vector2, Vector3, Quaternion } from "three";
import { intersectRayFromCamera, intersectRayFromCameraCapturedEvents, } from "../intersections/ray.js";
export function XWebPointers({ onIntersections, filterIntersections, onClickMissed, onPointerDownMissed, onPointerUpMissed, isDrag: customIsDrag, filterClipped = true, }) {
const pointerMap = useMemo(() => new Map(), []);
const emptyIntersection = [];
export function XWebPointers({ filterClipped, filterIntersections, onClickMissed, onIntersections, onPointerDownMissed, onPointerUpMissed, }) {
const store = useStore();
const dispatcher = useMemo(() => new R3FEventDispatcher(), []);
dispatcher.onPointerDownMissed = onPointerDownMissed;
dispatcher.onPointerUpMissed = onPointerUpMissed;
dispatcher.onClickMissed = onClickMissed;
//update properties for all pointers
for (const [pointerId, entry] of pointerMap) {
entry.translator.onIntersections = onIntersections?.bind(null, pointerId);
entry.translator.filterIntersections = filterIntersections;
entry.customIsDrag = customIsDrag;
entry.filterClipped = filterClipped;
}
const canvas = useThree(({ gl }) => gl.domElement);
const intersections = useMemo(() => computeIntersections.bind(null, store), [store]);
const eventFunctions = useForwardEvents(intersections, onIntersections, filterIntersections, onPointerDownMissed, onPointerUpMissed, onClickMissed, filterClipped);
useEffect(() => {
const getOrCreate = (id) => getOrCreatePointerMapEntry(pointerMap, store, dispatcher, id);
const pointercancel = (event) => {
const { translator } = getOrCreate(event.pointerId);
translator.cancel(event);
};
const pointerdown = (event) => {
const { pressedInputDeviceElements, translator } = getOrCreate(event.pointerId);
updatePressedButtons(event.buttons, pressedInputDeviceElements);
translator.update(event, false, true, event.button);
};
const pointerup = (event) => {
const { pressedInputDeviceElements, translator } = getOrCreate(event.pointerId);
updatePressedButtons(event.buttons, pressedInputDeviceElements);
translator.update(event, false, true);
};
const pointerover = (event) => {
const { translator, pressedInputDeviceElements } = getOrCreate(event.pointerId);
updatePressedButtons(event.buttons, pressedInputDeviceElements);
translator.update(event, true, true, event.button);
};
const pointermove = (event) => {
const { translator } = getOrCreate(event.pointerId);
translator.update(event, true, false);
};
const wheel = (event) => {
for (const { translator } of pointerMap.values()) {
translator.wheel(event);
}
};
const pointerout = (event) => {
const { translator } = getOrCreate(event.pointerId);
translator.leave(event);
pointerMap.delete(event.pointerId);
};
const blur = (event) => {
for (const { translator } of pointerMap.values()) {
translator.leave(event);
}
pointerMap.clear();
};
canvas.addEventListener("pointercancel", pointercancel);
canvas.addEventListener("pointerdown", pointerdown);
canvas.addEventListener("pointerup", pointerup);
canvas.addEventListener("pointerover", pointerover);
canvas.addEventListener("pointerout", pointerout);
canvas.addEventListener("pointermove", pointermove);
canvas.addEventListener("wheel", wheel);
canvas.addEventListener("blur", blur);
const pointerCancel = (e) => eventFunctions.cancel(e.pointerId, e);
const pointerDown = (e) => eventFunctions.press(e.pointerId, e, e.button);
const pointerUp = (e) => eventFunctions.release(e.pointerId, e, e.button);
const pointerOver = (e) => eventFunctions.enter(e.pointerId, e);
const pointerOut = (e) => eventFunctions.leave(e.pointerId, e);
const pointerMove = (e) => eventFunctions.move(e.pointerId, e);
canvas.addEventListener("pointercancel", pointerCancel);
canvas.addEventListener("pointerdown", pointerDown);
canvas.addEventListener("pointerup", pointerUp);
canvas.addEventListener("pointerover", pointerOver);
canvas.addEventListener("pointerout", pointerOut);
canvas.addEventListener("pointermove", pointerMove);
canvas.addEventListener("wheel", eventFunctions.wheel);
canvas.addEventListener("blur", eventFunctions.blur);
return () => {
canvas.removeEventListener("pointercancel", pointercancel);
canvas.removeEventListener("pointerdown", pointerdown);
canvas.removeEventListener("pointerup", pointerup);
canvas.removeEventListener("pointerover", pointerover);
canvas.removeEventListener("pointerout", pointerout);
canvas.removeEventListener("pointermove", pointermove);
canvas.removeEventListener("wheel", wheel);
canvas.removeEventListener("blur", blur);
canvas.removeEventListener("pointercancel", pointerCancel);
canvas.removeEventListener("pointerdown", pointerDown);
canvas.removeEventListener("pointerup", pointerUp);
canvas.removeEventListener("pointerover", pointerOver);
canvas.removeEventListener("pointerout", pointerOut);
canvas.removeEventListener("pointermove", pointerMove);
canvas.removeEventListener("wheel", eventFunctions.wheel);
canvas.removeEventListener("blur", eventFunctions.blur);
};
}, [canvas, store]);
}, [canvas, eventFunctions]);
return null;
}
function updatePressedButtons(buttons, pressedInputDeviceElements) {
let value = 1;
//5 buttons can be expected https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
for (let i = 0; i < 5; i++) {
const inputDeviceElementActive = (value & buttons) > 0;
if (inputDeviceElementActive) {
pressedInputDeviceElements.add(i);
}
else {
pressedInputDeviceElements.delete(i);
}
value *= 2;
function computeIntersections(store, event, capturedEvents, filterClipped, dispatcher, targetWorldPosition, targetWorldQuaternion) {
if (!(event.target instanceof HTMLCanvasElement)) {
return emptyIntersection;
}
const { camera, scene, size } = store.getState();
const coords = new Vector2((event.offsetX / size.width) * 2 - 1, -(event.offsetY / size.height) * 2 + 1);
return capturedEvents == null
? intersectRayFromCamera(camera, coords, scene, dispatcher, filterClipped, targetWorldPosition, targetWorldQuaternion)
: intersectRayFromCameraCapturedEvents(camera, coords, capturedEvents, targetWorldPosition, targetWorldQuaternion);
}
function getOrCreatePointerMapEntry(pointerMap, store, dispatcher, pointerId) {
let entry = pointerMap.get(pointerId);
if (entry == null) {
pointerMap.set(pointerId, (entry = createPointerMapEntry(pointerId, store, dispatcher)));
}
return entry;
}
const emptyIntersection = [];
function createPointerMapEntry(pointerId, store, dispatcher) {
const lastWorldPosition = new Vector3();
const lastWorldRotation = new Quaternion();
const pointerMapEntry = {
filterClipped: true,
pressedInputDeviceElements: new Set(),
translator: new EventTranslator(pointerId, false, dispatcher, (event, capturedEvents) => {
if (!(event.target instanceof HTMLCanvasElement)) {
return emptyIntersection;
}
const { camera, scene, size } = store.getState();
const coords = new Vector2((event.offsetX / size.width) * 2 - 1, -(event.offsetY / size.height) * 2 + 1);
return capturedEvents == null
? intersectRayFromCamera(camera, coords, scene, dispatcher, pointerMapEntry.filterClipped, lastWorldPosition, lastWorldRotation)
: intersectRayFromCameraCapturedEvents(camera, coords, capturedEvents, lastWorldPosition, lastWorldRotation);
}, () => pointerMapEntry.pressedInputDeviceElements, (i1, i2) => pointerMapEntry.customIsDrag == null
? isDragDefault(store.getState().camera, i1, i2)
: pointerMapEntry.customIsDrag(i1, i2), (position, rotation) => {
position.copy(lastWorldPosition);
rotation.copy(lastWorldRotation);
}),
};
return pointerMapEntry;
}
{
"name": "@coconut-xr/xinteraction",
"version": "0.0.3",
"version": "0.0.4",
"homepage": "https://coconut-xr.github.io/xinteraction",

@@ -5,0 +5,0 @@ "license": "SEE LICENSE IN LICENSE",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc