diff --git a/index.html b/index.html
index 2f98510..2c4e868 100644
--- a/index.html
+++ b/index.html
@@ -39,7 +39,7 @@
href="/src/MeasurementControl/measurementsPanel.css"
/>
-
+
diff --git a/src/AcceptedFiltering/threePanels.css b/src/Filter/filter.css
similarity index 75%
rename from src/AcceptedFiltering/threePanels.css
rename to src/Filter/filter.css
index e83b9e6..be09a06 100644
--- a/src/AcceptedFiltering/threePanels.css
+++ b/src/Filter/filter.css
@@ -1,10 +1,7 @@
/* ---------- Buttons (shared look) ---------- */
/* Reuse your accepted button style for all four */
#btnDoElevationControl,
-#doAcceptedFiltering,
-#btnTHU,
-#btnTVU,
-#btnTHUFilter {
+#doAcceptedFiltering {
display: flex;
width: 100%;
margin: 6px 0 10px;
@@ -22,55 +19,34 @@
}
#btnDoElevationControl:hover,
-#doAcceptedFiltering:hover,
-#btnTHU:hover,
-#btnTVU:hover,
-#btnTHUFilter:hover {
+#doAcceptedFiltering:hover {
background-color: #8f8f8f;
}
#btnDoElevationControl:active,
-#doAcceptedFiltering:active,
-#btnTHU:active,
-#btnTVU:active,
-#btnTHUFilter:active {
+#doAcceptedFiltering:active {
transform: scale(0.97);
background-color: #a8a6a6;
}
/* Optional: “active mode” outline if you toggle a class via JS */
#btnDoElevationControl.active,
-#doAcceptedFiltering.active,
-#btnTHU.active,
-#btnTVU.active,
-#btnTHUFilter:active {
+#doAcceptedFiltering.active {
outline: 2px solid #7ba8ff;
outline-offset: 1px;
}
-/* THU/TVU side-by-side */
-#thu_tvu_list .thu-tvu-row {
- display: flex;
- gap: 6px;
-}
-#thu_tvu_list .thu-tvu-row > button {
- flex: 1 1 50%;
- margin: 0;
-}
-
/* ---------- Panels / moved containers ---------- */
/* Keep Potree’s moved subtrees neat and full-width inside our panels */
-#elevation2_list [id='materials.elevation_container'],
-#thu_tvu_list [id='materials.extra_container'] {
+#elevation_list [id='materials.elevation_container'] {
width: 100%;
box-sizing: border-box;
padding: 6px 8px; /* small breathing room since we moved it out of Appearance */
}
/* Slight spacing inside our panel lists (under the button) */
-#elevation2_list,
-#accepted_list_host,
-#thu_tvu_list {
+#elevation_list,
+#accepted_list_host {
display: block;
padding: 4px 0;
}
@@ -101,16 +77,14 @@
/* ---------- Accordions / headers (light touch) ---------- */
/* Don’t fight jQuery-UI’s theme. Just small spacing adjustments. */
-#menu_elevation2 + .pv-menu-list,
-#menu_accepted + .pv-menu-list,
-#menu_thu_tvu + .pv-menu-list {
+#menu_elevation + .pv-menu-list,
+#menu_accepted + .pv-menu-list {
padding-top: 6px;
}
/* Optional: header label color alignment with dark UI */
-#menu_elevation2 span,
-#menu_accepted span,
-#menu_thu_tvu span {
+#menu_elevation span,
+#menu_accepted span {
color: #e6e6e6;
font-weight: 600;
letter-spacing: 0.2px;
diff --git a/src/AcceptedFiltering/threePanels.js b/src/Filter/filter.js
similarity index 93%
rename from src/AcceptedFiltering/threePanels.js
rename to src/Filter/filter.js
index 249df0f..40c5d56 100644
--- a/src/AcceptedFiltering/threePanels.js
+++ b/src/Filter/filter.js
@@ -1,7 +1,10 @@
-// Three Potree sidebar sections with buttons + panel bodies:
-// • Elevation → moves #materials.elevation_container into our Elevation body
-// • Accepted → custom UI fully defined here (no external module)
-
+/** Two Potree sidebar sections with buttons + panel bodies:
+ *
+ * • Elevation → moves #materials.elevation_container into our Elevation body
+ * Used for controlling the elevation gradient with a slider and altering between different gradient schemes
+ * • Accepted → custom UI fully defined here (no external module)
+ * Used for indicating which points/surveys are accepted as the seabed and which are not
+ */
const byId = (id) => document.getElementById(id)
/**
@@ -88,7 +91,7 @@ function ensurePanelScaffold(listId) {
* @param {'elevation'|'accepted'} key
*/
function showOnly(key) {
- const elevBody = byId('elevation2_list')?.querySelector('.panel-body')
+ const elevBody = byId('elevation_list')?.querySelector('.panel-body')
const accBody = byId('accepted_list_host')?.querySelector('.panel-body')
if (elevBody) elevBody.style.display = key === 'elevation' ? '' : 'none'
@@ -150,7 +153,7 @@ function selectCloudNode(hooks) {
* @param {number} pollEvery
* @returns {Promise}
*/
-async function waitForOrPoll(id, softMs = 1400, pollEvery = 120) {
+async function waitForOrPoll(id, softMs = 1400, pollEvery = 10) {
const start = performance.now()
while (performance.now() - start < softMs) {
const el = byId(id)
@@ -168,9 +171,9 @@ function createElevationPanel() {
insertSection({
headerId: 'menu_elevation',
headerText: 'Elevation Control',
- listId: 'elevation2_list'
+ listId: 'elevation_list'
})
- ensurePanelScaffold('elevation2_list')
+ ensurePanelScaffold('elevation_list')
}
/**
@@ -178,7 +181,7 @@ function createElevationPanel() {
* @param {{onActivateElevation?:Function}} hooks
*/
function ensureElevationButton(hooks) {
- const { btns } = ensurePanelScaffold('elevation2_list')
+ const { btns } = ensurePanelScaffold('elevation_list')
if (!btns || byId('btnDoElevationControl')) return
const btn = document.createElement('button')
@@ -219,7 +222,7 @@ function setUpElevationSlider(hooks) {
* @returns {boolean} true if moved or already in place
*/
function moveElevationContainer(hooks) {
- const { body } = ensurePanelScaffold('elevation2_list')
+ const { body } = ensurePanelScaffold('elevation_list')
const src = byId('materials.elevation_container')
if (!body || !src) return false
@@ -228,6 +231,7 @@ function moveElevationContainer(hooks) {
setUpElevationSlider(hooks)
accordionRefresh()
}
+ src.style.removeProperty('display')
return true
}
@@ -412,7 +416,7 @@ function attachSelfHealing(activeGetter, hooks) {
const mode = activeGetter()
if (mode === 'elevation') {
const src = byId('materials.elevation_container')
- const { body } = ensurePanelScaffold('elevation2_list')
+ const { body } = ensurePanelScaffold('elevation_list')
if (src && body && src.parentNode !== body) moveElevationContainer(hooks)
}
})
@@ -426,7 +430,7 @@ function attachSelfHealing(activeGetter, hooks) {
* @param {object} viewer Potree viewer (not used directly here but available to hooks)
* @param {{onActivateElevation?:Function, onActivateAccepted?:Function, selectCloudOnce?:Function, onElevationRangeChange?:Function}} hooks
*/
-export function initThreePanels(viewer, hooks = {}) {
+export function initFilterPanels(viewer, hooks = {}) {
// Build sections
initElevationControls(hooks)
initAcceptedControlsInline(hooks)
diff --git a/src/potreeViewer.js b/src/potreeViewer.js
index e710bd3..ab6c461 100644
--- a/src/potreeViewer.js
+++ b/src/potreeViewer.js
@@ -1,10 +1,7 @@
import { initAnnotationsPanel } from './AnnotationControl/annotationPanel.js'
import { initMeasurementsPanel } from './MeasurementControl/measurementsPanel.js'
import { initMiniMap } from './MiniMap/miniMap.js'
-import {
- initThreePanels,
- toggleAcceptedLegend
-} from './AcceptedFiltering/threePanels.js'
+import { initFilterPanels, toggleAcceptedLegend } from './Filter/filter.js'
import { ecef } from './config.js'
/**
@@ -90,7 +87,7 @@ export async function createPotreeViewer(
})
}
- initThreePanels(viewer, {
+ initFilterPanels(viewer, {
onActivateElevation: () => {
const $ = window.jQuery || window.$
const slider = $ ? $('#sldHeightRange') : null
@@ -208,6 +205,9 @@ function overrideShaderForGradient(pc) {
}
}
+// Prevent overlapping scroll freezing when activating filters quickly
+let suppressionActive = false
+
/**
* Freeze all scrollable ancestors of a given root during an action (e.g., jsTree select)
* Need this so that when Elevation control or Accepted filter is activated the sidebar doesn't scroll down to the Scene panel
@@ -215,6 +215,13 @@ function overrideShaderForGradient(pc) {
* @param {*} action
*/
function suppressSidebarAutoScroll(action, holdMs = 350) {
+ // --- Re-entrancy guard ---
+ if (suppressionActive) {
+ action()
+ return
+ }
+ suppressionActive = true
+
// anchor on the tree root; fall back to the menu if not found
const treeRoot =
document.querySelector('#scene_objects') ||
@@ -231,8 +238,10 @@ function suppressSidebarAutoScroll(action, holdMs = 350) {
if (canScroll) scrollers.push(el)
el = el.parentElement
}
+
if (!scrollers.length) {
action()
+ suppressionActive = false
return
}
@@ -264,20 +273,19 @@ function suppressSidebarAutoScroll(action, holdMs = 350) {
const origFocus = HTMLElement.prototype.focus
HTMLElement.prototype.focus = function (opts) {
- // force preventScroll behavior even if caller didn't ask
try {
origFocus.call(this, { ...(opts || {}), preventScroll: true })
} catch {
origFocus.call(this)
}
}
+
try {
action()
} finally {
const until = performance.now() + holdMs
const restoreLoop = () => {
- // keep snapping until the selection animations/handlers settle
states.forEach(({ el, top, left }) => {
el.scrollTop = top
el.scrollLeft = left
@@ -300,8 +308,11 @@ function suppressSidebarAutoScroll(action, holdMs = 350) {
if (h) el.removeEventListener('scroll', h)
el.style.overflow = overflow
})
+ // --- Release the guard ---
+ suppressionActive = false
}
}
+
requestAnimationFrame(restoreLoop)
}
}