feat: enhance camera controls and switch view functionality with 3D toggle integration

This commit is contained in:
2025-09-11 10:14:17 +05:30
parent 767e301776
commit 0f478e8e1a
2 changed files with 57 additions and 29 deletions

View File

@@ -1,11 +1,14 @@
import { Vector3 } from "three";
import { useEffect } from "react"; import { useEffect } from "react";
import { useThree } from "@react-three/fiber"; import { useThree } from "@react-three/fiber";
import * as THREE from "three";
import type { CameraControls } from "@react-three/drei"; import type { CameraControls } from "@react-three/drei";
import { useThreeDStore } from "../../../../store/ui/useModuleStore";
import * as CONSTANTS from "../../../../types/world/worldConstants";
const CameraShortcutsControls = () => { const CameraShortcutsControls = () => {
const { camera, controls } = useThree(); const { camera, controls } = useThree();
const { toggleThreeD, setToggleThreeD } = useThreeDStore();
const isTextInput = (element: Element | null): boolean => const isTextInput = (element: Element | null): boolean =>
element instanceof HTMLInputElement || element instanceof HTMLInputElement ||
element instanceof HTMLTextAreaElement || element instanceof HTMLTextAreaElement ||
@@ -18,54 +21,77 @@ const CameraShortcutsControls = () => {
const cc = controls as CameraControls; const cc = controls as CameraControls;
// get current target // get current target
const target = new THREE.Vector3(); const target = new Vector3();
cc.getTarget(target); cc.getTarget(target);
const distance = camera.position.distanceTo(target); const distance = camera.position.distanceTo(target);
let pos: THREE.Vector3 | null = null; let pos: Vector3 | null = null;
const dir = new THREE.Vector3().subVectors(camera.position, target).normalize(); const dir = new Vector3().subVectors(camera.position, target).normalize();
if (isTextInput(document.activeElement)) return; if (isTextInput(document.activeElement)) return;
switch (e.key) { switch (e.code) {
case "1": // Front case "Numpad1": // Front
pos = new THREE.Vector3(0, 0, distance).add(target); pos = new Vector3(0, 0, distance).add(target);
LookAt(pos);
break; break;
case "3": // Right case "Numpad3": // Right
pos = new THREE.Vector3(distance, 0, 0).add(target); pos = new Vector3(distance, 0, 0).add(target);
LookAt(pos);
break; break;
case "7": // Top case "Numpad7": // Top
pos = new THREE.Vector3(0, distance, 0).add(target); pos = new Vector3(0, distance, 0).add(target);
LookAt(pos);
break; break;
case "9": { case "Numpad9": {
// Opposite view logic // Opposite view logic
if (Math.abs(dir.z) > Math.abs(dir.x) && Math.abs(dir.z) > Math.abs(dir.y)) { if (Math.abs(dir.z) > Math.abs(dir.x) && Math.abs(dir.z) > Math.abs(dir.y)) {
// Currently looking Front/Back → flip Z pos = new Vector3(0, 0, -Math.sign(dir.z) * distance).add(target);
pos = new THREE.Vector3(0, 0, -Math.sign(dir.z) * distance).add(target); LookAt(pos);
} else if (Math.abs(dir.x) > Math.abs(dir.z) && Math.abs(dir.x) > Math.abs(dir.y)) { } else if (
// Currently looking Right/Left → flip X Math.abs(dir.x) > Math.abs(dir.z) &&
pos = new THREE.Vector3(-Math.sign(dir.x) * distance, 0, 0).add(target); Math.abs(dir.x) > Math.abs(dir.y)
) {
pos = new Vector3(-Math.sign(dir.x) * distance, 0, 0).add(target);
LookAt(pos);
} else { } else {
// Currently looking Top/Bottom → stay Top pos = new Vector3(0, distance, 0).add(target);
pos = new THREE.Vector3(0, distance, 0).add(target); LookAt(pos);
}
break;
}
case "Numpad5": {
// Only apply when on Top view
if (!toggleThreeD) {
console.log("cc: ", cc.camera);
setToggleThreeD(true);
(cc as any).mouseButtons.left = CONSTANTS.threeDimension.leftMouse;
(cc as any).mouseButtons.right = CONSTANTS.threeDimension.rightMouse;
} else {
console.log("cc: ", cc.camera);
cc.setLookAt(0, distance, 0, target.x, target.y, target.z, false).then(
() => {
setToggleThreeD(false);
(cc as any).mouseButtons.left = CONSTANTS.twoDimension.leftMouse;
(cc as any).mouseButtons.right = CONSTANTS.twoDimension.rightMouse;
}
);
} }
break; break;
} }
} }
if (pos) { function LookAt(pos: Vector3) {
cc.setLookAt( console.log('hi lookat');
pos.x, pos.y, pos.z, // camera position cc.setLookAt(pos.x, pos.y, pos.z, target.x, target.y, target.z, true);
target.x, target.y, target.z, // keep same target
true // smooth transition
);
} }
}; };
window.addEventListener("keydown", handleKeyDown); window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown);
}, [controls, camera]); }, [controls, camera, toggleThreeD, setToggleThreeD]);
return null; return null;
}; };

View File

@@ -6,11 +6,13 @@ import { useParams } from "react-router-dom";
import * as CONSTANTS from "../../../types/world/worldConstants"; import * as CONSTANTS from "../../../types/world/worldConstants";
import { getCameraApi } from "../../../services/factoryBuilder/camera/getCameraApi"; import { getCameraApi } from "../../../services/factoryBuilder/camera/getCameraApi";
import { useToggleView } from "../../../store/builder/store"; import { useToggleView } from "../../../store/builder/store";
import { useThreeDStore } from "../../../store/ui/useModuleStore";
export default function SwitchView() { export default function SwitchView() {
const { toggleView } = useToggleView(); const { toggleView } = useToggleView();
const { controls } = useThree(); const { controls } = useThree();
const { projectId } = useParams(); const { projectId } = useParams();
const { toggleThreeD } = useThreeDStore();
useEffect(() => { useEffect(() => {
if (toggleView && controls) { if (toggleView && controls) {
@@ -39,11 +41,11 @@ export default function SwitchView() {
(controls as any).mouseButtons.right = CONSTANTS.threeDimension.rightMouse; (controls as any).mouseButtons.right = CONSTANTS.threeDimension.rightMouse;
} }
} }
}, [toggleView, controls]); }, [toggleView, controls, projectId]);
return ( return (
<> <>
{toggleView ? ( {(toggleView || !toggleThreeD) ? (
<OrthographicCamera <OrthographicCamera
makeDefault makeDefault
position={CONSTANTS.twoDimension.defaultPosition} position={CONSTANTS.twoDimension.defaultPosition}