Skip to content

Commit 5369e7f

Browse files
committed
fix: inherit pointerEventsOrder, #318 forwardObjectEvents inverted, origin scale + minDistance is incorrect
1 parent 0735728 commit 5369e7f

File tree

8 files changed

+102
-37
lines changed

8 files changed

+102
-37
lines changed

packages/pointer-events/src/forward.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ function portalEventToCoords(e: unknown, target: Vector2): Vector2 {
6464
return target.set(0, 0)
6565
}
6666
target.copy(e.uv).multiplyScalar(2).addScalar(-1)
67-
target.y *= -1
6867
return target
6968
}
7069

packages/pointer-events/src/intersections/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,12 @@ export type IntersectionOptions = {
3838
* for sorting by distance use i1.distance - i2.distance
3939
* => if i1 has a smaller distance the value is negative and i1 is returned as intersection
4040
*/
41-
customSort?: (i1: ThreeIntersection, i2: ThreeIntersection) => number
41+
customSort?: (
42+
i1: ThreeIntersection,
43+
pointerEventsOrder1: number | undefined,
44+
i2: ThreeIntersection,
45+
pointerEventsOrder2: number | undefined,
46+
) => number
4247
}
4348

4449
export * from './lines.js'

packages/pointer-events/src/intersections/lines.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
Object3D,
1111
} from 'three'
1212
import { Intersection, IntersectionOptions } from './index.js'
13-
import { computeIntersectionWorldPlane, getDominantIntersection, traversePointerEventTargets } from './utils.js'
13+
import { computeIntersectionWorldPlane, getDominantIntersectionIndex, traversePointerEventTargets } from './utils.js'
1414
import type { PointerCapture } from '../pointer.js'
1515

1616
const raycaster = new Raycaster()
@@ -31,8 +31,9 @@ export function intersectLines(
3131
return intersectLinesPointerCapture(fromMatrixWorld, linePoints, pointerCapture)
3232
}
3333
let intersection: (ThreeIntersection & { details: { distanceOnLine: number; lineIndex: number } }) | undefined
34+
let pointerEventsOrder: number | undefined
3435

35-
traversePointerEventTargets(scene, pointerId, pointerType, pointerState, (object) => {
36+
traversePointerEventTargets(scene, pointerId, pointerType, pointerState, (object, objectPointerEventsOrder) => {
3637
let prevAccLineLength = 0
3738
const length = (intersection?.details.lineIndex ?? linePoints.length - 2) + 2
3839
for (let i = 1; i < length; i++) {
@@ -64,7 +65,17 @@ export function intersectLines(
6465
},
6566
})
6667
}
67-
intersection = getDominantIntersection(intersection, intersectsHelper, options)
68+
const index = getDominantIntersectionIndex(
69+
intersection,
70+
pointerEventsOrder,
71+
intersectsHelper,
72+
objectPointerEventsOrder,
73+
options,
74+
)
75+
if (index != null) {
76+
intersection = intersectsHelper[index]
77+
pointerEventsOrder = objectPointerEventsOrder
78+
}
6879
intersectsHelper.length = 0
6980
prevAccLineLength += lineLength
7081
}

packages/pointer-events/src/intersections/ray.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
} from 'three'
1313
import { Intersection, IntersectionOptions } from './index.js'
1414
import type { PointerCapture } from '../pointer.js'
15-
import { computeIntersectionWorldPlane, getDominantIntersection, traversePointerEventTargets } from './utils.js'
15+
import { computeIntersectionWorldPlane, getDominantIntersectionIndex, traversePointerEventTargets } from './utils.js'
1616

