Skip to content

Commit

Permalink
Merge branch 'dev' into 13-minimap
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrianSolberg committed Oct 27, 2025
2 parents 4a7af35 + 5f93b94 commit df56307
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 51 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Molloy Explorer is a 3D seabed visualization tool built with **Potree**. It allo

### Add point cloud data

Place the point cloud data (in Potree format with EPSG:4978 coordinates) in `public/pointclouds/data_converted`.
Place the point cloud data (in Potree format with EPSG:4978 coordinates) in `public/pointclouds`. Ensure the point cloud folder names match the paths specified in `src/config.js`, either by renaming the point cloud folders or by updating the paths.

**Note:** Point cloud files should not be committed to Git.

Expand Down
36 changes: 24 additions & 12 deletions src/AcceptedFiltering/threePanels.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ function insertSection({ headerId, headerText, listId }) {
}

accordionRefresh()

header.addEventListener('click', () => {
const $ = window.jQuery || window.$
if ($ && $.fn?.accordion && $(menu).data('uiAccordion')) return
if ($) {
const $p = $(panel)
$p.is(':visible') ? $p.slideUp(350) : $p.slideDown(350)
return
}
panel.style.display = panel.style.display === 'none' ? '' : 'none'
})
}

/**
Expand Down Expand Up @@ -181,10 +192,10 @@ function ensureElevationButton(hooks) {
}

/**
* Reconnects the Elevation slider label to reflect the current range.
* Assumes #sldHeightRange and #lblHeightRange exist.
* Sets up a elevation range slider for interactive updates
* @param {{onElevationRangeChange?:Function}} hooks
*/
function rebindElevationLabel() {
function setUpElevationSlider(hooks) {
const $ = window.jQuery || window.$
const slider = $ ? $('#sldHeightRange') : null
const label = byId('lblHeightRange')
Expand All @@ -194,26 +205,27 @@ function rebindElevationLabel() {
const low = slider.slider('values', 0)
const high = slider.slider('values', 1)
label.textContent = `${low.toFixed(2)} to ${high.toFixed(2)}`
hooks?.onElevationRangeChange([low, high])
}

slider.slider({ min: -10000, max: 0, values: [-10000, 0] })
slider.off('slide.custom slidestop.custom change.custom')
slider.on('slide.custom', 'slidestop.custom change.custom', update)
slider.on('slide.custom slidestop.custom change.custom', update)
update()
}

/**
* Moves Potree's Elevation container under the Elevation panel body and rebinds label.
* @returns {boolean} true if moved or already in place
*/
function moveElevationContainer() {
function moveElevationContainer(hooks) {
const { body } = ensurePanelScaffold('elevation2_list')
const src = byId('materials.elevation_container')
if (!body || !src) return false

if (src.parentNode !== body) {
body.appendChild(src)
rebindElevationLabel()
setUpElevationSlider(hooks)
accordionRefresh()
}
return true
Expand All @@ -229,7 +241,7 @@ function initElevationControls(hooks) {

const root = byId('potree_menu') || document.body
const obs = new MutationObserver(() => {
if (byId('materials.elevation_container')) moveElevationContainer()
if (byId('materials.elevation_container')) moveElevationContainer(hooks)
})
obs.observe(root, { childList: true, subtree: true })
}
Expand Down Expand Up @@ -362,7 +374,7 @@ async function ensurePanelCaptured(mode, hooks) {
selectCloudNode(hooks)
src = await waitForOrPoll('materials.elevation_container', 1800)
}
if (src) moveElevationContainer()
if (src) moveElevationContainer(hooks)
return
}
}
Expand Down Expand Up @@ -394,14 +406,14 @@ async function switchMode(mode, hook, hooksBag = {}) {
* @param {()=>'elevation'|'accepted'} activeGetter
* @returns {MutationObserver}
*/
function attachSelfHealing(activeGetter) {
function attachSelfHealing(activeGetter, hooks) {
const root = byId('potree_menu') || document.body
const obs = new MutationObserver(() => {
const mode = activeGetter()
if (mode === 'elevation') {
const src = byId('materials.elevation_container')
const { body } = ensurePanelScaffold('elevation2_list')
if (src && body && src.parentNode !== body) moveElevationContainer()
if (src && body && src.parentNode !== body) moveElevationContainer(hooks)
}
})
obs.observe(root, { childList: true, subtree: true })
Expand All @@ -412,7 +424,7 @@ function attachSelfHealing(activeGetter) {
/**
* Public entrypoint: builds Elevation and Accepted panels and wires behavior.
* @param {object} viewer Potree viewer (not used directly here but available to hooks)
* @param {{onActivateElevation?:Function, onActivateAccepted?:Function, selectCloudOnce?:Function}} hooks
* @param {{onActivateElevation?:Function, onActivateAccepted?:Function, selectCloudOnce?:Function, onElevationRangeChange?:Function}} hooks
*/
export function initThreePanels(viewer, hooks = {}) {
// Build sections
Expand All @@ -433,7 +445,7 @@ export function initThreePanels(viewer, hooks = {}) {
setActive('accepted')
)

attachSelfHealing(getActive)
attachSelfHealing(getActive, hooks)

// Default: auto-activate Elevation once
clickOnce('btnDoElevationControl')
Expand Down
8 changes: 5 additions & 3 deletions src/AnnotationControl/annotationPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,14 @@ export function initAnnotationsPanel(viewer) {

// Toggle collapse
header.addEventListener('click', () => {
if ($(menu).accordion && $(menu).data('uiAccordion')) return
if (window.jQuery) {
const $p = window.jQuery(panel)
const $ = window.jQuery || window.$
if ($ && $.fn?.accordion && $(menu).data('uiAccordion')) return
if ($) {
const $p = $(panel)
$p.is(':visible') ? $p.slideUp(350) : $p.slideDown(350)
return
}
panel.style.display = panel.style.display === 'none' ? '' : 'none'
})
targetContainer = panel.querySelector('#annotations_list')
}
Expand Down
27 changes: 26 additions & 1 deletion src/AnnotationControl/persistence.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
/**
* Annotation persistence.
* - Loads annotations from JSON and rebuilds the live tree.
* - Serializes live annotations (title, description, position, cameraPosition).
* - Autosaves to server (saveUrl) and localStorage on changes.
*
* Usage (minimal):
* const api = initAnnotationPersistence(viewer, { jsonUrl: '/annotations/annotations.json' })
* // api: { getAnnotationsJSON, saveToServer, snapshotToLocalStorage, loadFromJson, serializeGrouped }
*/

/**
* Initialize annotation persistence.
* @param {Potree.Viewer} viewer - Potree viewer with scene.annotations as root
* @param {Object} [options]
* @param {string} [options.jsonUrl] - URL to fetch/load annotations JSON
* @param {string} [options.saveUrl] - URL to POST saved JSON (defaults set automatically)
* @returns {{
* getAnnotationsJSON: function(): object,
* saveToServer: function(object=): Promise<object>,
* snapshotToLocalStorage: function(): void,
* loadFromJson: function(): Promise<void>,
* serializeGrouped: function(): object
* }}
*/
export function initAnnotationPersistence(viewer, options = {}) {
const jsonUrl = options.jsonUrl || '/annotations/annotations.json'
const defaultSaveUrl = (() => {
Expand Down Expand Up @@ -255,7 +280,7 @@ export function initAnnotationPersistence(viewer, options = {}) {
last = cur
debouncedSnapshot()
}
if (frames++ < 90) requestAnimationFrame(poll) // ~1.5s at 60fps
if (frames++ < 90) requestAnimationFrame(poll)
}
requestAnimationFrame(poll)
}
Expand Down
18 changes: 17 additions & 1 deletion src/config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
export const POTREE_POINTCLOUD_URL = '/pointclouds/data_converted/metadata.json'
export const POTREE_POINTCLOUD_URLS = [
'/pointclouds/cell_1/metadata.json',
'/pointclouds/cell_2/metadata.json',
'/pointclouds/cell_3/metadata.json',
'/pointclouds/cell_4/metadata.json',
'/pointclouds/cell_5/metadata.json',
'/pointclouds/cell_6/metadata.json',
'/pointclouds/cell_7/metadata.json',
'/pointclouds/cell_8/metadata.json',
'/pointclouds/cell_9/metadata.json',
'/pointclouds/cell_10/metadata.json',
'/pointclouds/cell_11/metadata.json',
'/pointclouds/cell_12/metadata.json',
'/pointclouds/cell_13/metadata.json',
'/pointclouds/cell_14/metadata.json',
'/pointclouds/cell_15/metadata.json'
]

export const POTREE_SETTINGS = {
edl: true,
Expand Down
4 changes: 2 additions & 2 deletions src/main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { POTREE_POINTCLOUD_URL, POTREE_SETTINGS } from './config.js'
import { POTREE_POINTCLOUD_URLS, POTREE_SETTINGS } from './config.js'
import { createCesiumViewer, loadCountryBorders } from './cesiumViewer.js'
import { createPotreeViewer } from './potreeViewer.js'
import { syncCameras } from './cameraSync.js'
Expand All @@ -18,7 +18,7 @@ async function init() {

window.potreeViewer = await createPotreeViewer(
'potree_render_area',
POTREE_POINTCLOUD_URL,
POTREE_POINTCLOUD_URLS,
POTREE_SETTINGS
)

Expand Down
Loading

0 comments on commit df56307

Please sign in to comment.