Skip to content

Commit 122ab3d

Browse files
committed
Update splat-overlay, splat, and mode-toggle
1 parent 7828c76 commit 122ab3d

3 files changed

Lines changed: 10 additions & 117 deletions

File tree

src/splat-overlay.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ class SplatOverlay extends Element {
190190
return splat &&
191191
events.invoke('camera.splatSize') > 0 &&
192192
scene.camera.renderOverlays &&
193-
events.invoke('camera.overlay') &&
194193
events.invoke('camera.mode') === 'centers';
195194
}
196195
}

src/splat.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,14 +323,14 @@ class Splat extends Element {
323323
const isSceneSelection = events.invoke('splatSelection') === this;
324324
const hasSelectedGaussians = this.numSelected > 0;
325325
const renderOverlays = this.scene.camera.renderOverlays;
326-
const selected = renderOverlays && (isSceneSelection || hasSelectedGaussians);
326+
const hasSelection = isSceneSelection || hasSelectedGaussians;
327+
const selected = renderOverlays && hasSelection;
327328
const cameraMode = events.invoke('camera.mode');
328-
const cameraOverlay = events.invoke('camera.overlay');
329329

330-
// configure rings rendering
330+
// configure rings rendering - rings show whenever there's a selection, regardless of overlay
331331
const material = this.entity.gsplat.instance.material;
332332
material.setParameter('outlineMode', events.invoke('view.outlineSelection') ? 1 : 0);
333-
material.setParameter('ringSize', (selected && cameraOverlay && cameraMode === 'rings') ? 0.04 : 0);
333+
material.setParameter('ringSize', (hasSelection && cameraMode === 'rings') ? 0.04 : 0);
334334

335335
// configure colors
336336
const selectedClr = events.invoke('selectedClr');

src/ui/mode-toggle.ts

Lines changed: 6 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { localize } from './localization';
55
import centersSvg from './svg/centers.svg';
66
import chevronDownSvg from './svg/chevron-down.svg';
77
import chevronUpSvg from './svg/chevron-up.svg';
8-
import circleSvg from './svg/circle.svg';
98
import ringsSvg from './svg/rings.svg';
9+
import circleSvg from './svg/circle.svg';
1010
import { Tooltips } from './tooltips';
1111

1212
const createSvg = (svgString: string) => {
@@ -134,119 +134,9 @@ class ModeToggle extends Container {
134134

135135
this.dom.addEventListener('pointerdown', (event) => {
136136
event.stopPropagation();
137+
dropdownMenu.hidden = !dropdownMenu.hidden;
137138
});
138139

139-
// ---- Long-press / drag-to-select interaction ----
140-
// Hold down on mode-toggle → after 200ms (or right-drag ≥20px) → open
141-
// dropdown → drag to an item → release to select that mode.
142-
let longPressTimer: ReturnType<typeof setTimeout> | null = null;
143-
let isLongPressDrag = false;
144-
let dragStartX = 0;
145-
const SWIPE_THRESHOLD = 20;
146-
147-
const modeActions: Array<{ element: HTMLElement; mode: string }> = [
148-
{ element: splatOption.dom, mode: 'splat' },
149-
{ element: centersOption.dom, mode: 'centers' },
150-
{ element: ringsOption.dom, mode: 'rings' }
151-
];
152-
153-
const findModeItemAtPoint = (x: number, y: number) => {
154-
const el = document.elementFromPoint(x, y);
155-
if (!el) return null;
156-
for (const item of modeActions) {
157-
if (item.element === el || item.element.contains(el)) {
158-
return item;
159-
}
160-
}
161-
return null;
162-
};
163-
164-
const cleanupDrag = () => {
165-
isLongPressDrag = false;
166-
dropdownMenu.hidden = true;
167-
// eslint-disable-next-line no-use-before-define
168-
document.removeEventListener('mouseup', onDocMouseUpCapture, true);
169-
// eslint-disable-next-line no-use-before-define
170-
document.removeEventListener('mousemove', onDocMouseMove, true);
171-
for (const item of modeActions) {
172-
item.element.classList.remove('longpress-hover');
173-
}
174-
};
175-
176-
const onDocMouseMove = (e: MouseEvent) => {
177-
const hovered = findModeItemAtPoint(e.clientX, e.clientY);
178-
for (const item of modeActions) {
179-
item.element.classList.toggle('longpress-hover', item === hovered);
180-
}
181-
};
182-
183-
const onDocMouseUpCapture = (e: MouseEvent) => {
184-
if (e.button !== 0) return;
185-
const hit = findModeItemAtPoint(e.clientX, e.clientY);
186-
if (hit) {
187-
events.fire('camera.setMode', hit.mode);
188-
}
189-
cleanupDrag();
190-
};
191-
192-
const startDrag = () => {
193-
if (longPressTimer) {
194-
clearTimeout(longPressTimer);
195-
longPressTimer = null;
196-
}
197-
isLongPressDrag = true;
198-
dropdownMenu.hidden = false;
199-
document.addEventListener('mouseup', onDocMouseUpCapture, true);
200-
document.addEventListener('mousemove', onDocMouseMove, true);
201-
};
202-
203-
this.dom.addEventListener('mousedown', (e) => {
204-
if (e.button !== 0) return;
205-
isLongPressDrag = false;
206-
dragStartX = e.clientX;
207-
longPressTimer = setTimeout(startDrag, 200);
208-
});
209-
210-
this.dom.addEventListener('mousemove', (e) => {
211-
if (isLongPressDrag || !longPressTimer) return;
212-
if (e.clientX - dragStartX >= SWIPE_THRESHOLD) {
213-
startDrag();
214-
// highlight item under cursor after popup shown
215-
const hovered = findModeItemAtPoint(e.clientX, e.clientY);
216-
for (const item of modeActions) {
217-
item.element.classList.toggle('longpress-hover', item === hovered);
218-
}
219-
}
220-
});
221-
222-
this.dom.addEventListener('mouseup', (e) => {
223-
if (e.button !== 0) return;
224-
if (isLongPressDrag) return;
225-
if (longPressTimer) {
226-
clearTimeout(longPressTimer);
227-
longPressTimer = null;
228-
// Short click: toggle dropdown
229-
dropdownMenu.hidden = !dropdownMenu.hidden;
230-
}
231-
});
232-
233-
this.dom.addEventListener('mouseleave', () => {
234-
if (longPressTimer) {
235-
clearTimeout(longPressTimer);
236-
longPressTimer = null;
237-
}
238-
});
239-
240-
// Click outside closes dropdown (skip during drag)
241-
document.addEventListener('pointerdown', (e) => {
242-
if (isLongPressDrag) return;
243-
if (!this.dom.contains(e.target as Node)) {
244-
dropdownMenu.hidden = true;
245-
}
246-
});
247-
248-
// ---- Click handlers for dropdown items (for normal click users) ----
249-
250140
centersOption.dom.addEventListener('pointerdown', (event) => {
251141
event.stopPropagation();
252142
events.fire('camera.setMode', 'centers');
@@ -265,6 +155,10 @@ class ModeToggle extends Container {
265155
dropdownMenu.hidden = true;
266156
});
267157

158+
document.addEventListener('pointerdown', () => {
159+
dropdownMenu.hidden = true;
160+
});
161+
268162
events.on('camera.mode', (mode: string) => {
269163
this.class[mode === 'centers' ? 'add' : 'remove']('centers-mode');
270164
this.class[mode === 'rings' ? 'add' : 'remove']('rings-mode');

0 commit comments

Comments
 (0)