1717
const raycaster = new Raycaster()
1818
const directionHelper = new Vector3()
@@ -34,12 +34,23 @@ export function intersectRay(
3434
if (pointerCapture != null) {
3535
return intersectRayPointerCapture(fromPosition, fromQuaternion, direction, pointerCapture)
3636
}
37-
let intersection: ThreeIntersection | undefined
37+
let intersection: (ThreeIntersection & { pointerEventsOrder?: number }) | undefined
38+
let pointerEventsOrder: number | undefined
3839
raycaster.ray.origin.copy(fromPosition)
3940
raycaster.ray.direction.copy(direction).applyQuaternion(fromQuaternion)
40-
traversePointerEventTargets(scene, pointerId, pointerType, pointerState, (object) => {
41+
traversePointerEventTargets(scene, pointerId, pointerType, pointerState, (object, objectPointerEventsOrder) => {
4142
object.raycast(raycaster, intersectsHelper)
42-
intersection = getDominantIntersection(intersection, intersectsHelper, options)
43+
const index = getDominantIntersectionIndex(
44+
intersection,
45+
pointerEventsOrder,
46+
intersectsHelper,
47+
objectPointerEventsOrder,
48+
options,
49+
)
50+
if (index != null) {
51+
intersection = intersectsHelper[index]
52+
pointerEventsOrder = objectPointerEventsOrder
53+
}
4354
intersectsHelper.length = 0
4455
})
4556
if (intersection == null) {
@@ -99,14 +110,25 @@ export function intersectRayFromCamera(
99110
return intersectRayFromCameraPointerCapture(from, coords, fromPosition, fromQuaternion, pointerCapture)
100111
}
101112
let intersection: ThreeIntersection | undefined
113+
let pointerEventsOrder: number | undefined
102114

103115
raycaster.setFromCamera(coords, from)
104116

105117
planeHelper.setFromNormalAndCoplanarPoint(from.getWorldDirection(directionHelper), raycaster.ray.origin)
106118

107-
traversePointerEventTargets(scene, pointerId, pointerType, pointerState, (object) => {
119+
traversePointerEventTargets(scene, pointerId, pointerType, pointerState, (object, objectPointerEventsOrder) => {
108120
object.raycast(raycaster, intersectsHelper)
109-
intersection = getDominantIntersection(intersection, intersectsHelper, options)
121+
const index = getDominantIntersectionIndex(
122+
intersection,
123+
pointerEventsOrder,
124+
intersectsHelper,
125+
objectPointerEventsOrder,
126+
options,
127+
)
128+
if (index != null) {
129+
intersection = intersectsHelper[index]
130+
pointerEventsOrder = objectPointerEventsOrder
131+
}
110132
intersectsHelper.length = 0
111133
})
112134

packages/pointer-events/src/intersections/sphere.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
Plane,
1111
} from 'three'
1212
import { Intersection, IntersectionOptions } from './index.js'
13-
import { computeIntersectionWorldPlane, getDominantIntersection, traversePointerEventTargets } from './utils.js'
13+
import { computeIntersectionWorldPlane, getDominantIntersectionIndex, traversePointerEventTargets } from './utils.js'
1414
import type { PointerCapture } from '../pointer.js'
1515

1616
const collisionSphere = new Sphere()
@@ -31,12 +31,23 @@ export function intersectSphere(
3131
return intersectSpherePointerCapture(fromPosition, fromQuaternion, pointerCapture)
3232
}
3333
let intersection: ThreeIntersection | undefined
34+
let pointerEventsOrder: number | undefined
3435
collisionSphere.center.copy(fromPosition)
3536
collisionSphere.radius = radius
3637

37-
traversePointerEventTargets(scene, pointerId, pointerType, pointerState, (object) => {
38+
traversePointerEventTargets(scene, pointerId, pointerType, pointerState, (object, objectPointerEventsOrder) => {
3839
intersectSphereWithObject(collisionSphere, object, intersectsHelper)
39-
intersection = getDominantIntersection(intersection, intersectsHelper, options)
40+
const index = getDominantIntersectionIndex(
41+
intersection,
42+
pointerEventsOrder,
43+
intersectsHelper,
44+
objectPointerEventsOrder,
45+
options,
46+
)
47+
if (index != null) {
48+
intersection = intersectsHelper[index]
49+
pointerEventsOrder = objectPointerEventsOrder
50+
}
4051
intersectsHelper.length = 0
4152
})
4253

packages/pointer-events/src/intersections/utils.ts

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -56,26 +56,28 @@ export function traversePointerEventTargets(
5656
pointerId: number,
5757
pointerType: string,
5858
pointerState: unknown,
59-
callback: (object: Object3D) => void,
59+
callback: (object: Object3D, pointerEventsOrder: number | undefined) => void,
6060
parentHasListener: boolean = false,
6161
parentPointerEvents?: AllowedPointerEvents,
6262
parentPointerEventsType?: AllowedPointerEventsType,
63+
parentPointerEventsOrder?: number,
6364
): void {
6465
const hasListener = parentHasListener || hasObjectListeners(object)
65-
const allowedPointerEvents = object.pointerEvents ?? parentPointerEvents ?? 'listener'
66-
const allowedPointerEventsType = object.pointerEventsType ?? parentPointerEventsType ?? 'all'
66+
const pointerEvents = object.pointerEvents ?? parentPointerEvents
67+
const pointerEventsType = object.pointerEventsType ?? parentPointerEventsType
68+
const pointerEventsOrder = object.pointerEventsOrder ?? parentPointerEventsOrder
6769

6870
const isAllowed = isPointerEventsAllowed(
6971
hasListener,
70-
allowedPointerEvents,
71-
allowedPointerEventsType,
72+
pointerEvents ?? 'listener',
73+
pointerEventsType ?? 'all',
7274
pointerId,
7375
pointerType,
7476
pointerState,
7577
)
7678

7779
if (isAllowed) {
78-
callback(object)
80+
callback(object, pointerEventsOrder)
7981
}
8082

8183
const length = object.children.length
@@ -87,39 +89,50 @@ export function traversePointerEventTargets(
8789
pointerState,
8890
callback,
8991
hasListener,
90-
allowedPointerEvents,
91-
allowedPointerEventsType,
92+
pointerEvents,
93+
pointerEventsType,
94+
pointerEventsOrder,
9295
)
9396
}
9497
}
9598

96-
export function getDominantIntersection<T extends ThreeIntersection>(
97-
target: T | undefined,
98-
current: Array<T>,
99+
/**
100+
* @returns undefined if `i1` is the dominant intersection
101+
*/
102+
export function getDominantIntersectionIndex<T extends ThreeIntersection>(
103+
i1: T | undefined,
104+
pointerEventsOrder1: number | undefined,
105+
i2: Array<T>,
106+
pointerEventsOrder2: number | undefined,
99107
{ customFilter, customSort: compare = defaultSort }: IntersectionOptions = {},
100-
): T | undefined {
101-
const length = current.length
108+
): number | undefined {
109+
let index = undefined
110+
const length = i2.length
102111
for (let i = 0; i < length; i++) {
103-
const intersection = current[i]
112+
const intersection = i2[i]
104113
if (!(customFilter?.(intersection) ?? true)) {
105114
continue
106115
}
107-
if (target == null || compare(target, intersection) > 0) {
108-
target = intersection
116+
if (i1 == null || compare(i1, pointerEventsOrder1, intersection, pointerEventsOrder2) > 0) {
117+
i1 = intersection
118+
index = i
109119
}
110120
}
111-
return target
121+
return index
112122
}
113123

114124
/**
115125
* @returns a negative number if i1 should be sorted before i2
116126
*/
117-
function defaultSort(i1: ThreeIntersection, i2: ThreeIntersection): number {
118-
const { pointerEventsOrder: o1 = 0 } = i1.object
119-
const { pointerEventsOrder: o2 = 0 } = i2.object
120-
if (o1 != o2) {
127+
function defaultSort(
128+
i1: ThreeIntersection,
129+
pointerEventsOrder1: number = 0,
130+
i2: ThreeIntersection,
131+
pointerEventsOrder2: number = 0,
132+
): number {
133+
if (pointerEventsOrder1 != pointerEventsOrder2) {
121134
//inverted order because order is sorted highest first
122-
return o2 - o1
135+
return pointerEventsOrder2 - pointerEventsOrder1
123136
}
124137
//i1 - i2 because negative values mean the sorting i1 before i2 is correct
125138
return i1.distance - i2.distance

packages/pointer-events/src/pointer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export type AllowedPointerEventsType =
1414
| ((poinerId: number, pointerType: string, pointerState: unknown) => boolean)
1515
| { allow: string | Array<string> }
1616
| { deny: string | Array<string> }
17+
1718
declare module 'three' {
1819
interface Object3D {
1920
_listeners?: Record<string, Array<(event: unknown) => void> | undefined>

packages/pointer-events/src/pointer/ray.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { generateUniquePointerId } from './index.js'
66
export type RayPointerOptions = {
77
/**
88
* @default 0
9+
* distance to intersection in local space
910
*/
1011
minDistance?: number
1112
/**
@@ -20,6 +21,7 @@ export type RayPointerOptions = {
2021
IntersectionOptions
2122

2223
const NegZAxis = new Vector3(0, 0, -1)
24+
const vectorHelper = new Vector3()
2325

2426
export const defaultRayPointerOptions = {
2527
direction: NegZAxis,
@@ -77,7 +79,8 @@ export function createRayPointer(
7779
if (intersection == null) {
7880
return undefined
7981
}
80-
if (intersection.distance < (options.minDistance ?? defaultRayPointerOptions.minDistance)) {
82+
const localDistance = intersection.distance * spaceObject.getWorldScale(vectorHelper).x
83+
if (localDistance < (options.minDistance ?? defaultRayPointerOptions.minDistance)) {
8184
return undefined
8285
}
8386
return intersection

0 commit comments

Comments
 (0)