@tableslayer/ui 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -13
- package/src/lib/components/Avatar/Avatar.svelte +82 -0
- package/src/lib/components/Avatar/AvatarFileInput.svelte +85 -0
- package/src/lib/components/Avatar/AvatarPopover.svelte +34 -0
- package/src/lib/components/Avatar/index.ts +4 -0
- package/src/lib/components/Avatar/types.ts +24 -0
- package/src/lib/components/BrushSizeSlider/BrushSizeSlider.svelte +174 -0
- package/src/lib/components/BrushSizeSlider/index.ts +1 -0
- package/src/lib/components/Button/Button.svelte +182 -0
- package/src/lib/components/Button/ConfirmActionButton.svelte +98 -0
- package/src/lib/components/Button/IconButton.svelte +121 -0
- package/src/lib/components/Button/RadioButton.svelte +93 -0
- package/src/lib/components/Button/index.ts +5 -0
- package/src/lib/components/Button/types.ts +54 -0
- package/src/lib/components/CardFan/CardFan.svelte +165 -0
- package/src/lib/components/CardFan/index.ts +2 -0
- package/src/lib/components/CardFan/types.ts +6 -0
- package/src/lib/components/CodeBlock/Code.svelte +7 -0
- package/src/lib/components/CodeBlock/CodeBlock.svelte +102 -0
- package/src/lib/components/CodeBlock/index.ts +3 -0
- package/src/lib/components/CodeBlock/types.ts +10 -0
- package/src/lib/components/ColorMode/ColorMode.svelte +8 -0
- package/src/lib/components/ColorMode/index.ts +2 -0
- package/src/lib/components/ColorMode/types.ts +12 -0
- package/src/lib/components/ColorPicker/ColorPicker.svelte +838 -0
- package/src/lib/components/ColorPicker/ColorPickerSwatch.svelte +32 -0
- package/src/lib/components/ColorPicker/index.ts +3 -0
- package/src/lib/components/ColorPicker/types.ts +51 -0
- package/src/lib/components/ContextMenu/ContextMenu.svelte +86 -0
- package/src/lib/components/ContextMenu/index.ts +2 -0
- package/src/lib/components/ContextMenu/types.ts +15 -0
- package/src/lib/components/DrawingSliders/DrawingSliders.svelte +379 -0
- package/src/lib/components/DrawingSliders/index.ts +1 -0
- package/src/lib/components/Editor/Editor.svelte +825 -0
- package/src/lib/components/Editor/index.ts +1 -0
- package/src/lib/components/FogSliders/FogSliders.svelte +33 -0
- package/src/lib/components/FogSliders/index.ts +1 -0
- package/src/lib/components/Hr/Hr.svelte +15 -0
- package/src/lib/components/Hr/index.ts +1 -0
- package/src/lib/components/Icon/Icon.svelte +6 -0
- package/src/lib/components/Icon/index.ts +2 -0
- package/src/lib/components/Icon/types.ts +20 -0
- package/src/lib/components/Input/DualInputSlider.svelte +126 -0
- package/src/lib/components/Input/FileInput.svelte +176 -0
- package/src/lib/components/Input/FormControl.svelte +150 -0
- package/src/lib/components/Input/FormError.svelte +37 -0
- package/src/lib/components/Input/Input.svelte +56 -0
- package/src/lib/components/Input/InputCheckbox.svelte +99 -0
- package/src/lib/components/Input/InputSlider.svelte +86 -0
- package/src/lib/components/Input/Label.svelte +19 -0
- package/src/lib/components/Input/index.ts +9 -0
- package/src/lib/components/Input/types.ts +39 -0
- package/src/lib/components/Link/Link.svelte +41 -0
- package/src/lib/components/Link/LinkBox.svelte +20 -0
- package/src/lib/components/Link/LinkOverlay.svelte +23 -0
- package/src/lib/components/Link/index.ts +4 -0
- package/src/lib/components/Link/types.ts +17 -0
- package/src/lib/components/Loading/Loader.svelte +60 -0
- package/src/lib/components/Loading/Skeleton.svelte +9 -0
- package/src/lib/components/Loading/index.ts +2 -0
- package/src/lib/components/Logo/Logo.svelte +16 -0
- package/src/lib/components/Logo/index.ts +1 -0
- package/src/lib/components/MarkerTooltip/MarkerTooltip.svelte +435 -0
- package/src/lib/components/MarkerTooltip/index.ts +1 -0
- package/src/lib/components/Menu/SelectorMenu.svelte +280 -0
- package/src/lib/components/Menu/index.ts +2 -0
- package/src/lib/components/Menu/types.ts +17 -0
- package/src/lib/components/MyCounterButton.svelte +11 -0
- package/src/lib/components/Panel/index.ts +2 -0
- package/src/lib/components/Panel/panel.svelte +18 -0
- package/src/lib/components/Panel/types.ts +8 -0
- package/src/lib/components/PersistButton/PersistButton.svelte +100 -0
- package/src/lib/components/PersistButton/index.ts +1 -0
- package/src/lib/components/Popover/Popover.svelte +81 -0
- package/src/lib/components/Popover/index.ts +2 -0
- package/src/lib/components/Popover/types.ts +19 -0
- package/src/lib/components/PropsTable/PropsTable.svelte +107 -0
- package/src/lib/components/RadialMenu/EffectPreview.svelte +36 -0
- package/src/lib/components/RadialMenu/EffectPreviewScene.svelte +194 -0
- package/src/lib/components/RadialMenu/RadialMenu.svelte +503 -0
- package/src/lib/components/RadialMenu/RadialMenuItem.svelte +176 -0
- package/src/lib/components/RadialMenu/index.ts +2 -0
- package/src/lib/components/RadialMenu/types.ts +35 -0
- package/src/lib/components/Select/Select.svelte +342 -0
- package/src/lib/components/Select/index.ts +2 -0
- package/src/lib/components/Select/types.ts +22 -0
- package/src/lib/components/Spacer/Spacer.svelte +14 -0
- package/src/lib/components/Spacer/index.ts +2 -0
- package/src/lib/components/Spacer/types.ts +5 -0
- package/src/lib/components/Stage/components/AnnotationLayer/AnnotationLayer.svelte +445 -0
- package/src/lib/components/Stage/components/AnnotationLayer/AnnotationMaterial.svelte +167 -0
- package/src/lib/components/Stage/components/AnnotationLayer/types.ts +196 -0
- package/src/lib/components/Stage/components/CursorLayer/CursorLayer.svelte +148 -0
- package/src/lib/components/Stage/components/CursorLayer/cursor.svg +26 -0
- package/src/lib/components/Stage/components/CursorLayer/index.ts +2 -0
- package/src/lib/components/Stage/components/CursorLayer/types.ts +23 -0
- package/src/lib/components/Stage/components/DrawingLayer/DrawingMaterial.svelte +364 -0
- package/src/lib/components/Stage/components/DrawingLayer/types.ts +65 -0
- package/src/lib/components/Stage/components/EdgeOverlayLayer/EdgeOverlayLayer.svelte +72 -0
- package/src/lib/components/Stage/components/EdgeOverlayLayer/types.ts +34 -0
- package/src/lib/components/Stage/components/FogLayer/FogLayer.svelte +75 -0
- package/src/lib/components/Stage/components/FogLayer/types.ts +51 -0
- package/src/lib/components/Stage/components/FogOfWarLayer/FogOfWarLayer.svelte +249 -0
- package/src/lib/components/Stage/components/FogOfWarLayer/FogOfWarMaterial.svelte +200 -0
- package/src/lib/components/Stage/components/FogOfWarLayer/types.ts +116 -0
- package/src/lib/components/Stage/components/GridLayer/GridLayer.svelte +20 -0
- package/src/lib/components/Stage/components/GridLayer/GridMaterial.svelte +69 -0
- package/src/lib/components/Stage/components/GridLayer/types.ts +79 -0
- package/src/lib/components/Stage/components/LayerInput/LayerInput.svelte +300 -0
- package/src/lib/components/Stage/components/MapLayer/MapLayer.svelte +196 -0
- package/src/lib/components/Stage/components/MapLayer/dataSources/GifDataSource.ts +265 -0
- package/src/lib/components/Stage/components/MapLayer/dataSources/IMapDataSource.ts +55 -0
- package/src/lib/components/Stage/components/MapLayer/dataSources/ImageDataSource.ts +87 -0
- package/src/lib/components/Stage/components/MapLayer/dataSources/VideoDataSource.ts +150 -0
- package/src/lib/components/Stage/components/MapLayer/dataSources/dataSourceFactory.ts +48 -0
- package/src/lib/components/Stage/components/MapLayer/dataSources/index.ts +16 -0
- package/src/lib/components/Stage/components/MapLayer/types.ts +58 -0
- package/src/lib/components/Stage/components/MarkerLayer/MarkerLayer.svelte +398 -0
- package/src/lib/components/Stage/components/MarkerLayer/MarkerToken.svelte +262 -0
- package/src/lib/components/Stage/components/MarkerLayer/types.ts +126 -0
- package/src/lib/components/Stage/components/MeasurementLayer/MeasurementLayer.svelte +364 -0
- package/src/lib/components/Stage/components/MeasurementLayer/MeasurementManager.svelte +473 -0
- package/src/lib/components/Stage/components/MeasurementLayer/measurements/BaseMeasurement.ts +427 -0
- package/src/lib/components/Stage/components/MeasurementLayer/measurements/BeamMeasurement.ts +105 -0
- package/src/lib/components/Stage/components/MeasurementLayer/measurements/CircleMeasurement.ts +98 -0
- package/src/lib/components/Stage/components/MeasurementLayer/measurements/ConeMeasurement.ts +163 -0
- package/src/lib/components/Stage/components/MeasurementLayer/measurements/LineMeasurement.ts +102 -0
- package/src/lib/components/Stage/components/MeasurementLayer/measurements/RectangleMeasurement.ts +120 -0
- package/src/lib/components/Stage/components/MeasurementLayer/measurements/index.ts +7 -0
- package/src/lib/components/Stage/components/MeasurementLayer/types.ts +94 -0
- package/src/lib/components/Stage/components/MeasurementLayer/utils/canvasDrawing.ts +357 -0
- package/src/lib/components/Stage/components/MeasurementLayer/utils/distanceCalculations.ts +170 -0
- package/src/lib/components/Stage/components/ParticleSystem/ParticleSystem.svelte +220 -0
- package/src/lib/components/Stage/components/ParticleSystem/particles/atlases/ash.png +0 -0
- package/src/lib/components/Stage/components/ParticleSystem/particles/atlases/leaves.png +0 -0
- package/src/lib/components/Stage/components/ParticleSystem/particles/atlases/rain.png +0 -0
- package/src/lib/components/Stage/components/ParticleSystem/particles/atlases/snow.png +0 -0
- package/src/lib/components/Stage/components/ParticleSystem/rng.js +20 -0
- package/src/lib/components/Stage/components/ParticleSystem/types.ts +95 -0
- package/src/lib/components/Stage/components/PerformanceDebugger/PerformanceDebugger.svelte +144 -0
- package/src/lib/components/Stage/components/PerformanceDebugger/index.ts +1 -0
- package/src/lib/components/Stage/components/PerformanceOverlay/PerformanceOverlay.svelte +208 -0
- package/src/lib/components/Stage/components/PerformanceOverlay/index.ts +1 -0
- package/src/lib/components/Stage/components/PointerInputManager/PointerInputManager.svelte +201 -0
- package/src/lib/components/Stage/components/Scene/Scene.svelte +651 -0
- package/src/lib/components/Stage/components/Scene/luts.ts +24 -0
- package/src/lib/components/Stage/components/Scene/types.ts +225 -0
- package/src/lib/components/Stage/components/Stage/Stage.svelte +332 -0
- package/src/lib/components/Stage/components/Stage/types.ts +136 -0
- package/src/lib/components/Stage/components/WeatherLayer/WeatherLayer.svelte +135 -0
- package/src/lib/components/Stage/components/WeatherLayer/presets/AshPreset.ts +71 -0
- package/src/lib/components/Stage/components/WeatherLayer/presets/LeavesPreset.ts +70 -0
- package/src/lib/components/Stage/components/WeatherLayer/presets/RainPreset.ts +68 -0
- package/src/lib/components/Stage/components/WeatherLayer/presets/SnowPreset.ts +70 -0
- package/src/lib/components/Stage/components/WeatherLayer/presets/index.ts +6 -0
- package/src/lib/components/Stage/components/WeatherLayer/types.ts +35 -0
- package/src/lib/components/Stage/helpers/clippingPlaneStore.svelte.ts +28 -0
- package/src/lib/components/Stage/helpers/debugState.svelte.ts +18 -0
- package/src/lib/components/Stage/helpers/grid.ts +548 -0
- package/src/lib/components/Stage/helpers/lazyBrush.ts +171 -0
- package/src/lib/components/Stage/helpers/performanceMetrics.svelte.ts +220 -0
- package/src/lib/components/Stage/helpers/utils.ts +21 -0
- package/src/lib/components/Stage/index.ts +49 -0
- package/src/lib/components/Stage/shaders/AnnotationEffects.frag +1070 -0
- package/src/lib/components/Stage/shaders/Annotations.frag +29 -0
- package/src/lib/components/Stage/shaders/Drawing.frag +83 -0
- package/src/lib/components/Stage/shaders/Drawing.vert +5 -0
- package/src/lib/components/Stage/shaders/Fog.frag +147 -0
- package/src/lib/components/Stage/shaders/FractalNoise.frag +96 -0
- package/src/lib/components/Stage/shaders/GridShader.frag +174 -0
- package/src/lib/components/Stage/shaders/Overlay.frag +23 -0
- package/src/lib/components/Stage/shaders/Overlay.vert +0 -0
- package/src/lib/components/Stage/shaders/Particles.frag +27 -0
- package/src/lib/components/Stage/shaders/Particles.vert +51 -0
- package/src/lib/components/Stage/shaders/ToolOutline.frag +59 -0
- package/src/lib/components/Stage/shaders/default.vert +8 -0
- package/src/lib/components/Stage/types.ts +4 -0
- package/src/lib/components/Table/Table.svelte +16 -0
- package/src/lib/components/Table/Td.svelte +17 -0
- package/src/lib/components/Table/Th.svelte +18 -0
- package/src/lib/components/Table/index.ts +4 -0
- package/src/lib/components/Table/types.ts +14 -0
- package/src/lib/components/Text/Text.svelte +23 -0
- package/src/lib/components/Text/index.ts +2 -0
- package/src/lib/components/Text/types.ts +12 -0
- package/src/lib/components/Title/Title.svelte +54 -0
- package/src/lib/components/Title/index.ts +2 -0
- package/src/lib/components/Title/types.ts +9 -0
- package/src/lib/components/Toast/Toast.svelte +155 -0
- package/src/lib/components/Toast/index.ts +5 -0
- package/src/lib/components/Toast/toastCookie.ts +24 -0
- package/src/lib/components/Toast/types.ts +6 -0
- package/src/lib/components/ToolTip/ToolTip.svelte +70 -0
- package/src/lib/components/ToolTip/index.ts +2 -0
- package/src/lib/components/ToolTip/types.ts +14 -0
- package/src/lib/components/index.ts +32 -0
- package/src/lib/components/types.ts +0 -0
- package/src/lib/index.ts +2 -0
- package/src/lib/styles/globals.css +108 -0
- package/src/lib/styles/normalize.css +9 -0
- package/src/lib/styles/reset.css +133 -0
- package/src/lib/styles/utilities.css +179 -0
- package/src/lib/styles/vars.css +1103 -0
- package/src/lib/types/awareness.ts +17 -0
- package/src/lib/utils/rle.ts +217 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
import { T, useTask } from '@threlte/core';
|
|
4
|
+
import { onDestroy } from 'svelte';
|
|
5
|
+
import { MeasurementType, type MeasurementLayerProps } from './types';
|
|
6
|
+
import type { IMeasurement } from './measurements/BaseMeasurement';
|
|
7
|
+
import { LineMeasurement } from './measurements/LineMeasurement';
|
|
8
|
+
import { CircleMeasurement } from './measurements/CircleMeasurement';
|
|
9
|
+
import { RectangleMeasurement } from './measurements/RectangleMeasurement';
|
|
10
|
+
import { BeamMeasurement } from './measurements/BeamMeasurement';
|
|
11
|
+
import { ConeMeasurement } from './measurements/ConeMeasurement';
|
|
12
|
+
import { drawCircle } from './utils/canvasDrawing';
|
|
13
|
+
import type { DisplayProps } from '../Stage/types';
|
|
14
|
+
import type { GridLayerProps } from '../GridLayer/types';
|
|
15
|
+
import { SceneLayer, SceneLayerOrder } from '../Scene/types';
|
|
16
|
+
|
|
17
|
+
interface Props {
|
|
18
|
+
props: MeasurementLayerProps;
|
|
19
|
+
visible: boolean;
|
|
20
|
+
displayProps: DisplayProps;
|
|
21
|
+
gridProps: GridLayerProps;
|
|
22
|
+
sceneRotation?: number;
|
|
23
|
+
onFadeComplete?: () => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const { props, visible, displayProps, gridProps, sceneRotation = 0, onFadeComplete }: Props = $props();
|
|
27
|
+
|
|
28
|
+
$effect(() => {
|
|
29
|
+
console.log('[MeasurementManager] Grid props:', gridProps);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
let currentMeasurement: IMeasurement | null = null;
|
|
33
|
+
let measurementGroup = $state(new THREE.Group());
|
|
34
|
+
let autoHideTimeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
35
|
+
|
|
36
|
+
// Fade animation state
|
|
37
|
+
let isFading = $state(false);
|
|
38
|
+
let fadeStartTime = $state(0);
|
|
39
|
+
let fadeOpacity = $state(1.0);
|
|
40
|
+
let receivedFadeoutTime = $state<number | null>(null); // Store fadeout time for received measurements
|
|
41
|
+
|
|
42
|
+
// Preview indicator
|
|
43
|
+
let previewMesh = $state(new THREE.Mesh());
|
|
44
|
+
let previewMaterial = $state(new THREE.MeshBasicMaterial());
|
|
45
|
+
let previewGeometry = $state(new THREE.PlaneGeometry());
|
|
46
|
+
let previewSize = $derived(props ? props.markerSize + props.outlineThickness * 2 : 22);
|
|
47
|
+
let showPreview = $state(false);
|
|
48
|
+
|
|
49
|
+
// Task for fade animation
|
|
50
|
+
useTask(() => {
|
|
51
|
+
if (isFading && props) {
|
|
52
|
+
const now = performance.now();
|
|
53
|
+
const fadeElapsed = now - fadeStartTime;
|
|
54
|
+
// Use receivedFadeoutTime if set, otherwise use props.fadeoutTime
|
|
55
|
+
const fadeTime = receivedFadeoutTime ?? props.fadeoutTime;
|
|
56
|
+
const progress = Math.min(fadeElapsed / fadeTime, 1);
|
|
57
|
+
|
|
58
|
+
fadeOpacity = 1 - progress;
|
|
59
|
+
|
|
60
|
+
// Update the opacity of all materials in the measurement group
|
|
61
|
+
if (currentMeasurement) {
|
|
62
|
+
if (currentMeasurement.shapeMesh.material instanceof THREE.MeshBasicMaterial) {
|
|
63
|
+
currentMeasurement.shapeMesh.material.opacity = props.opacity * fadeOpacity;
|
|
64
|
+
}
|
|
65
|
+
if (currentMeasurement.textMesh.material instanceof THREE.MeshBasicMaterial) {
|
|
66
|
+
currentMeasurement.textMesh.material.opacity = props.opacity * fadeOpacity;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (progress >= 1) {
|
|
71
|
+
isFading = false;
|
|
72
|
+
clearMeasurement();
|
|
73
|
+
// Notify parent that fade is complete
|
|
74
|
+
if (onFadeComplete) {
|
|
75
|
+
onFadeComplete();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
onDestroy(() => {
|
|
82
|
+
// Clear any pending auto-hide timeout
|
|
83
|
+
if (autoHideTimeoutId !== null) {
|
|
84
|
+
clearTimeout(autoHideTimeoutId);
|
|
85
|
+
autoHideTimeoutId = null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Stop fade animation
|
|
89
|
+
isFading = false;
|
|
90
|
+
|
|
91
|
+
currentMeasurement?.dispose();
|
|
92
|
+
if (previewGeometry) {
|
|
93
|
+
previewGeometry.dispose();
|
|
94
|
+
}
|
|
95
|
+
if (previewMaterial) {
|
|
96
|
+
if (previewMaterial.map) {
|
|
97
|
+
previewMaterial.map.dispose();
|
|
98
|
+
}
|
|
99
|
+
previewMaterial.dispose();
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Creates a canvas texture for the preview marker that matches the measurement point styling.
|
|
105
|
+
* The marker uses the same visual properties (color, thickness, outline) as measurement start/end points.
|
|
106
|
+
*/
|
|
107
|
+
$effect(() => {
|
|
108
|
+
if (!props) return;
|
|
109
|
+
|
|
110
|
+
// Create the preview marker texture
|
|
111
|
+
const markerCanvas = createMarkerCanvas();
|
|
112
|
+
const markerTexture = new THREE.CanvasTexture(markerCanvas);
|
|
113
|
+
markerTexture.needsUpdate = true;
|
|
114
|
+
|
|
115
|
+
// Dispose the old texture before assigning new one to prevent memory leak
|
|
116
|
+
if (previewMaterial.map) {
|
|
117
|
+
previewMaterial.map.dispose();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Assign the texture to the preview material
|
|
121
|
+
previewMaterial.map = markerTexture;
|
|
122
|
+
previewMaterial.needsUpdate = true;
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Updates the preview indicator position and visibility based on mouse position and measurement state.
|
|
127
|
+
* The preview is automatically hidden when a measurement is currently being created.
|
|
128
|
+
*
|
|
129
|
+
* @param {THREE.Vector2 | null} position - The world position where the preview should be displayed, or null to hide
|
|
130
|
+
* @param {boolean} [visible=true] - Whether the preview should be visible (defaults to true)
|
|
131
|
+
* @returns {void}
|
|
132
|
+
*/
|
|
133
|
+
function updatePreview(position: THREE.Vector2 | null, visible: boolean = true): void {
|
|
134
|
+
if (!position || currentMeasurement) {
|
|
135
|
+
showPreview = false;
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
showPreview = visible;
|
|
140
|
+
if (previewMesh && showPreview) {
|
|
141
|
+
previewMesh.position.set(position.x, position.y, 0);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Hides the preview indicator from view.
|
|
147
|
+
* Used when measurements are active or when the cursor leaves the measurement area.
|
|
148
|
+
* @returns {void}
|
|
149
|
+
*/
|
|
150
|
+
function hidePreview(): void {
|
|
151
|
+
showPreview = false;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Shows the preview indicator if no measurement is currently active.
|
|
156
|
+
* Provides visual feedback for where the next measurement point will be placed.
|
|
157
|
+
* @returns {void}
|
|
158
|
+
*/
|
|
159
|
+
function showPreviewIndicator(): void {
|
|
160
|
+
if (!currentMeasurement) {
|
|
161
|
+
showPreview = true;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Creates a canvas texture for the measurement marker that matches the measurement point styling.
|
|
167
|
+
* The marker uses the same visual properties (color, thickness, outline) as measurement start/end points.
|
|
168
|
+
*
|
|
169
|
+
* @returns {HTMLCanvasElement} A canvas element with the rendered marker that can be used as a texture
|
|
170
|
+
*/
|
|
171
|
+
function createMarkerCanvas(): HTMLCanvasElement {
|
|
172
|
+
const canvas = document.createElement('canvas');
|
|
173
|
+
const context = canvas.getContext('2d', { colorSpace: 'srgb' })!;
|
|
174
|
+
|
|
175
|
+
const width = previewSize;
|
|
176
|
+
const height = previewSize;
|
|
177
|
+
|
|
178
|
+
canvas.width = width;
|
|
179
|
+
canvas.height = height;
|
|
180
|
+
|
|
181
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
182
|
+
|
|
183
|
+
if (props) {
|
|
184
|
+
drawCircle(
|
|
185
|
+
context,
|
|
186
|
+
previewSize / 2,
|
|
187
|
+
previewSize / 2,
|
|
188
|
+
props.markerSize / 2,
|
|
189
|
+
props.color,
|
|
190
|
+
props.outlineColor,
|
|
191
|
+
props.outlineThickness
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return canvas;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Starts a new measurement at the specified point based on the current measurement type.
|
|
200
|
+
* Clears any existing measurement and creates the appropriate measurement class instance.
|
|
201
|
+
*
|
|
202
|
+
* @param {THREE.Vector2} startPoint - The world coordinates where the measurement should begin
|
|
203
|
+
* @returns {void}
|
|
204
|
+
*/
|
|
205
|
+
function startMeasurement(startPoint: THREE.Vector2): void {
|
|
206
|
+
if (!props) return;
|
|
207
|
+
|
|
208
|
+
// Clear any existing auto-hide timeout
|
|
209
|
+
if (autoHideTimeoutId !== null) {
|
|
210
|
+
clearTimeout(autoHideTimeoutId);
|
|
211
|
+
autoHideTimeoutId = null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Reset fade state
|
|
215
|
+
isFading = false;
|
|
216
|
+
fadeOpacity = 1.0;
|
|
217
|
+
|
|
218
|
+
clearMeasurement();
|
|
219
|
+
showPreview = false; // Hide preview when starting measurement
|
|
220
|
+
|
|
221
|
+
// Create new measurement based on type
|
|
222
|
+
let measurement: IMeasurement;
|
|
223
|
+
|
|
224
|
+
switch (props.type) {
|
|
225
|
+
case MeasurementType.Line:
|
|
226
|
+
measurement = new LineMeasurement(startPoint, props, displayProps, gridProps);
|
|
227
|
+
break;
|
|
228
|
+
case MeasurementType.Beam:
|
|
229
|
+
measurement = new BeamMeasurement(startPoint, props, displayProps, gridProps);
|
|
230
|
+
break;
|
|
231
|
+
case MeasurementType.Cone:
|
|
232
|
+
measurement = new ConeMeasurement(startPoint, props, displayProps, gridProps);
|
|
233
|
+
break;
|
|
234
|
+
case MeasurementType.Circle:
|
|
235
|
+
measurement = new CircleMeasurement(startPoint, props, displayProps, gridProps);
|
|
236
|
+
break;
|
|
237
|
+
case MeasurementType.Square:
|
|
238
|
+
measurement = new RectangleMeasurement(startPoint, props, displayProps, gridProps);
|
|
239
|
+
break;
|
|
240
|
+
default:
|
|
241
|
+
measurement = new LineMeasurement(startPoint, props, displayProps, gridProps);
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
currentMeasurement = measurement;
|
|
246
|
+
measurementGroup.add(measurement.object);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Updates the current measurement with a new end point, typically called during mouse movement.
|
|
251
|
+
* Recalculates measurement geometry and updates the visual representation in real-time.
|
|
252
|
+
*
|
|
253
|
+
* @param {THREE.Vector2} endPoint - The world coordinates for the current end point of the measurement
|
|
254
|
+
* @returns {void}
|
|
255
|
+
*/
|
|
256
|
+
function updateMeasurement(endPoint: THREE.Vector2): void {
|
|
257
|
+
currentMeasurement?.update(endPoint, sceneRotation);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Completes the current measurement and schedules its automatic removal.
|
|
262
|
+
* The measurement is displayed for the duration specified by autoHideDelay, then fades out over fadeoutTime before being cleared.
|
|
263
|
+
* @returns {void}
|
|
264
|
+
*/
|
|
265
|
+
function finishMeasurement(): void {
|
|
266
|
+
if (!currentMeasurement || !props) return;
|
|
267
|
+
|
|
268
|
+
// Don't finish measurements with zero distance (same start and end point)
|
|
269
|
+
const distance = currentMeasurement.startPoint.distanceTo(currentMeasurement.endPoint);
|
|
270
|
+
if (distance === 0) {
|
|
271
|
+
clearMeasurement();
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
autoHideTimeoutId = setTimeout(() => {
|
|
276
|
+
// Start the fade animation
|
|
277
|
+
fadeStartTime = performance.now();
|
|
278
|
+
isFading = true;
|
|
279
|
+
}, props.autoHideDelay);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Removes the current measurement from the scene and disposes of its resources.
|
|
284
|
+
* Cleans up Three.js objects to prevent memory leaks and resets the measurement state.
|
|
285
|
+
* @returns {void}
|
|
286
|
+
*/
|
|
287
|
+
function clearMeasurement(): void {
|
|
288
|
+
// Clear any existing auto-hide timeout
|
|
289
|
+
if (autoHideTimeoutId !== null) {
|
|
290
|
+
clearTimeout(autoHideTimeoutId);
|
|
291
|
+
autoHideTimeoutId = null;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Reset fade state
|
|
295
|
+
isFading = false;
|
|
296
|
+
fadeOpacity = 1.0;
|
|
297
|
+
receivedFadeoutTime = null; // Reset received fadeout time
|
|
298
|
+
|
|
299
|
+
if (currentMeasurement) {
|
|
300
|
+
currentMeasurement.dispose();
|
|
301
|
+
currentMeasurement = null;
|
|
302
|
+
measurementGroup.clear();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Displays a measurement received from another user (via Y.js).
|
|
308
|
+
* Creates the measurement and immediately sets it to finished state to trigger auto-fade.
|
|
309
|
+
*
|
|
310
|
+
* @param {THREE.Vector2} startPoint - The starting point of the measurement
|
|
311
|
+
* @param {THREE.Vector2} endPoint - The ending point of the measurement
|
|
312
|
+
* @param {number} type - The type of measurement (MeasurementType enum)
|
|
313
|
+
* @returns {void}
|
|
314
|
+
*/
|
|
315
|
+
function displayReceivedMeasurement(
|
|
316
|
+
startPoint: THREE.Vector2,
|
|
317
|
+
endPoint: THREE.Vector2,
|
|
318
|
+
type: number,
|
|
319
|
+
beamWidth?: number,
|
|
320
|
+
coneAngle?: number,
|
|
321
|
+
color?: string,
|
|
322
|
+
thickness?: number,
|
|
323
|
+
outlineColor?: string,
|
|
324
|
+
outlineThickness?: number,
|
|
325
|
+
opacity?: number,
|
|
326
|
+
markerSize?: number,
|
|
327
|
+
autoHideDelay?: number,
|
|
328
|
+
fadeoutTime?: number,
|
|
329
|
+
showDistance?: boolean,
|
|
330
|
+
snapToGrid?: boolean,
|
|
331
|
+
enableDMG252?: boolean
|
|
332
|
+
): void {
|
|
333
|
+
if (!props) {
|
|
334
|
+
console.log('[MeasurementManager] No props available for displayReceivedMeasurement');
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
console.log('[MeasurementManager] displayReceivedMeasurement called:', {
|
|
339
|
+
startPoint,
|
|
340
|
+
endPoint,
|
|
341
|
+
type,
|
|
342
|
+
beamWidth,
|
|
343
|
+
coneAngle,
|
|
344
|
+
thickness,
|
|
345
|
+
hasCurrentMeasurement: !!currentMeasurement
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// Clear any existing measurement
|
|
349
|
+
clearMeasurement();
|
|
350
|
+
|
|
351
|
+
// Create the appropriate measurement type
|
|
352
|
+
let measurement: IMeasurement;
|
|
353
|
+
|
|
354
|
+
// Use the received properties if provided, override the props temporarily
|
|
355
|
+
const measurementProps = {
|
|
356
|
+
...props,
|
|
357
|
+
type,
|
|
358
|
+
...(beamWidth !== undefined && { beamWidth }),
|
|
359
|
+
...(coneAngle !== undefined && { coneAngle }),
|
|
360
|
+
...(color !== undefined && { color }),
|
|
361
|
+
...(thickness !== undefined && { thickness }),
|
|
362
|
+
...(outlineColor !== undefined && { outlineColor }),
|
|
363
|
+
...(outlineThickness !== undefined && { outlineThickness }),
|
|
364
|
+
...(opacity !== undefined && { opacity }),
|
|
365
|
+
...(markerSize !== undefined && { markerSize }),
|
|
366
|
+
...(autoHideDelay !== undefined && { autoHideDelay }),
|
|
367
|
+
...(fadeoutTime !== undefined && { fadeoutTime }),
|
|
368
|
+
...(showDistance !== undefined && { showDistance }),
|
|
369
|
+
...(snapToGrid !== undefined && { snapToGrid }),
|
|
370
|
+
...(enableDMG252 !== undefined && { enableDMG252 })
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
switch (type) {
|
|
374
|
+
case MeasurementType.Line:
|
|
375
|
+
measurement = new LineMeasurement(startPoint, measurementProps, displayProps, gridProps);
|
|
376
|
+
break;
|
|
377
|
+
case MeasurementType.Beam:
|
|
378
|
+
measurement = new BeamMeasurement(startPoint, measurementProps, displayProps, gridProps);
|
|
379
|
+
break;
|
|
380
|
+
case MeasurementType.Cone:
|
|
381
|
+
measurement = new ConeMeasurement(startPoint, measurementProps, displayProps, gridProps);
|
|
382
|
+
break;
|
|
383
|
+
case MeasurementType.Circle:
|
|
384
|
+
measurement = new CircleMeasurement(startPoint, measurementProps, displayProps, gridProps);
|
|
385
|
+
break;
|
|
386
|
+
case MeasurementType.Square:
|
|
387
|
+
measurement = new RectangleMeasurement(startPoint, measurementProps, displayProps, gridProps);
|
|
388
|
+
break;
|
|
389
|
+
default:
|
|
390
|
+
measurement = new LineMeasurement(startPoint, measurementProps, displayProps, gridProps);
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Set the measurement
|
|
395
|
+
currentMeasurement = measurement;
|
|
396
|
+
measurementGroup.add(measurement.object);
|
|
397
|
+
|
|
398
|
+
console.log('[MeasurementManager] Measurement created and added to group:', {
|
|
399
|
+
groupChildren: measurementGroup.children.length,
|
|
400
|
+
measurementObject: measurement.object,
|
|
401
|
+
visible: measurementGroup.visible
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
// Update to the end point
|
|
405
|
+
currentMeasurement.update(endPoint, sceneRotation);
|
|
406
|
+
|
|
407
|
+
console.log('[MeasurementManager] Measurement updated to endpoint');
|
|
408
|
+
|
|
409
|
+
// Store the fadeout time if provided for the fade animation
|
|
410
|
+
if (fadeoutTime !== undefined) {
|
|
411
|
+
receivedFadeoutTime = fadeoutTime;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Schedule auto-fade with the received timing properties
|
|
415
|
+
const delay = autoHideDelay ?? props.autoHideDelay;
|
|
416
|
+
console.log(
|
|
417
|
+
'[MeasurementManager] Scheduling auto-fade with delay:',
|
|
418
|
+
delay,
|
|
419
|
+
'fadeTime:',
|
|
420
|
+
fadeoutTime ?? props.fadeoutTime
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
autoHideTimeoutId = setTimeout(() => {
|
|
424
|
+
// Start the fade animation
|
|
425
|
+
fadeStartTime = performance.now();
|
|
426
|
+
isFading = true;
|
|
427
|
+
}, delay);
|
|
428
|
+
|
|
429
|
+
console.log('[MeasurementManager] Measurement auto-fade scheduled');
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Export the methods for use by parent components
|
|
433
|
+
export {
|
|
434
|
+
startMeasurement,
|
|
435
|
+
updateMeasurement,
|
|
436
|
+
finishMeasurement,
|
|
437
|
+
clearMeasurement,
|
|
438
|
+
updatePreview,
|
|
439
|
+
hidePreview,
|
|
440
|
+
showPreviewIndicator,
|
|
441
|
+
displayReceivedMeasurement
|
|
442
|
+
};
|
|
443
|
+
</script>
|
|
444
|
+
|
|
445
|
+
<!-- Measurement Group -->
|
|
446
|
+
<!-- Always visible to show received measurements in playfield -->
|
|
447
|
+
<T.Group
|
|
448
|
+
bind:ref={measurementGroup}
|
|
449
|
+
visible={true}
|
|
450
|
+
layers={[SceneLayer.Overlay]}
|
|
451
|
+
renderOrder={SceneLayerOrder.Measurement}
|
|
452
|
+
>
|
|
453
|
+
<!-- Measurement objects will be added here dynamically -->
|
|
454
|
+
</T.Group>
|
|
455
|
+
|
|
456
|
+
<!-- Preview indicator -->
|
|
457
|
+
<T.Mesh
|
|
458
|
+
bind:ref={previewMesh}
|
|
459
|
+
visible={showPreview && visible}
|
|
460
|
+
layers={[SceneLayer.Overlay]}
|
|
461
|
+
renderOrder={SceneLayerOrder.Measurement}
|
|
462
|
+
>
|
|
463
|
+
<T.MeshBasicMaterial
|
|
464
|
+
bind:ref={previewMaterial}
|
|
465
|
+
transparent={true}
|
|
466
|
+
opacity={props?.opacity ?? 1}
|
|
467
|
+
side={THREE.DoubleSide}
|
|
468
|
+
depthWrite={false}
|
|
469
|
+
depthTest={false}
|
|
470
|
+
toneMapped={false}
|
|
471
|
+
/>
|
|
472
|
+
<T.PlaneGeometry bind:ref={previewGeometry} args={[previewSize, previewSize]} />
|
|
473
|
+
</T.Mesh>
|