mirror of
https://github.com/zhigang1992/react-three-fiber.git
synced 2026-04-29 12:55:25 +08:00
fix pointercapture/stoppropagation #596
This commit is contained in:
@@ -1,32 +1,67 @@
|
||||
import React, { useState, useCallback, useRef } from 'react'
|
||||
import { Canvas } from 'react-three-fiber'
|
||||
import * as THREE from 'three'
|
||||
import React, { Suspense } from 'react'
|
||||
import { Canvas, useLoader } from 'react-three-fiber'
|
||||
|
||||
function M() {
|
||||
const t = useLoader(
|
||||
THREE.TextureLoader,
|
||||
`https://raw.githubusercontent.com/flowers1225/threejs-earth/master/src/img/earth4.jpg`
|
||||
)
|
||||
function Ball() {
|
||||
const [pos, setPos] = useState(new THREE.Vector3())
|
||||
const isPressed = useRef(false)
|
||||
|
||||
const onPointerDown = useCallback((e) => {
|
||||
isPressed.current = true
|
||||
e.target.setPointerCapture(e.pointerId)
|
||||
}, [])
|
||||
|
||||
const onPointerUp = useCallback((e) => {
|
||||
isPressed.current = false
|
||||
e.target.releasePointerCapture(e.pointerId)
|
||||
}, [])
|
||||
|
||||
const onPointerMove = useCallback((e) => {
|
||||
if (isPressed.current) {
|
||||
setPos(e.unprojectedPoint.clone().setZ(0))
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<mesh position={[-1, 0, 0]}>
|
||||
<boxBufferGeometry attach="geometry" />
|
||||
<meshBasicMaterial attach="material" color="hotpink" />
|
||||
</mesh>
|
||||
<mesh position={[1, 0, 0]}>
|
||||
<boxBufferGeometry attach="geometry" />
|
||||
<meshBasicMaterial attach="material" map={t} />
|
||||
</mesh>
|
||||
</>
|
||||
<mesh position={pos} onPointerMove={onPointerMove} onPointerDown={onPointerDown} onPointerUp={onPointerUp}>
|
||||
<boxBufferGeometry attach="geometry" args={[10, 32, 32]} />
|
||||
<meshBasicMaterial attach="material" color={0x000000} />
|
||||
</mesh>
|
||||
)
|
||||
}
|
||||
|
||||
function Cube() {
|
||||
const onPointerOver = useCallback((e) => {
|
||||
e.stopPropagation()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<mesh onPointerOver={onPointerOver} position={new THREE.Vector3(0, 0, -20)}>
|
||||
<boxBufferGeometry attach="geometry" args={[800, 400, 40]} />
|
||||
<meshBasicMaterial attach="material" color={0xfcfc00} />
|
||||
</mesh>
|
||||
)
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Canvas colorManagement style={{ background: '#272730' }}>
|
||||
<Suspense fallback={null}>
|
||||
<M />
|
||||
</Suspense>
|
||||
</Canvas>
|
||||
<>
|
||||
<Canvas
|
||||
gl={{ alpha: false, antialias: false, logarithmicDepthBuffer: true }}
|
||||
camera={{ fov: 75, position: [0, 0, 70] }}
|
||||
orthographic
|
||||
onCreated={({ gl }) => {
|
||||
gl.setClearColor('white')
|
||||
gl.toneMapping = THREE.ACESFilmicToneMapping
|
||||
gl.outputEncoding = THREE.sRGBEncoding
|
||||
}}>
|
||||
<ambientLight intensity={1.1} />
|
||||
<pointLight position={[100, 100, 100]} intensity={2.2} />
|
||||
<pointLight position={[-100, -100, -100]} intensity={5} color="red" />
|
||||
|
||||
<Ball />
|
||||
<Cube />
|
||||
</Canvas>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -321,8 +321,9 @@ export const useCanvas = (props: UseCanvasProps): DomEventHandlers => {
|
||||
|
||||
// #16031: (https://github.com/mrdoob/three.js/issues/16031)
|
||||
// Allow custom userland intersect sort order
|
||||
if (raycaster && raycaster.filter && sharedState.current)
|
||||
if (raycaster && raycaster.filter && sharedState.current) {
|
||||
intersects = raycaster.filter(intersects, sharedState.current)
|
||||
}
|
||||
|
||||
for (let intersect of intersects) {
|
||||
let eventObject: THREE.Object3D | null = intersect.object
|
||||
@@ -382,9 +383,10 @@ export const useCanvas = (props: UseCanvasProps): DomEventHandlers => {
|
||||
state.current.captured = []
|
||||
}
|
||||
// Push hits to the array
|
||||
if (state.current.captured)
|
||||
if (state.current.captured) {
|
||||
state.current.captured.push(hit)
|
||||
// Call the original event now
|
||||
}
|
||||
// Call the original event now
|
||||
;(event.target as any).setPointerCapture(id)
|
||||
}
|
||||
|
||||
@@ -398,7 +400,14 @@ export const useCanvas = (props: UseCanvasProps): DomEventHandlers => {
|
||||
ray: defaultRaycaster.ray,
|
||||
camera: state.current.camera,
|
||||
// Hijack stopPropagation, which just sets a flag
|
||||
stopPropagation: () => (raycastEvent.stopped = localState.stopped = true),
|
||||
stopPropagation: () => {
|
||||
// https://github.com/react-spring/react-three-fiber/issues/596
|
||||
// Events are not allowed to stop propagation if the pointer has been captured
|
||||
const cap = state.current.captured
|
||||
if (!cap || cap.find((h) => h.eventObject.id === hit.eventObject.id)) {
|
||||
raycastEvent.stopped = localState.stopped = true
|
||||
}
|
||||
},
|
||||
// Pointer-capture needs the hit, on which the user may call stopPropagation()
|
||||
// This makes it harder to use the actual event, because then we loose the connection
|
||||
// to the actual hit, which would mean it's picking up all intersects ...
|
||||
@@ -411,7 +420,7 @@ export const useCanvas = (props: UseCanvasProps): DomEventHandlers => {
|
||||
// Event bubbling may me interrupted by stopPropagation, but that should only include
|
||||
// events that aren't capturing, since these are in the middle of a gesture and should not
|
||||
// be disturbed until they resolve.
|
||||
if (localState.stopped === true && localState.captured == false) {
|
||||
if (localState.stopped === true) {
|
||||
// Propagation is stopped, remove all other hover records
|
||||
// An event handler is only allowed to flush other handlers if it is hovered itself
|
||||
if (hovered.size && Array.from(hovered.values()).find((i) => i.object === hit.object)) {
|
||||
|
||||
Reference in New Issue
Block a user