184 lines
5.7 KiB
TypeScript
184 lines
5.7 KiB
TypeScript
"use client";
|
|
|
|
import { ReactNode, useContext, useRef, useState } from "react";
|
|
|
|
import {
|
|
SceneViewContext,
|
|
SceneViewContextType,
|
|
} from "../providers/scene-view-provider";
|
|
import { Mesh, MeshStandardMaterial } from "three";
|
|
import { scheduler } from "timers/promises";
|
|
|
|
function Toggle({
|
|
title,
|
|
onChange,
|
|
defaultChecked,
|
|
}: {
|
|
title: string;
|
|
onChange: () => void;
|
|
defaultChecked?: boolean;
|
|
}) {
|
|
return (
|
|
<label className="inline-flex items-center cursor-pointer">
|
|
<input
|
|
type="checkbox"
|
|
value=""
|
|
className="sr-only peer"
|
|
onChange={onChange}
|
|
defaultChecked={defaultChecked ? true : false}
|
|
/>
|
|
<div className="relative w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600 dark:peer-checked:bg-blue-600"></div>
|
|
<span className="ms-3 text-sm font-medium text-gray-900 dark:text-gray-300">
|
|
{title}
|
|
</span>
|
|
</label>
|
|
);
|
|
}
|
|
|
|
function Accordion({
|
|
children,
|
|
title,
|
|
}: {
|
|
children?: ReactNode;
|
|
title: string;
|
|
}) {
|
|
const [expanded, setExpanded] = useState<boolean>(true);
|
|
const accordionBodyRef = useRef<HTMLDivElement>(null);
|
|
function handleClick() {
|
|
if (!accordionBodyRef.current) return;
|
|
|
|
accordionBodyRef.current.classList.toggle("hidden");
|
|
setExpanded(!expanded);
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<h2 id="accordion-collapse-heading-1">
|
|
<button
|
|
type="button"
|
|
className="flex items-center justify-between w-full p-5 font-medium rtl:text-right text-gray-500 border border-b-0 border-gray-200 rounded-t-xl 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"
|
|
data-accordion-target="#accordion-collapse-body-1"
|
|
aria-expanded={expanded ? "true" : "false"}
|
|
aria-controls="accordion-collapse-body-1"
|
|
onClick={handleClick}
|
|
>
|
|
<span>{title}</span>
|
|
<svg
|
|
data-accordion-icon
|
|
className="w-3 h-3 rotate-180 shrink-0"
|
|
aria-hidden="true"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
fill="none"
|
|
viewBox="0 0 10 6"
|
|
>
|
|
<path
|
|
stroke="currentColor"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth="2"
|
|
d="M9 5 5 1 1 5"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
</h2>
|
|
<div
|
|
id="accordion-collapse-body-1"
|
|
ref={accordionBodyRef}
|
|
aria-labelledby="accordion-collapse-heading-1"
|
|
>
|
|
<div className="p-5 border border-gray-200 dark:border-gray-700 dark:bg-gray-900">
|
|
{children}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function Form() {
|
|
const { sceneView } = useContext(SceneViewContext) as SceneViewContextType;
|
|
|
|
function handleChange() {
|
|
if (!sceneView) return;
|
|
|
|
sceneView.toggleClippingBox();
|
|
}
|
|
|
|
function handleChangeCG() {
|
|
if (!sceneView) return;
|
|
|
|
sceneView.toggleCoordinateGrid();
|
|
}
|
|
|
|
function handleChangeWireframe() {
|
|
if (!sceneView) return;
|
|
|
|
sceneView.toggleWireFrame();
|
|
}
|
|
|
|
function handleCheckboxChange(name: string) {
|
|
if (!sceneView) return;
|
|
|
|
sceneView.toggleLayerVisibility(name);
|
|
}
|
|
|
|
function handleChangeTopography() {
|
|
if (!sceneView) return;
|
|
|
|
sceneView.toggleTopography();
|
|
}
|
|
|
|
return (
|
|
<div className="w-full flex flex-col gap-2 overflow-y-auto">
|
|
<div className="w-full flex flex-col gap-3 p-4 border border-gray-200 rounded shadow">
|
|
<Toggle title="Slicing Box" onChange={handleChange} />
|
|
<Toggle title="Coordinate Grid" onChange={handleChangeCG} />
|
|
<Toggle title="Wireframe" onChange={handleChangeWireframe} />
|
|
<Toggle
|
|
title="Topography (OSM)"
|
|
onChange={handleChangeTopography}
|
|
defaultChecked
|
|
/>
|
|
<Accordion title="Layers">
|
|
{
|
|
<div className="flex flex-col gap-2">
|
|
{sceneView?.model.children.map((child) => {
|
|
const key = `toggle-visibility-${child.name}`;
|
|
const color = `#${(
|
|
(child as Mesh).material as MeshStandardMaterial
|
|
).color.getHexString()}`;
|
|
const visible = (child as Mesh).visible;
|
|
|
|
return (
|
|
<div
|
|
key={key}
|
|
className="flex items-center justify-start gap-2.5 border-b border-gray-200 py-1"
|
|
>
|
|
<span
|
|
className="inline-block w-5 h-5 flex-none rounded"
|
|
style={{
|
|
backgroundColor: color,
|
|
}}
|
|
></span>
|
|
<input
|
|
id={key}
|
|
type="checkbox"
|
|
onChange={() => handleCheckboxChange(child.name)}
|
|
className="hover:cursor-pointer"
|
|
defaultChecked={visible ? true : false}
|
|
/>
|
|
<label
|
|
htmlFor={key}
|
|
className="antialiased font-light text-gray-700"
|
|
>
|
|
{child.name}
|
|
</label>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
}
|
|
</Accordion>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|