From a7ab9cd41bbc044897caf9cc6b5965d47412588a Mon Sep 17 00:00:00 2001 From: AdrianSolberg Date: Sun, 26 Oct 2025 17:36:48 +0100 Subject: [PATCH 1/4] feat(#13): set up minimap --- src/MiniMap/miniMap.js | 92 ++++++++++++++++++++++++++++++++++++++++++ src/potreeViewer.js | 4 +- 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/MiniMap/miniMap.js diff --git a/src/MiniMap/miniMap.js b/src/MiniMap/miniMap.js new file mode 100644 index 0000000..7604489 --- /dev/null +++ b/src/MiniMap/miniMap.js @@ -0,0 +1,92 @@ +export function initMiniMap(viewer) { + const map = viewer.mapView.map + const layers = map.getLayers() + + replaceMiniMapLayers(layers) + + overrideMapViewUpdate(viewer) + + // Transform minimap center [lon, lat] from EPSG:4326 to EPSG:3857 + const center = proj4('EPSG:4326', 'EPSG:3857', [2, 69]) + map.getView().setCenter(center) +} + +function replaceMiniMapLayers(layers) { + // Remove the old Open Street Map layer + const oldOSMLayer = layers.item(0) + layers.remove(oldOSMLayer) + + // Add new offline GeoJSON layer + const newGeojsonLayer = new ol.layer.Vector({ + source: new ol.source.Vector({ + url: '/data/geo/world_simplified.geojson', + format: new ol.format.GeoJSON() + }) + }) + layers.insertAt(0, newGeojsonLayer) + + // Remove the extent layer + const extentLayer = layers.item(6) + layers.remove(extentLayer) +} + +function overrideMapViewUpdate(viewer) { + const Vector3 = THREE.Vector3 + const Vector2 = THREE.Vector2 + viewer.mapView.update = function (delta) { + if (!this.sceneProjection) { + return + } + + let pm = $('#potree_map') + + if (!this.enabled) { + return + } + + let mapSize = this.map.getSize() + let resized = pm.width() !== mapSize[0] || pm.height() !== mapSize[1] + if (resized) { + this.map.updateSize() + } + + let camera = this.viewer.scene.getActiveCamera() + + let scale = this.map.getView().getResolution() + let campos = camera.position + let camdir = camera.getWorldDirection(new Vector3()) + let sceneLookAt = camdir + .clone() + .multiplyScalar(30 * scale) + .add(campos) + let geoPos = camera.position + let geoLookAt = sceneLookAt + + // Include z-coordinate to handle EPSG:4978 properly + let mapPos = new Vector2().fromArray( + this.toMap.forward([geoPos.x, geoPos.y, geoPos.z]) + ) + let mapLookAt = new Vector2().fromArray( + this.toMap.forward([geoLookAt.x, geoLookAt.y, geoLookAt.z]) + ) + + // Reverse direction so pointer faces correct way + let mapDir = new Vector2().subVectors(mapPos, mapLookAt).normalize() + + mapLookAt = mapPos.clone().add(mapDir.clone().multiplyScalar(30 * scale)) + let mapLength = mapPos.distanceTo(mapLookAt) + let mapSide = new Vector2(-mapDir.y, mapDir.x) + + let p1 = mapPos.toArray() + let p2 = mapLookAt + .clone() + .sub(mapSide.clone().multiplyScalar(0.3 * mapLength)) + .toArray() + let p3 = mapLookAt + .clone() + .add(mapSide.clone().multiplyScalar(0.3 * mapLength)) + .toArray() + + this.gCamera.setCoordinates([p1, p2, p3, p1]) + } +} diff --git a/src/potreeViewer.js b/src/potreeViewer.js index 3d80cf0..b128769 100644 --- a/src/potreeViewer.js +++ b/src/potreeViewer.js @@ -1,5 +1,6 @@ import { initAnnotationsPanel } from './AnnotationControl/annotationPanel.js' import { initMeasurementsPanel } from './MeasurementControl/measurementsPanel.js' +import { initMiniMap } from './MiniMap/miniMap.js' import { initThreePanels, toggleAcceptedLegend @@ -64,6 +65,7 @@ export async function createPotreeViewer(containerId, pointcloudUrl, settings) { initMeasurementsPanel(viewer) initAnnotationsPanel(viewer) + initMiniMap(viewer) }) const e = await Potree.loadPointCloud(pointcloudUrl) @@ -89,7 +91,7 @@ export async function createPotreeViewer(containerId, pointcloudUrl, settings) { // Initialize camera position and target point (manually chosen) viewer.scene.view.setView( - [3961574.044, 1494736.334, 8348318.575], // Initial camera position + [4094989.813, 59057.337, 8363694.681], // Initial camera position [1500922.651, 510673.03, 5427934.722] // Initial target point ) From c4f9d26a204497452d348cf2aa4a4148445e1a5d Mon Sep 17 00:00:00 2001 From: AdrianSolberg Date: Sun, 26 Oct 2025 17:46:19 +0100 Subject: [PATCH 2/4] docs(#13): add function documentation --- src/MiniMap/miniMap.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/MiniMap/miniMap.js b/src/MiniMap/miniMap.js index 7604489..dacd026 100644 --- a/src/MiniMap/miniMap.js +++ b/src/MiniMap/miniMap.js @@ -1,3 +1,8 @@ +/** + * Initializes the Potree minimap to work with offline map and EPSG:4978 coordinates. + * + * @param {Potree.Viewer} viewer - The Potree viewer instance + */ export function initMiniMap(viewer) { const map = viewer.mapView.map const layers = map.getLayers() @@ -11,6 +16,12 @@ export function initMiniMap(viewer) { map.getView().setCenter(center) } +/** + * Replaces default Open Street Map layer with custom GeoJSON in order for it to work offline. + * Also removes the extent layer. + * + * @param {ol.Collection} layers - Collection of OpenLayers layers + */ function replaceMiniMapLayers(layers) { // Remove the old Open Street Map layer const oldOSMLayer = layers.item(0) @@ -30,6 +41,11 @@ function replaceMiniMapLayers(layers) { layers.remove(extentLayer) } +/** + * Overrides the minimap pointer update logic to use 3D coordinates and correct direction. + * + * @param {Potree.Viewer} viewer - The Potree viewer instance + */ function overrideMapViewUpdate(viewer) { const Vector3 = THREE.Vector3 const Vector2 = THREE.Vector2 From 63ee004d7cbce7da5fbbca7ef733630b11d282e9 Mon Sep 17 00:00:00 2001 From: AdrianSolberg Date: Sun, 26 Oct 2025 20:09:43 +0100 Subject: [PATCH 3/4] refactor(#13): remove unused tools --- src/MiniMap/miniMap.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/MiniMap/miniMap.js b/src/MiniMap/miniMap.js index dacd026..3403379 100644 --- a/src/MiniMap/miniMap.js +++ b/src/MiniMap/miniMap.js @@ -4,11 +4,14 @@ * @param {Potree.Viewer} viewer - The Potree viewer instance */ export function initMiniMap(viewer) { + if (!viewer.mapView) return const map = viewer.mapView.map const layers = map.getLayers() replaceMiniMapLayers(layers) + removeTileTools(map) + overrideMapViewUpdate(viewer) // Transform minimap center [lon, lat] from EPSG:4326 to EPSG:3857 @@ -41,6 +44,22 @@ function replaceMiniMapLayers(layers) { layers.remove(extentLayer) } +/** + * Removes the tools for downloading and showing/hiding tiles, denoted D and T in the minimap. + * + * @param {ol.Map} map - The OpenLayers map instance + */ +function removeTileTools(map) { + map.getControls().forEach((control) => { + if ( + control.constructor && + control.constructor.name === 'DownloadSelectionControl' + ) { + map.removeControl(control) + } + }) +} + /** * Overrides the minimap pointer update logic to use 3D coordinates and correct direction. * From 4a7af3504f34385487346da269abff795e02c34e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marie=20Wahlstr=C3=B8m?= Date: Mon, 27 Oct 2025 09:22:09 +0100 Subject: [PATCH 4/4] feat(#13): :lipstick: Made a background for the minimap --- src/MiniMap/miniMap.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/MiniMap/miniMap.js b/src/MiniMap/miniMap.js index 3403379..4420c04 100644 --- a/src/MiniMap/miniMap.js +++ b/src/MiniMap/miniMap.js @@ -14,11 +14,38 @@ export function initMiniMap(viewer) { overrideMapViewUpdate(viewer) + setMiniMapBackground(map, '#d6ecff') + // Transform minimap center [lon, lat] from EPSG:4326 to EPSG:3857 const center = proj4('EPSG:4326', 'EPSG:3857', [2, 69]) map.getView().setCenter(center) } +/** + * Sets the background color for the Minimap so that it is not seethrough. + * Makes it easier to get an overview when deep in a survey. + * + * @param {*} map + * @param {*} color + */ +function setMiniMapBackground(map, color) { + // OL ≥ 6.5 supports a map background property + try { + map.set && map.set('background', color) + } catch {} + + // Fallbacks that work on older OL + Potree + const viewport = map.getViewport && map.getViewport() + if (viewport) viewport.style.background = color + + const target = map.getTargetElement && map.getTargetElement() + if (target) target.style.background = color + + // As a last resort, paint the canvas background + const canvas = viewport && viewport.querySelector('canvas') + if (canvas) canvas.style.background = color +} + /** * Replaces default Open Street Map layer with custom GeoJSON in order for it to work offline. * Also removes the extent layer.