Add dark mode, range slider, reset view
This commit is contained in:
parent
7d197d73ef
commit
2388ce2883
6 changed files with 181 additions and 34 deletions
|
@ -16,6 +16,7 @@ import {
|
||||||
} from "../providers/scene-view-provider";
|
} from "../providers/scene-view-provider";
|
||||||
import { Mesh, MeshStandardMaterial } from "three";
|
import { Mesh, MeshStandardMaterial } from "three";
|
||||||
import { CustomEvent } from "../three/SceneView";
|
import { CustomEvent } from "../three/SceneView";
|
||||||
|
import { RangeSlider } from "./RangeSlider";
|
||||||
|
|
||||||
function Toggle({
|
function Toggle({
|
||||||
title,
|
title,
|
||||||
|
@ -35,8 +36,8 @@ function Toggle({
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
defaultChecked={defaultChecked ? true : false}
|
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>
|
<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-gray-300 rounded-full peer dark:bg-gray-400 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-400 peer-checked:bg-blue-600 dark:peer-checked:bg-blue-400"></div>
|
||||||
<span className="ms-3 text-xs xl:text-sm font-medium text-gray-900 dark:text-gray-300">
|
<span className="ms-3 text-xs xl:text-sm font-medium text-gray-500 dark:text-gray-400">
|
||||||
{title}
|
{title}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
|
@ -77,8 +78,8 @@ const Accordion = forwardRef<AccordionRef, AccordionProps>(
|
||||||
|
|
||||||
const className =
|
const className =
|
||||||
position === Position.Center
|
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 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 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 dark:border-gray-400 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 gap-3 hover:cursor-pointer";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -118,7 +119,7 @@ const Accordion = forwardRef<AccordionRef, AccordionProps>(
|
||||||
aria-labelledby="accordion-collapse-heading-1"
|
aria-labelledby="accordion-collapse-heading-1"
|
||||||
className={expanded ? "" : "hidden"}
|
className={expanded ? "" : "hidden"}
|
||||||
>
|
>
|
||||||
<div className="p-5 border border-gray-200 dark:border-gray-700 dark:bg-gray-900">
|
<div className="p-5 border border-gray-200 dark:border-gray-400 dark:bg-gray-700">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -132,6 +133,8 @@ export function Form() {
|
||||||
const svgContainerRef = useRef<HTMLDivElement>(null);
|
const svgContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const accordionRef1 = useRef<AccordionRef>(null);
|
const accordionRef1 = useRef<AccordionRef>(null);
|
||||||
const accordionRef0 = useRef<AccordionRef>(null);
|
const accordionRef0 = useRef<AccordionRef>(null);
|
||||||
|
|
||||||
|
const [emptyProfile, setEmptyProfile] = useState<boolean>(false);
|
||||||
const { sceneView } = useContext(SceneViewContext) as SceneViewContextType;
|
const { sceneView } = useContext(SceneViewContext) as SceneViewContextType;
|
||||||
|
|
||||||
function handleChange() {
|
function handleChange() {
|
||||||
|
@ -176,17 +179,26 @@ export function Form() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSVGCreated(e: CustomEvent) {
|
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) {
|
while (svgContainerRef.current.children.length > 0) {
|
||||||
const c = svgContainerRef.current.children[0];
|
const c = svgContainerRef.current.children[0];
|
||||||
svgContainerRef.current.removeChild(c);
|
svgContainerRef.current.removeChild(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.detail && e.detail.element) {
|
||||||
|
setEmptyProfile(false);
|
||||||
svgContainerRef.current.appendChild(e.detail.element);
|
svgContainerRef.current.appendChild(e.detail.element);
|
||||||
if (accordionRef0.current) {
|
|
||||||
accordionRef0.current.open(false);
|
accordionRef0.current.open(false);
|
||||||
}
|
accordionRef1.current.open(true);
|
||||||
if (accordionRef1.current) {
|
} else {
|
||||||
|
setEmptyProfile(true);
|
||||||
|
accordionRef0.current.open(false);
|
||||||
accordionRef1.current.open(true);
|
accordionRef1.current.open(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,17 +210,17 @@ export function Form() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full max-h-full flex flex-col gap-2">
|
<div className="w-full max-h-full flex flex-col gap-2 dark:bg-gray-700">
|
||||||
<div className="w-full h-full flex flex-col gap-3 p-2 border border-gray-200 rounded shadow">
|
<div className="w-full h-full flex flex-col gap-3 p-2 border border-gray-200 dark:border-gray-400 rounded shadow">
|
||||||
<div className="w-full flex justify-end">
|
<div className="w-full flex justify-end">
|
||||||
<button
|
<button
|
||||||
onClick={handleExport}
|
onClick={handleExport}
|
||||||
className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800 hover:cursor-pointer"
|
className="text-white bg-red-400 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 dark:bg-red-600 dark:hover:bg-red-700 focus:outline-none dark:focus:ring-red-800 hover:cursor-pointer"
|
||||||
>
|
>
|
||||||
Export as .obj
|
Export as .obj
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="border border-gray-200 rounded grid grid-cols-2 gap-y-2 p-2">
|
<div className="border border-gray-200 dark:border-gray-400 rounded grid grid-cols-2 gap-y-2 p-2">
|
||||||
<Toggle title="Slicing Box" onChange={handleChange} />
|
<Toggle title="Slicing Box" onChange={handleChange} />
|
||||||
<Toggle title="Virtual Profile" onChange={handleDrilling} />
|
<Toggle title="Virtual Profile" onChange={handleDrilling} />
|
||||||
<Toggle title="Coordinate Grid" onChange={handleChangeCG} />
|
<Toggle title="Coordinate Grid" onChange={handleChangeCG} />
|
||||||
|
@ -219,6 +231,10 @@ export function Form() {
|
||||||
defaultChecked
|
defaultChecked
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="px-2 pt-2 border border-gray-200 dark:border-gray-400 rounded">
|
||||||
|
<RangeSlider></RangeSlider>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="overflow-y-auto">
|
<div className="overflow-y-auto">
|
||||||
<Accordion
|
<Accordion
|
||||||
title="Layers"
|
title="Layers"
|
||||||
|
@ -238,7 +254,7 @@ export function Form() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={key}
|
key={key}
|
||||||
className="flex items-center justify-start gap-2.5 border-b border-gray-200 py-1"
|
className="flex items-center justify-start gap-2.5 border-b border-gray-200 dark:border-gray-400 py-1 dark:text-gray-400"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="inline-block w-5 h-5 flex-none rounded"
|
className="inline-block w-5 h-5 flex-none rounded"
|
||||||
|
@ -255,7 +271,7 @@ export function Form() {
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
htmlFor={key}
|
htmlFor={key}
|
||||||
className="antialiased font-light text-gray-700"
|
className="font-light text-gray-500 dark:text-gray-400"
|
||||||
>
|
>
|
||||||
{child.name}
|
{child.name}
|
||||||
</label>
|
</label>
|
||||||
|
@ -271,7 +287,17 @@ export function Form() {
|
||||||
open={false}
|
open={false}
|
||||||
ref={accordionRef1}
|
ref={accordionRef1}
|
||||||
>
|
>
|
||||||
<div ref={svgContainerRef}> </div>
|
{emptyProfile ? (
|
||||||
|
<div className="font-light text-gray-500 dark:text-gray-400 text-sm">
|
||||||
|
Virtual profile does not intersect the model.
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<div ref={svgContainerRef} className="dark:bg-gray-400">
|
||||||
|
<div className="font-light text-gray-500 dark:text-gray-400 dark:bg-gray-700 text-sm">
|
||||||
|
Please enable the Virtual Profile toggle and select a profile
|
||||||
|
position!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
67
app/components/RangeSlider.tsx
Normal file
67
app/components/RangeSlider.tsx
Normal file
|
@ -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<number>(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 (
|
||||||
|
<div className="relative mb-8">
|
||||||
|
<label
|
||||||
|
htmlFor="steps-range"
|
||||||
|
className="block mb-2 text-sm font-medium text-gray-500 dark:text-gray-400"
|
||||||
|
>
|
||||||
|
Z-Scaling
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="steps-range"
|
||||||
|
type="range"
|
||||||
|
min="1"
|
||||||
|
max="5"
|
||||||
|
value={scale}
|
||||||
|
step="0.5"
|
||||||
|
className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-400"
|
||||||
|
onChange={handleChange}
|
||||||
|
></input>
|
||||||
|
<span className="text-sm text-gray-500 dark:text-gray-400 absolute start-0 -bottom-6">
|
||||||
|
1
|
||||||
|
</span>
|
||||||
|
<span className="text-sm text-gray-500 dark:text-gray-400 absolute start-1/8 -translate-x-1/8 -bottom-6">
|
||||||
|
1.5
|
||||||
|
</span>
|
||||||
|
<span className="text-sm text-gray-500 dark:text-gray-400 absolute start-2/8 -translate-x-2/8 -bottom-6">
|
||||||
|
2
|
||||||
|
</span>
|
||||||
|
<span className="text-sm text-gray-500 dark:text-gray-400 absolute start-3/8 -translate-x-3/8 -bottom-6">
|
||||||
|
2.5
|
||||||
|
</span>
|
||||||
|
<span className="text-sm text-gray-500 dark:text-gray-400 absolute start-4/8 -translate-x-4/8 -bottom-6">
|
||||||
|
3
|
||||||
|
</span>
|
||||||
|
<span className="text-sm text-gray-500 dark:text-gray-400 absolute start-5/8 -translate-x-5/8 -bottom-6">
|
||||||
|
3.5
|
||||||
|
</span>
|
||||||
|
<span className="text-sm text-gray-500 dark:text-gray-400 absolute start-6/8 -translate-x-6/8 -bottom-6">
|
||||||
|
4
|
||||||
|
</span>
|
||||||
|
<span className="text-sm text-gray-500 dark:text-gray-400 absolute start-7/8 -translate-x-7/8 -bottom-6">
|
||||||
|
4.5
|
||||||
|
</span>
|
||||||
|
<span className="text-sm text-gray-500 dark:text-gray-400 absolute end-0 -bottom-6">
|
||||||
|
5
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
23
app/components/ResetView.tsx
Normal file
23
app/components/ResetView.tsx
Normal file
|
@ -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 (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleClick}
|
||||||
|
className="flex items-center justify-center w-10 h-10 text-white text-3xl bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg p-2 pb-3.5 dark:bg-blue-400 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800 hover:cursor-pointer"
|
||||||
|
>
|
||||||
|
<span className="inline-block">⌂</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
20
app/page.tsx
20
app/page.tsx
|
@ -4,34 +4,40 @@ import { Map } from "./components/Map";
|
||||||
import { Form } from "./components/Form";
|
import { Form } from "./components/Form";
|
||||||
import { SceneViewProvider } from "./providers/scene-view-provider";
|
import { SceneViewProvider } from "./providers/scene-view-provider";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { ResetView } from "./components/ResetView";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const [isFormOpen, setIsFormOpen] = useState<boolean>(false);
|
const [isFormOpen, setIsFormOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-screen h-screen">
|
<div className="w-screen h-screen">
|
||||||
<main className="h-screen flex flex-col">
|
<main className="h-screen">
|
||||||
<SceneViewProvider>
|
<SceneViewProvider>
|
||||||
<div className="sm:hidden p-4 bg-white shadow-md flex justify-between items-center">
|
<div className="sm:hidden p-4 bg-white dark:bg-gray-700 shadow-md flex justify-between items-center">
|
||||||
<span className="text-lg font-semibold">3D-Viewer</span>
|
<span className="text-lg font-semibold text-gray-700 dark:text-gray-400">
|
||||||
|
3D-Viewer
|
||||||
|
</span>
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsFormOpen(true)}
|
onClick={() => setIsFormOpen(true)}
|
||||||
className="text-3xl hover:cursor-pointer"
|
className="text-3xl hover:cursor-pointer text-gray-700 dark:text-gray-400"
|
||||||
>
|
>
|
||||||
☰
|
☰
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 flex min-h-0">
|
<div className="flex-1 flex min-h-0 h-full">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
|
<div className="hidden sm:block absolute top-2 left-2">
|
||||||
|
<ResetView></ResetView>
|
||||||
|
</div>
|
||||||
<Map></Map>
|
<Map></Map>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`fixed inset-0 bg-white p-2 flex flex-col items-center border-l border-gray-200 shadow-lg transition-transform duration-300 sm:static w-full sm:w-[350px] xl:w-[480px] sm:translate-x-0 ${
|
className={`fixed sm:static inset-0 flex flex-col gap-1 items-center bg-white dark:bg-gray-700 p-2 sm:border-l border-gray-200 shadow-lg transition-transform duration-300 w-full sm:w-[350px] xl:w-[480px] ${
|
||||||
isFormOpen ? "translate-x-0" : "translate-x-full"
|
isFormOpen ? "translate-x-0" : "translate-x-full"
|
||||||
} sm:translate-x-0`}
|
} sm:translate-x-0`}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
className="self-end text-gray-500 sm:hidden text-3xl hover:cursor-pointer mb-1 mr-1"
|
className="sm:hidden self-end text-gray-500 text-3xl hover:cursor-pointer p-1"
|
||||||
onClick={() => setIsFormOpen(false)}
|
onClick={() => setIsFormOpen(false)}
|
||||||
>
|
>
|
||||||
✖
|
✖
|
||||||
|
|
|
@ -13,14 +13,18 @@ import {
|
||||||
} from "three";
|
} from "three";
|
||||||
import { buildMeshes } from "./utils/build-meshes";
|
import { buildMeshes } from "./utils/build-meshes";
|
||||||
import { Extent, buildScene } from "./utils/build-scene";
|
import { Extent, buildScene } from "./utils/build-scene";
|
||||||
import { getMetadata, transform } from "./utils/utils";
|
import { getCenter3D, getMetadata, transform } from "./utils/utils";
|
||||||
import { MAPTILER_API_KEY, MODEL_ID, SERVICE_URL } from "./config";
|
import { MAPTILER_API_KEY, MODEL_ID, SERVICE_URL } from "./config";
|
||||||
import {
|
import {
|
||||||
Orientation,
|
Orientation,
|
||||||
buildClippingplanes,
|
buildClippingplanes,
|
||||||
} from "./utils/build-clipping-planes";
|
} from "./utils/build-clipping-planes";
|
||||||
import { buildCoordinateGrid } from "./utils/build-coordinate-grid";
|
import { buildCoordinateGrid } from "./utils/build-coordinate-grid";
|
||||||
import { DragControls, OBJExporter } from "three/examples/jsm/Addons.js";
|
import {
|
||||||
|
DragControls,
|
||||||
|
OBJExporter,
|
||||||
|
OrbitControls,
|
||||||
|
} from "three/examples/jsm/Addons.js";
|
||||||
import { MapTilerProvider, MapView, OpenStreetMapsProvider } from "geo-three";
|
import { MapTilerProvider, MapView, OpenStreetMapsProvider } from "geo-three";
|
||||||
import { CustomMapHeightNodeShader } from "./CustomMapHeightNodeShader";
|
import { CustomMapHeightNodeShader } from "./CustomMapHeightNodeShader";
|
||||||
import { Data, createSVG } from "./utils/create-borehole-svg";
|
import { Data, createSVG } from "./utils/create-borehole-svg";
|
||||||
|
@ -42,32 +46,43 @@ export class SceneView extends EventTarget {
|
||||||
private _isDragging: boolean = false;
|
private _isDragging: boolean = false;
|
||||||
private static _DRAG_THRESHOLD = 5;
|
private static _DRAG_THRESHOLD = 5;
|
||||||
private _callback: EventListenerOrEventListenerObject | null = null;
|
private _callback: EventListenerOrEventListenerObject | null = null;
|
||||||
|
private _orbitControls: OrbitControls;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
model: Group,
|
model: Group,
|
||||||
controls: DragControls,
|
dragControls: DragControls,
|
||||||
camera: Camera,
|
camera: Camera,
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
extent: Extent
|
extent: Extent,
|
||||||
|
orbitControls: OrbitControls
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this._scene = scene;
|
this._scene = scene;
|
||||||
this._dragControls = controls;
|
this._dragControls = dragControls;
|
||||||
this._model = model;
|
this._model = model;
|
||||||
this._camera = camera;
|
this._camera = camera;
|
||||||
this._container = container;
|
this._container = container;
|
||||||
this._raycaster = new Raycaster();
|
this._raycaster = new Raycaster();
|
||||||
this._extent = extent;
|
this._extent = extent;
|
||||||
|
this._orbitControls = orbitControls;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async create(container: HTMLElement, modelId: string) {
|
static async create(container: HTMLElement, modelId: string) {
|
||||||
const { scene, model, dragControls, camera, extent } = await init(
|
const { scene, model, dragControls, camera, extent, controls } = await init(
|
||||||
container,
|
container,
|
||||||
modelId
|
modelId
|
||||||
);
|
);
|
||||||
|
|
||||||
return new SceneView(scene, model, dragControls, camera, container, extent);
|
return new SceneView(
|
||||||
|
scene,
|
||||||
|
model,
|
||||||
|
dragControls,
|
||||||
|
camera,
|
||||||
|
container,
|
||||||
|
extent,
|
||||||
|
controls
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get scene() {
|
get scene() {
|
||||||
|
@ -218,6 +233,11 @@ export class SceneView extends EventTarget {
|
||||||
detail: { element },
|
detail: { element },
|
||||||
});
|
});
|
||||||
this.dispatchEvent(event);
|
this.dispatchEvent(event);
|
||||||
|
} else {
|
||||||
|
const event = new CustomEvent("svg-created", {
|
||||||
|
detail: null,
|
||||||
|
});
|
||||||
|
this.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,6 +321,11 @@ export class SceneView extends EventTarget {
|
||||||
link.click();
|
link.click();
|
||||||
document.body.removeChild(link);
|
document.body.removeChild(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset view to initial extent
|
||||||
|
public resetView() {
|
||||||
|
this._orbitControls.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function init(container: HTMLElement, modelId = MODEL_ID) {
|
async function init(container: HTMLElement, modelId = MODEL_ID) {
|
||||||
|
@ -370,5 +395,5 @@ async function init(container: HTMLElement, modelId = MODEL_ID) {
|
||||||
map.name = "topography";
|
map.name = "topography";
|
||||||
scene.add(map);
|
scene.add(map);
|
||||||
|
|
||||||
return { scene, model, dragControls, camera, extent };
|
return { scene, model, dragControls, camera, extent, controls };
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,9 +64,9 @@ export function buildScene(container: HTMLElement, extent: Extent) {
|
||||||
controls.maxDistance = maxSize * 3;
|
controls.maxDistance = maxSize * 3;
|
||||||
controls.minDistance = maxSize / 5;
|
controls.minDistance = maxSize / 5;
|
||||||
controls.update();
|
controls.update();
|
||||||
|
controls.saveState();
|
||||||
|
|
||||||
// Scene
|
// Set wireframe to false on initial load
|
||||||
// set wireframe to false on initial load
|
|
||||||
scene = new Scene();
|
scene = new Scene();
|
||||||
scene.userData.wireframe = false;
|
scene.userData.wireframe = false;
|
||||||
|
|
||||||
|
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue