我使用React Three Fiber
和drei
。我想知道如何限制MapControls
的最大平移距离。网上有一些关于如何用普通three.js
存档它的解决方案,但没有使用drei
和r3f
的MapControls
或OrbitControls
。
我试过了,但是一旦我达到极限,相机就会奇怪地出现故障。
function Controls() {
const { camera } = useThree();
useFrame(() => {
camera.position.x = THREE.MathUtils.clamp(camera.position.x, -90, 90)
camera.position.y = THREE.MathUtils.clamp(camera.position.y, -90, 90)
})
return (
<MapControls />
)
}
谢谢你的帮助
亚历山大
基于这个答案,一个解决方案是创建一个自定义的'Controls'
组件,如下所示:
const Controls = () => {
const { camera } = useThree()
const controlsRef = useRef()
useEffect(() => {
controlsRef.current.addEventListener('change', function () {
if (this.target.y < -10) {
this.target.y = -10
camera.position.y = -10
} else if (this.target.y > 10) {
this.target.y = 10
camera.position.y = 10
}
})
}, [])
return (
<MapControls ref={controlsRef} enableZoom={false} enableRotate={false} />
)
}
可以用作Canvas
组件的子组件。
<Canvas>
<Controls />
</Canvas>
我的解决方案是基于上面的答案
const { camera, size } = useThree();
const limitPanningDistance = useCallback(
(e?: THREE.Event) => {
// 704.5 102
// 1056.75 320
// Returns the drag container width and height
const [w, h] = [1920, 1080]
const pan = (w * camera.zoom - size.width) / 2 / camera.zoom;
const vertical = (h * camera.zoom - size.height) / 2 / camera.zoom;
// console.log('pan vertical', pan, vertical);
const maxX = pan;
const minX = -pan;
const maxY = vertical;
const minY = -vertical;
const x = e?.target.target.x;
const y = e?.target.target.y;
if (x < minX || x > maxX) {
e?.target.target.setX(x < minX ? minX : maxX);
camera.position.setX(x < minX ? minX : maxX);
}
if (y < minY || y > maxY) {
e?.target.target.setY(y < minY ? minY : maxY);
camera.position.setY(y < minY ? minY : maxY);
}
},
[camera.zoom, size]
);
<MapControls
enableRotate={false}
minZoom={1}
maxZoom={2}
onChange={(e) => {
// console.log(e?.target);
limitPanningDistance(e);
}}
makeDefault
/>
这是我使用MapControls
的onChange
属性的解决方案。
控制组件:
import React, { useRef } from 'react'
import { MapControls } from '@react-three/drei'
import { useThree } from '@react-three/fiber'
const Controls = () => {
const { camera } = useThree()
const cameraLastPosition = useRef({
x: camera.position.x,
y: camera.position.y,
})
return (
<MapControls
onChange={(e) => {
const maxX = 90
const minX = -90
const maxY = 90
const minY = -90
const x = e?.target.target.x
const y = e?.target.target.y
if (x < minX || x > maxX) {
e?.target.target.setX(x < minX ? minX : maxX)
camera.position.setX(cameraLastPosition.current.x)
}
if (y < minY || y > maxY) {
e?.target.target.setY(y < minY ? minY : maxY)
camera.position.setY(cameraLastPosition.current.y)
}
cameraLastPosition.current.x = camera.position.x
cameraLastPosition.current.y = camera.position.y
}}
/>
)
}
export default Controls
导入该组件并在Canvas
:
<Canvas>
<Controls />
</Canvas>