@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,126 @@
|
|
|
1
|
+
import type { JSONContent } from '@tiptap/core';
|
|
2
|
+
|
|
3
|
+
export enum MarkerVisibility {
|
|
4
|
+
Always = 0,
|
|
5
|
+
DM = 1,
|
|
6
|
+
Player = 2,
|
|
7
|
+
Hover = 3 // Hidden from players, revealed on DM hover
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export enum MarkerShape {
|
|
11
|
+
None = 0,
|
|
12
|
+
Circle = 1,
|
|
13
|
+
Square = 2,
|
|
14
|
+
Triangle = 3,
|
|
15
|
+
Pin = 4
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export enum MarkerSize {
|
|
19
|
+
Small = 1,
|
|
20
|
+
Medium = 2,
|
|
21
|
+
Large = 3
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface Marker {
|
|
25
|
+
id: string;
|
|
26
|
+
title: string;
|
|
27
|
+
position: {
|
|
28
|
+
x: number;
|
|
29
|
+
y: number;
|
|
30
|
+
};
|
|
31
|
+
size: MarkerSize;
|
|
32
|
+
shape: MarkerShape;
|
|
33
|
+
shapeColor: string;
|
|
34
|
+
label: string | null;
|
|
35
|
+
imageUrl: string | null;
|
|
36
|
+
imageScale: number;
|
|
37
|
+
visibility: MarkerVisibility;
|
|
38
|
+
note: JSONContent | null;
|
|
39
|
+
pinnedTooltip?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface MarkerLayerProps {
|
|
43
|
+
/**
|
|
44
|
+
* Whether the marker layer is visible
|
|
45
|
+
*/
|
|
46
|
+
visible: boolean;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The shape of the marker icons
|
|
50
|
+
*/
|
|
51
|
+
shape: {
|
|
52
|
+
/**
|
|
53
|
+
* The stroke color of the marker icons represented as a hex string (e.g. 0x60A3FE)
|
|
54
|
+
*/
|
|
55
|
+
strokeColor: string;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The stroke width of the marker icons
|
|
59
|
+
*/
|
|
60
|
+
strokeWidth: number;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The shadow color of the marker icons represented as a hex string (e.g. 0x60A3FE)
|
|
64
|
+
*/
|
|
65
|
+
shadowColor: string;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The shadow blur of the marker icons
|
|
69
|
+
*/
|
|
70
|
+
shadowBlur: number;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The shadow offset of the marker icons
|
|
74
|
+
*/
|
|
75
|
+
shadowOffset: {
|
|
76
|
+
x: number;
|
|
77
|
+
y: number;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The text of the marker
|
|
83
|
+
*/
|
|
84
|
+
text: {
|
|
85
|
+
/**
|
|
86
|
+
* The size of the marker text
|
|
87
|
+
*/
|
|
88
|
+
size: number;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The color of the marker text
|
|
92
|
+
*/
|
|
93
|
+
color: string;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The stroke width of the marker text
|
|
97
|
+
*/
|
|
98
|
+
strokeWidth: number;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The color of the marker text stroke
|
|
102
|
+
*/
|
|
103
|
+
strokeColor: string;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Whether to snap the marker to the grid
|
|
108
|
+
*/
|
|
109
|
+
snapToGrid: boolean;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* An array of Marker objects
|
|
113
|
+
*/
|
|
114
|
+
markers: Marker[];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface MarkerLayerExports {
|
|
118
|
+
markerState: {
|
|
119
|
+
isHovering: boolean;
|
|
120
|
+
isDragging: boolean;
|
|
121
|
+
hoveredMarker: Marker | null;
|
|
122
|
+
selectedMarker: Marker | null;
|
|
123
|
+
};
|
|
124
|
+
maintainHover: (maintain: boolean) => void;
|
|
125
|
+
onSceneChange: () => void;
|
|
126
|
+
}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
import { T, type Props as ThrelteProps } from '@threlte/core';
|
|
4
|
+
import { type MeasurementLayerProps } from './types';
|
|
5
|
+
import { type DisplayProps } from '../Stage/types';
|
|
6
|
+
import { SceneLayer } from '../Scene/types';
|
|
7
|
+
import { type GridLayerProps, GridType } from '../GridLayer/types';
|
|
8
|
+
import { snapToGrid } from '../../helpers/grid';
|
|
9
|
+
import LayerInput from '../LayerInput/LayerInput.svelte';
|
|
10
|
+
import MeasurementManager from './MeasurementManager.svelte';
|
|
11
|
+
|
|
12
|
+
interface Props extends ThrelteProps<typeof THREE.Mesh> {
|
|
13
|
+
props: MeasurementLayerProps;
|
|
14
|
+
isActive: boolean;
|
|
15
|
+
display: DisplayProps;
|
|
16
|
+
grid: GridLayerProps;
|
|
17
|
+
sceneRotation?: number;
|
|
18
|
+
onMeasurementStart?: (startPoint: THREE.Vector2, type: number) => void;
|
|
19
|
+
onMeasurementUpdate?: (startPoint: THREE.Vector2, endPoint: THREE.Vector2, type: number) => void;
|
|
20
|
+
onMeasurementEnd?: () => void;
|
|
21
|
+
receivedMeasurement?: {
|
|
22
|
+
startPoint: { x: number; y: number };
|
|
23
|
+
endPoint: { x: number; y: number };
|
|
24
|
+
type: number;
|
|
25
|
+
beamWidth?: number;
|
|
26
|
+
coneAngle?: number;
|
|
27
|
+
// Visual properties
|
|
28
|
+
color?: string;
|
|
29
|
+
thickness?: number;
|
|
30
|
+
outlineColor?: string;
|
|
31
|
+
outlineThickness?: number;
|
|
32
|
+
opacity?: number;
|
|
33
|
+
markerSize?: number;
|
|
34
|
+
// Timing properties
|
|
35
|
+
autoHideDelay?: number;
|
|
36
|
+
fadeoutTime?: number;
|
|
37
|
+
// Distance properties
|
|
38
|
+
showDistance?: boolean;
|
|
39
|
+
snapToGrid?: boolean;
|
|
40
|
+
enableDMG252?: boolean;
|
|
41
|
+
} | null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const {
|
|
45
|
+
props,
|
|
46
|
+
isActive,
|
|
47
|
+
display,
|
|
48
|
+
grid,
|
|
49
|
+
sceneRotation = 0,
|
|
50
|
+
onMeasurementStart,
|
|
51
|
+
onMeasurementUpdate,
|
|
52
|
+
onMeasurementEnd,
|
|
53
|
+
receivedMeasurement
|
|
54
|
+
}: Props = $props();
|
|
55
|
+
|
|
56
|
+
// Pre-allocated vectors to avoid GC pressure
|
|
57
|
+
const centerOffset = new THREE.Vector2();
|
|
58
|
+
let snappedPosition = new THREE.Vector2();
|
|
59
|
+
let inputMesh = $state(new THREE.Mesh());
|
|
60
|
+
|
|
61
|
+
// Update centerOffset when display resolution changes
|
|
62
|
+
$effect(() => {
|
|
63
|
+
centerOffset.set(display.resolution.x / 2, display.resolution.y / 2);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Measurement state
|
|
67
|
+
let isDrawing = false;
|
|
68
|
+
let startPoint: THREE.Vector2 | null = null;
|
|
69
|
+
let measurementManager: MeasurementManager | null = null;
|
|
70
|
+
|
|
71
|
+
// Track previous display resolution to detect scene changes
|
|
72
|
+
let prevResX = display.resolution.x;
|
|
73
|
+
let prevResY = display.resolution.y;
|
|
74
|
+
|
|
75
|
+
// Reset measurement state when layer becomes inactive or display changes (scene switch)
|
|
76
|
+
$effect(() => {
|
|
77
|
+
const resChanged = display.resolution.x !== prevResX || display.resolution.y !== prevResY;
|
|
78
|
+
|
|
79
|
+
// Reset any lingering measurement state when layer deactivates or scene changes
|
|
80
|
+
if (!isActive || resChanged) {
|
|
81
|
+
isDrawing = false;
|
|
82
|
+
startPoint = null;
|
|
83
|
+
if (measurementManager) {
|
|
84
|
+
measurementManager.clearMeasurement();
|
|
85
|
+
measurementManager.hidePreview();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Update tracked resolution
|
|
90
|
+
prevResX = display.resolution.x;
|
|
91
|
+
prevResY = display.resolution.y;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Handles mouse down events to initiate measurement creation.
|
|
96
|
+
* Converts screen coordinates to world coordinates, applies grid snapping if enabled,
|
|
97
|
+
* and starts a new measurement at the clicked position.
|
|
98
|
+
*
|
|
99
|
+
* @param {MouseEvent | TouchEvent} event - The mouse or touch event that triggered this handler
|
|
100
|
+
* @param {THREE.Vector2 | null} coords - The world coordinates of the mouse/touch position, or null if outside bounds
|
|
101
|
+
* @returns {void}
|
|
102
|
+
*/
|
|
103
|
+
function handleMouseDown(event: MouseEvent | TouchEvent, coords: THREE.Vector2 | null): void {
|
|
104
|
+
if (!coords || !isActive || !measurementManager || !props) return;
|
|
105
|
+
|
|
106
|
+
coords.sub(centerOffset);
|
|
107
|
+
|
|
108
|
+
// For measurements on hex grids, snap to centers only
|
|
109
|
+
const isHexGrid = grid.gridType === GridType.Hex;
|
|
110
|
+
const snappedCoords = props.snapToGrid ? snapToGrid(coords, grid, display, isHexGrid) : coords;
|
|
111
|
+
|
|
112
|
+
// Always clear any existing measurement state before starting new one
|
|
113
|
+
// This handles edge cases where isDrawing might be unexpectedly true
|
|
114
|
+
if (isDrawing) {
|
|
115
|
+
measurementManager.clearMeasurement();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Start new measurement
|
|
119
|
+
isDrawing = true;
|
|
120
|
+
startPoint = snappedCoords.clone(); // Clone to avoid reference issues
|
|
121
|
+
measurementManager.startMeasurement(snappedCoords);
|
|
122
|
+
|
|
123
|
+
// Notify parent component
|
|
124
|
+
if (onMeasurementStart) {
|
|
125
|
+
onMeasurementStart(snappedCoords, props.type);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Handles mouse move events to update measurement preview and active measurements.
|
|
131
|
+
* Converts coordinates to world space, applies grid snapping, and either updates
|
|
132
|
+
* the current measurement being drawn or shows a preview indicator.
|
|
133
|
+
*
|
|
134
|
+
* @param {MouseEvent | TouchEvent} event - The mouse or touch event that triggered this handler
|
|
135
|
+
* @param {THREE.Vector2 | null} coords - The world coordinates of the mouse/touch position, or null if outside bounds
|
|
136
|
+
* @returns {void}
|
|
137
|
+
*/
|
|
138
|
+
function handleMouseMove(event: MouseEvent | TouchEvent, coords: THREE.Vector2 | null): void {
|
|
139
|
+
if (!coords || !isActive || !measurementManager || !props) return;
|
|
140
|
+
|
|
141
|
+
coords.sub(centerOffset);
|
|
142
|
+
|
|
143
|
+
// Apply snapping if enabled
|
|
144
|
+
// For measurements on hex grids, snap to centers only
|
|
145
|
+
const isHexGrid = grid.gridType === GridType.Hex;
|
|
146
|
+
if (props.snapToGrid) {
|
|
147
|
+
snappedPosition = snapToGrid(coords, grid, display, isHexGrid);
|
|
148
|
+
} else {
|
|
149
|
+
snappedPosition.copy(coords);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (isDrawing && startPoint && measurementManager) {
|
|
153
|
+
// Update current measurement
|
|
154
|
+
measurementManager.updateMeasurement(snappedPosition);
|
|
155
|
+
|
|
156
|
+
// Notify parent component
|
|
157
|
+
if (onMeasurementUpdate) {
|
|
158
|
+
onMeasurementUpdate(startPoint, snappedPosition, props.type);
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
// Update the preview indicator position
|
|
162
|
+
measurementManager.updatePreview(snappedPosition, isActive);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Handles mouse up events to complete measurement creation.
|
|
168
|
+
* Finalizes the current measurement at the release position and resets the drawing state.
|
|
169
|
+
* Applies grid snapping to the final position if enabled.
|
|
170
|
+
*
|
|
171
|
+
* @param {MouseEvent | TouchEvent} event - The mouse or touch event that triggered this handler
|
|
172
|
+
* @param {THREE.Vector2 | null} coords - The world coordinates of the mouse/touch position, or null if outside bounds
|
|
173
|
+
* @returns {void}
|
|
174
|
+
*/
|
|
175
|
+
function handleMouseUp(event: MouseEvent | TouchEvent, coords: THREE.Vector2 | null): void {
|
|
176
|
+
// Always reset drawing state when mouseUp is called, even if coords is null
|
|
177
|
+
// This prevents isDrawing from staying true after touch gestures or edge cases
|
|
178
|
+
const wasDrawing = isDrawing;
|
|
179
|
+
isDrawing = false;
|
|
180
|
+
|
|
181
|
+
if (!wasDrawing || !startPoint || !measurementManager) {
|
|
182
|
+
startPoint = null;
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (coords) {
|
|
187
|
+
coords.sub(centerOffset);
|
|
188
|
+
// For measurements on hex grids, snap to centers only
|
|
189
|
+
const isHexGrid = grid.gridType === GridType.Hex;
|
|
190
|
+
const snappedCoords = props.snapToGrid ? snapToGrid(coords, grid, display, isHexGrid) : coords;
|
|
191
|
+
|
|
192
|
+
if (snappedCoords) {
|
|
193
|
+
measurementManager.finishMeasurement();
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
// Coords is null (released outside canvas) - clear the incomplete measurement
|
|
197
|
+
measurementManager.clearMeasurement();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
startPoint = null;
|
|
201
|
+
|
|
202
|
+
// Notify parent component
|
|
203
|
+
if (onMeasurementEnd) {
|
|
204
|
+
onMeasurementEnd();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Handles mouse leave events when the cursor exits the measurement area.
|
|
210
|
+
* Hides the preview indicator to provide clear visual feedback that measurements
|
|
211
|
+
* cannot be placed outside the active area.
|
|
212
|
+
* Also resets any in-progress measurement to prevent stuck state.
|
|
213
|
+
* @returns {void}
|
|
214
|
+
*/
|
|
215
|
+
function handleMouseLeave(): void {
|
|
216
|
+
// Reset drawing state if user leaves canvas while drawing
|
|
217
|
+
if (isDrawing && measurementManager) {
|
|
218
|
+
measurementManager.clearMeasurement();
|
|
219
|
+
isDrawing = false;
|
|
220
|
+
startPoint = null;
|
|
221
|
+
if (onMeasurementEnd) {
|
|
222
|
+
onMeasurementEnd();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (measurementManager) {
|
|
227
|
+
measurementManager.hidePreview();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Handles mouse enter events when the cursor enters the measurement area.
|
|
233
|
+
* Shows the preview indicator if the measurement layer is active, providing
|
|
234
|
+
* visual feedback for where measurements can be placed.
|
|
235
|
+
* @returns {void}
|
|
236
|
+
*/
|
|
237
|
+
function handleMouseEnter(): void {
|
|
238
|
+
if (measurementManager && isActive) {
|
|
239
|
+
measurementManager.showPreviewIndicator();
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Export methods for parent components to get measurement state
|
|
244
|
+
export function getCurrentMeasurement(): {
|
|
245
|
+
startPoint: THREE.Vector2 | null;
|
|
246
|
+
endPoint: THREE.Vector2 | null;
|
|
247
|
+
type: number;
|
|
248
|
+
} | null {
|
|
249
|
+
if (!measurementManager || !isDrawing || !startPoint) return null;
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
startPoint: startPoint.clone(),
|
|
253
|
+
endPoint: snappedPosition.clone(),
|
|
254
|
+
type: props.type
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export function isCurrentlyDrawing(): boolean {
|
|
259
|
+
return isDrawing;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Track the last displayed measurement to avoid redundant updates
|
|
263
|
+
let lastDisplayedMeasurement: {
|
|
264
|
+
startX: number;
|
|
265
|
+
startY: number;
|
|
266
|
+
endX: number;
|
|
267
|
+
endY: number;
|
|
268
|
+
type: number;
|
|
269
|
+
} | null = null;
|
|
270
|
+
|
|
271
|
+
// Track if a measurement is currently fading (so we don't clear it prematurely)
|
|
272
|
+
let measurementIsFading = false;
|
|
273
|
+
|
|
274
|
+
// Effect to handle received measurements from other users
|
|
275
|
+
$effect(() => {
|
|
276
|
+
if (receivedMeasurement && measurementManager && !isActive) {
|
|
277
|
+
// Check if this is a new measurement (not the same as last displayed)
|
|
278
|
+
const isNewMeasurement =
|
|
279
|
+
!lastDisplayedMeasurement ||
|
|
280
|
+
lastDisplayedMeasurement.startX !== receivedMeasurement.startPoint.x ||
|
|
281
|
+
lastDisplayedMeasurement.startY !== receivedMeasurement.startPoint.y ||
|
|
282
|
+
lastDisplayedMeasurement.endX !== receivedMeasurement.endPoint.x ||
|
|
283
|
+
lastDisplayedMeasurement.endY !== receivedMeasurement.endPoint.y ||
|
|
284
|
+
lastDisplayedMeasurement.type !== receivedMeasurement.type;
|
|
285
|
+
|
|
286
|
+
if (isNewMeasurement) {
|
|
287
|
+
// Convert to Vector2 with center offset adjustment
|
|
288
|
+
const startPoint = new THREE.Vector2(receivedMeasurement.startPoint.x, receivedMeasurement.startPoint.y);
|
|
289
|
+
const endPoint = new THREE.Vector2(receivedMeasurement.endPoint.x, receivedMeasurement.endPoint.y);
|
|
290
|
+
|
|
291
|
+
// Display the received measurement with all properties if available
|
|
292
|
+
measurementManager.displayReceivedMeasurement(
|
|
293
|
+
startPoint,
|
|
294
|
+
endPoint,
|
|
295
|
+
receivedMeasurement.type,
|
|
296
|
+
receivedMeasurement.beamWidth,
|
|
297
|
+
receivedMeasurement.coneAngle,
|
|
298
|
+
receivedMeasurement.color,
|
|
299
|
+
receivedMeasurement.thickness,
|
|
300
|
+
receivedMeasurement.outlineColor,
|
|
301
|
+
receivedMeasurement.outlineThickness,
|
|
302
|
+
receivedMeasurement.opacity,
|
|
303
|
+
receivedMeasurement.markerSize,
|
|
304
|
+
receivedMeasurement.autoHideDelay,
|
|
305
|
+
receivedMeasurement.fadeoutTime,
|
|
306
|
+
receivedMeasurement.showDistance,
|
|
307
|
+
receivedMeasurement.snapToGrid,
|
|
308
|
+
receivedMeasurement.enableDMG252
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
// Mark that a measurement is now fading
|
|
312
|
+
measurementIsFading = true;
|
|
313
|
+
|
|
314
|
+
// Update last displayed measurement
|
|
315
|
+
lastDisplayedMeasurement = {
|
|
316
|
+
startX: receivedMeasurement.startPoint.x,
|
|
317
|
+
startY: receivedMeasurement.startPoint.y,
|
|
318
|
+
endX: receivedMeasurement.endPoint.x,
|
|
319
|
+
endY: receivedMeasurement.endPoint.y,
|
|
320
|
+
type: receivedMeasurement.type
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
} else if (!receivedMeasurement && lastDisplayedMeasurement && !measurementIsFading) {
|
|
324
|
+
// Only clear if no measurement is fading
|
|
325
|
+
// The measurement will clear itself after fade completes
|
|
326
|
+
lastDisplayedMeasurement = null;
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
</script>
|
|
330
|
+
|
|
331
|
+
<!-- Input handling -->
|
|
332
|
+
<LayerInput
|
|
333
|
+
{isActive}
|
|
334
|
+
target={inputMesh}
|
|
335
|
+
layerSize={{ width: display.resolution.x, height: display.resolution.y }}
|
|
336
|
+
onMouseDown={handleMouseDown}
|
|
337
|
+
onMouseMove={handleMouseMove}
|
|
338
|
+
onMouseUp={handleMouseUp}
|
|
339
|
+
onMouseLeave={handleMouseLeave}
|
|
340
|
+
onMouseEnter={handleMouseEnter}
|
|
341
|
+
/>
|
|
342
|
+
|
|
343
|
+
<!-- This quad is user for raycasting / mouse input detection. It is invisible -->
|
|
344
|
+
<T.Mesh
|
|
345
|
+
bind:ref={inputMesh}
|
|
346
|
+
scale={[display.resolution.x, display.resolution.y, 1]}
|
|
347
|
+
layers={isActive ? [SceneLayer.Input] : undefined}
|
|
348
|
+
>
|
|
349
|
+
<T.MeshBasicMaterial visible={false} />
|
|
350
|
+
<T.PlaneGeometry />
|
|
351
|
+
</T.Mesh>
|
|
352
|
+
|
|
353
|
+
<!-- Measurement Manager Component -->
|
|
354
|
+
<MeasurementManager
|
|
355
|
+
bind:this={measurementManager}
|
|
356
|
+
{props}
|
|
357
|
+
visible={isActive}
|
|
358
|
+
displayProps={display}
|
|
359
|
+
gridProps={grid}
|
|
360
|
+
{sceneRotation}
|
|
361
|
+
onFadeComplete={() => {
|
|
362
|
+
measurementIsFading = false;
|
|
363
|
+
}}
|
|
364
|
+
/>
|