diff --git a/app/components/Form.tsx b/app/components/Form.tsx index 7e34aa2..48e6f5d 100644 --- a/app/components/Form.tsx +++ b/app/components/Form.tsx @@ -16,6 +16,7 @@ import { } from "../providers/scene-view-provider"; import { Mesh, MeshStandardMaterial } from "three"; import { CustomEvent } from "../three/SceneView"; +import { RangeSlider } from "./RangeSlider"; function Toggle({ title, @@ -35,8 +36,8 @@ function Toggle({ onChange={onChange} defaultChecked={defaultChecked ? true : false} /> -
- +
+ {title} @@ -77,8 +78,8 @@ const Accordion = forwardRef( const className = position === Position.Center - ? "flex items-center justify-between w-full p-5 font-medium rtl:text-right text-gray-500 border border-b border-gray-200 focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-800 dark:border-gray-700 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 gap-3 hover:cursor-pointer" - : "flex items-center justify-between w-full p-5 font-medium rtl:text-right text-gray-500 border border-b border-gray-200 rounded-t focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-800 dark:border-gray-700 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 gap-3 hover:cursor-pointer"; + ? "flex items-center justify-between w-full p-5 font-medium rtl:text-right text-gray-500 border border-b border-gray-200 dark:border-gray-400 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 gap-3 hover:cursor-pointer" + : "flex items-center justify-between w-full p-5 font-medium rtl:text-right text-gray-500 border border-b border-gray-200 rounded-t dark:border-gray-400 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 gap-3 hover:cursor-pointer"; return (
@@ -118,7 +119,7 @@ const Accordion = forwardRef( aria-labelledby="accordion-collapse-heading-1" className={expanded ? "" : "hidden"} > -
+
{children}
@@ -132,6 +133,8 @@ export function Form() { const svgContainerRef = useRef(null); const accordionRef1 = useRef(null); const accordionRef0 = useRef(null); + + const [emptyProfile, setEmptyProfile] = useState(false); const { sceneView } = useContext(SceneViewContext) as SceneViewContextType; function handleChange() { @@ -176,17 +179,26 @@ export function Form() { } function handleSVGCreated(e: CustomEvent) { - if (!svgContainerRef.current || !e.detail || !e.detail.element) return; + if ( + !svgContainerRef.current || + !accordionRef0.current || + !accordionRef1.current + ) + return; while (svgContainerRef.current.children.length > 0) { const c = svgContainerRef.current.children[0]; svgContainerRef.current.removeChild(c); } - svgContainerRef.current.appendChild(e.detail.element); - if (accordionRef0.current) { + + if (e.detail && e.detail.element) { + setEmptyProfile(false); + svgContainerRef.current.appendChild(e.detail.element); + accordionRef0.current.open(false); + accordionRef1.current.open(true); + } else { + setEmptyProfile(true); accordionRef0.current.open(false); - } - if (accordionRef1.current) { accordionRef1.current.open(true); } } @@ -198,17 +210,17 @@ export function Form() { } return ( -
-
+
+
-
+
@@ -219,6 +231,10 @@ export function Form() { defaultChecked />
+
+ +
+
@@ -271,7 +287,17 @@ export function Form() { open={false} ref={accordionRef1} > -
+ {emptyProfile ? ( +
+ Virtual profile does not intersect the model. +
+ ) : null} +
+
+ Please enable the Virtual Profile toggle and select a profile + position! +
+
diff --git a/app/components/RangeSlider.tsx b/app/components/RangeSlider.tsx new file mode 100644 index 0000000..1981b90 --- /dev/null +++ b/app/components/RangeSlider.tsx @@ -0,0 +1,67 @@ +import { ChangeEvent, useContext, useState } from "react"; +import { + SceneViewContext, + SceneViewContextType, +} from "../providers/scene-view-provider"; + +export function RangeSlider() { + const { sceneView } = useContext(SceneViewContext) as SceneViewContextType; + const [scale, setScale] = useState(1); + + const handleChange = (e: ChangeEvent) => { + if (!sceneView) return; + const t = e.target as HTMLInputElement; + const z = parseFloat(t.value); + if (!isNaN(z)) { + setScale(z); + sceneView.scene.scale.set(1, 1, z); + } + }; + return ( +
+ + + + 1 + + + 1.5 + + + 2 + + + 2.5 + + + 3 + + + 3.5 + + + 4 + + + 4.5 + + + 5 + +
+ ); +} diff --git a/app/components/ResetView.tsx b/app/components/ResetView.tsx new file mode 100644 index 0000000..ca03149 --- /dev/null +++ b/app/components/ResetView.tsx @@ -0,0 +1,23 @@ +import { useContext } from "react"; +import { + SceneViewContext, + SceneViewContextType, +} from "../providers/scene-view-provider"; + +export function ResetView() { + const { sceneView } = useContext(SceneViewContext) as SceneViewContextType; + const handleClick = () => { + if (!sceneView) return; + + sceneView.resetView(); + }; + return ( + + ); +} diff --git a/app/page.tsx b/app/page.tsx index eebee00..a480a9c 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -4,34 +4,40 @@ import { Map } from "./components/Map"; import { Form } from "./components/Form"; import { SceneViewProvider } from "./providers/scene-view-provider"; import { useState } from "react"; +import { ResetView } from "./components/ResetView"; export default function Home() { const [isFormOpen, setIsFormOpen] = useState(false); return (
-
+
-
- 3D-Viewer +
+ + 3D-Viewer +
-
+
+
+ +