diff --git a/index.html b/index.html
index 5334e6b..eb87702 100644
--- a/index.html
+++ b/index.html
@@ -3,22 +3,12 @@
-
+
-
-
-
Info
-
![Standortbild]()
-
-
-
-
-
-
Bitte wählen Sie eine Punktwolke aus.
-
-
-
-
+
+
+
Info
+
![Standortbild]()
+
+
+
+
+
+
Bitte wählen Sie eine Punktwolke aus.
+
+
+
diff --git a/main.js b/main.js
index f1f33df..3cfe068 100644
--- a/main.js
+++ b/main.js
@@ -1,68 +1,68 @@
+
import maplibregl from "maplibre-gl";
import proj4 from "proj4";
import * as THREE from "three";
-import { LidarControl } from "maplibre-gl-lidar";
+import { LidarControl } from "maplibre-gl-lidar";
import "maplibre-gl/dist/maplibre-gl.css";
import "maplibre-gl-lidar/style.css";
+// UTM Zone 32N für Koordinatentransformation registrieren
proj4.defs("EPSG:25832", "+proj=utm +zone=32 +ellps=GRS80 +units=m +no_defs");
-
-// Koordinaten des Obernkirchener Sandstein
+// Koordinaten des Obernkirchener Sandstein (Kartenmittelpunkt)
const center = [9.209116842757239, 52.26520546238239];
-// die Grundkarte
+// Zustandsvariablen
+let currentPointCloud = null; // aktuell geladene Potree-Punktwolke
+let isVisible = true; // Punktwolke sichtbar?
+let currentRenderer = "deckgl"; // Default-Renderer deck.gl"
+let currentColorMode = "rgb"; // Farbmodus: "rgb" oder "elevation"
+let currentPointSize = Number(document.getElementById("pointSizeSlider").value);
+let currentPointcloudKey = null; // ausgewählte Punktwolke
+let lidarControl = null; // Deck.gl LidarControl-Instanz
+var quality = "medium"; // Qualitätsstufe
+
+
+//-------------------------------- Karten-Initialisierung --------------------------------------------------
+// Grundkarte: OpenFreeMap hell
const map = new maplibregl.Map({
- container: 'map',
- style: "https://tiles.openfreemap.org/styles/bright",
- center: center,
- zoom: 17,
- maxZoom: 24,
+ container: "map",
+ style: "https://tiles.openfreemap.org/styles/bright",
+ center: center,
+ zoom: 17,
+ maxZoom: 24,
});
// Karten-Bedienelemente
-map.addControl(new maplibregl.NavigationControl({
+map.addControl(
+ new maplibregl.NavigationControl({
visualizePitch: true,
showZoom: true,
- showCompass: true
-}));
-
-let currentPointCloud = null;
-let isVisible = true;
-let currentRenderer='deckgl';
-let currentColorMode='rgb';
-let currentPointSize=Number(document.getElementById("pointSizeSlider").value);
-let currentPointcloudKey = null;
-let lidarControl=null;
-var quality = 'medium';
+ showCompass: true,
+ }),
+);
-// WICHTIG: Layer/Controls immer erst im 'load'-Event der Karte hinzufügen
-map.on('load', () => {
- lidarControl = new LidarControl({
- title: 'Mein LiDAR-Viewer',
- collapsed: false,
- pointSize: 2,
- colorScheme: 'rgb', // 'elevation' oder 'rgb'
- pointBudget: 3000000,
- maxRequests: 32,
- pickable: false,
- });
+// Karten Load-Event: LidarControl anlegen, JSON-Datei laden
+map.on("load", () => {
+ lidarControl = new LidarControl({
+ title: "LiDAR-Viewer",
+ collapsed: false,
+ pointSize: 2,
+ colorScheme: "rgb", // 'elevation' oder 'rgb'
+ pointBudget: 3000000,
+ maxRequests: 32,
+ pickable: false,
+ });
- // COPC-Datei laden
- const selectBox=document.querySelector('select[name="pointcloud"]');
- if (selectBox && selectBox.value){
- currentPointcloudKey=selectBox.value;
- loadCurrentPointCloud();
- }
- loadInfoJSON();
+ loadInfoJSON();
});
//---------------Potree Eigenschaften--------------------------
var pointSize = document.getElementById("pointSizeSlider").value;
const elRenderArea = document.getElementById("potree_render_area");
-const viewer = new Potree.Viewer(elRenderArea, {noDragAndDrop: true});
+const viewer = new Potree.Viewer(elRenderArea, { noDragAndDrop: true });
viewer.setEDLEnabled(false);
viewer.setFOV(60);
viewer.setMinNodeSize(pointSize);
@@ -70,563 +70,613 @@ viewer.setBackground("none");
viewer.orbitControls.enabled = false;
viewer.fpControls.enabled = false;
viewer.deviceControls.enabled = false;
-elRenderArea.style.display='none';
-viewer.setPointBudget(3000000)
+elRenderArea.style.display = "none";
+viewer.setPointBudget(3000000);
+
+//-------------------------- LIDARCONTROL (DECK.GL) NEU AUFBAUEN ----------------------------------------
+// entfernt das bestehende LidarControl und erzeugt es mit den aktuellen Einstellungen neu
function resetLidarControl() {
- if (!lidarControl) return;
- try {
- map.removeControl(lidarControl);
- } catch(e) {}
- lidarControl = null;
+ if (!lidarControl)
+ return;
+ try {
+ map.removeControl(lidarControl);
+ } catch (e) {}
+ lidarControl = null;
- lidarControl = new LidarControl({
- title: 'Mein LiDAR-Viewer',
- collapsed: false,
- pointSize: currentPointSize > 0 ? currentPointSize : 2,
- colorScheme: currentColorMode === 'rgb' ? 'rgb' : 'elevation',
- pointBudget: 3000000,
- maxRequests: 32,
- pickable: false
- });
- map.addControl(lidarControl, 'top-right');
+ lidarControl = new LidarControl({
+ title: "LiDAR-Viewer",
+ collapsed: false,
+ pointSize: currentPointSize > 0 ? currentPointSize : 2,
+ colorScheme: currentColorMode === "rgb" ? "rgb" : "elevation",
+ pointBudget: 3000000,
+ maxRequests: 32,
+ pickable: false,
+ });
+ map.addControl(lidarControl, "top-right");
}
+//-------------- PUNKTWOLKEN-DATENQUELLEN (Pfade je Renderer-Format) - aktuell auf Server der Jade-HS --------------------
+
// Punktwolkendaten im Potree-Format
function getPointCloudFilesPOTREE() {
- return {
- first: `http://ar2350.web-01.fbbgg.hs-woe.de/Punktwolken%20konvertiert%20potree%20Format/sp1_${quality}/metadata.json`,
- second: `http://ar2350.web-01.fbbgg.hs-woe.de/Punktwolken%20konvertiert%20potree%20Format/sp2_${quality}/metadata.json`,
- third: `http://ar2350.web-01.fbbgg.hs-woe.de/Punktwolken%20konvertiert%20potree%20Format/sp3_${quality}/metadata.json`,
- };
+ return {
+ first: `http://ar2350.web-01.fbbgg.hs-woe.de/Punktwolken%20konvertiert%20potree%20Format/sp1_${quality}/metadata.json`,
+ second: `http://ar2350.web-01.fbbgg.hs-woe.de/Punktwolken%20konvertiert%20potree%20Format/sp2_${quality}/metadata.json`,
+ third: `http://ar2350.web-01.fbbgg.hs-woe.de/Punktwolken%20konvertiert%20potree%20Format/sp3_${quality}/metadata.json`,
+ };
}
// Punktwolkendaten im COPC (Cloud Optimised Point Cloud)-Format für deck.gl
function getPointCloudFilesCOPC() {
- return {
- first: `http://ar2350.web-01.fbbgg.hs-woe.de/copc%20Daten/sp1_${quality}.copc.laz`,
- second: `http://ar2350.web-01.fbbgg.hs-woe.de/copc%20Daten/sp2_${quality}.copc.laz`,
- third: `http://ar2350.web-01.fbbgg.hs-woe.de/copc%20Daten/sp3_${quality}.copc.laz`,
- };
+ return {
+ first: `http://ar2350.web-01.fbbgg.hs-woe.de/copc%20Daten/sp1_${quality}.copc.laz`,
+ second: `http://ar2350.web-01.fbbgg.hs-woe.de/copc%20Daten/sp2_${quality}.copc.laz`,
+ third: `http://ar2350.web-01.fbbgg.hs-woe.de/copc%20Daten/sp3_${quality}.copc.laz`,
+ };
}
-function loadCurrentPointCloud() {
- if (!currentPointcloudKey) return;
- if (currentRenderer === 'deckgl') {
- loadDeckGL(getPointCloudFilesCOPC()[currentPointcloudKey]);
- } else {
- loadPointCloud(getPointCloudFilesPOTREE()[currentPointcloudKey]);
- }
+//---------------------------- PUNKTWOLKEN LADEN (je nach aktivem Renderer) -------------------------------------
+
+// wählt automatisch Potree- oder Deck.gl-Renderer und lädt die Punktwolke
+function loadPointCloud() {
+ if (!currentPointcloudKey)
+ return;
+ if (currentRenderer === "deckgl") {
+ loadDeckGL(getPointCloudFilesCOPC()[currentPointcloudKey]);
+ } else {
+ loadPointCloudPotree(getPointCloudFilesPOTREE()[currentPointcloudKey]);
+ }
}
+
+//---------------------- Punktwolken laden über den deck.gl-Renderer ----------------------
function loadDeckGL(path) {
- if (!lidarControl || !path) return;
- resetLidarControl();
- lidarControl.loadPointCloudStreaming(path);
- setTimeout(() => applyDeckGLSettings(), 500);
+ if (!lidarControl || !path)
+ return;
+ resetLidarControl();
+ lidarControl.loadPointCloudStreaming(path);
+ setTimeout(() => applyDeckGLSettings(), 500);
}
+// Punktgröße, Farbschema und Colormap auf LidarControl anwenden
function applyDeckGLSettings() {
- if (!lidarControl) return;
- try {
- lidarControl.setPointSize(currentPointSize > 0 ? currentPointSize : 2);
- lidarControl.setColorScheme(currentColorMode === 'rgb' ? 'rgb' : 'elevation');
- lidarControl.setColormap('jet');
- //lidarControl.setPointBudget(3000000);
- } catch(e) { console.warn("LidarControl API:", e); }
+ if (!lidarControl)
+ return;
+ try {
+ lidarControl.setPointSize(currentPointSize > 0 ? currentPointSize : 2);
+ lidarControl.setColorScheme(currentColorMode === "rgb" ? "rgb" : "elevation",);
+ lidarControl.setColormap("jet");
+ } catch (e) {}
}
+
+//------------------------- Renderer zwischen deck.gl und potree umstellen -----------------------------------
function switchRenderer(renderer) {
- currentRenderer = renderer;
- const slider = document.getElementById("pointSizeSlider");
- if (renderer === 'deckgl') {
- elRenderArea.style.display = 'none';
- if (currentPointCloud) currentPointCloud.visible = false;
-
- currentPointSize = 2;
- slider.min = 1;
- slider.max = 10;
- slider.value = 2;
- if (lidarControl && currentPointcloudKey) loadDeckGL(getPointCloudFilesCOPC()[currentPointcloudKey]);
- document.getElementById('rendererToggle').dataset.active = 'deckgl';
- document.getElementById('rendererLabel').textContent = 'Renderer: Deck.gl';
- } else {
- resetLidarControl();
- elRenderArea.style.display = 'block';
-
- currentPointSize = 0;
- slider.min = 0;
- slider.max = 1000;
- slider.value = 0;
-
- if (currentPointcloudKey) loadPointCloud(getPointCloudFilesPOTREE()[currentPointcloudKey]);
- document.getElementById('rendererToggle').dataset.active = 'potree';
- document.getElementById('rendererLabel').textContent = 'Renderer: Potree';
+ currentRenderer = renderer;
+ const slider = document.getElementById("pointSizeSlider");
+ if (renderer === "deckgl") {
+ elRenderArea.style.display = "none";
+ if (currentPointCloud){
+ currentPointCloud.visible = false;
}
- applyVisibility();
+ currentPointSize = 2;
+ slider.min = 1;
+ slider.max = 10;
+ slider.value = 2;
+ if (lidarControl && currentPointcloudKey){
+ loadDeckGL(getPointCloudFilesCOPC()[currentPointcloudKey]);
+ }
+ document.getElementById("rendererToggle").dataset.active = "deckgl";
+ document.getElementById("rendererLabel").textContent = "Renderer: Deck.gl";
+ } else {
+ resetLidarControl();
+ elRenderArea.style.display = "block";
+
+ currentPointSize = 0;
+ slider.min = 0;
+ slider.max = 1000;
+ slider.value = 0;
+
+ if (currentPointcloudKey){
+ loadPointCloudPotree(getPointCloudFilesPOTREE()[currentPointcloudKey]);
+ }
+ document.getElementById("rendererToggle").dataset.active = "potree";
+ document.getElementById("rendererLabel").textContent = "Renderer: Potree";
+ }
+ applyVisibility();
}
+
+// Sichtbarkeit der Punktwolke je nach aktivem Renderer setzen
function applyVisibility() {
-
- if (currentRenderer === 'potree' && currentPointCloud) {
- currentPointCloud.visible = isVisible;
- }
-
- if (currentRenderer === 'deckgl') {
-
- lidarControl.setPointSize(isVisible ? 2 : 0);
- }
+ if (currentRenderer === "potree" && currentPointCloud) {
+ currentPointCloud.visible = isVisible;
+ }
+
+ if (currentRenderer === "deckgl") {
+ // Trick: Punktgröße auf 0 setzen
+ lidarControl.setPointSize(isVisible ? 2 : 0);
+ }
}
-
+// Farbmodus (rgb/elevation) auf die Potree-Punktwolke anwenden
function applyColorModePotree() {
- if (!currentPointCloud) return;
- let mat = currentPointCloud.material;
- mat.activeAttributeName = currentColorMode === 'rgb' ? "rgba" : "elevation";
- viewer.renderer.resetState();
- viewer.render();
- map.triggerRepaint();
+ if (!currentPointCloud)
+ return;
+ let mat = currentPointCloud.material;
+ mat.activeAttributeName = currentColorMode === "rgb" ? "rgba" : "elevation";
+ viewer.renderer.resetState();
+ viewer.render();
+ map.triggerRepaint();
}
+
+// Farbmodus je nach aktivem Renderer anwenden
function applyColorMode() {
- if (currentRenderer === 'potree') { applyColorModePotree(); }
- else { applyDeckGLSettings(); }
+ if (currentRenderer === "potree") {
+ applyColorModePotree();
+ } else {
+ applyDeckGLSettings();
+ }
}
+
+//-------------------- INFO-JSON laden (Texte/Bilder zu den Punktwolken) -----------------
function loadInfoJSON() {
- fetch("info.json")
- .then(r => r.json())
- .then(data => { pointCloudInfo = data; })
- .catch(e => console.error("Fehler beim Laden der JSON:", e));
+ fetch("info.json").then((r) => r.json()).then((data) => {
+ pointCloudInfo = data;
+ })
+ .catch((e) => console.error("Fehler beim Laden der JSON:", e));
}
+//------------------------ Punktwolke im Potree Format laden -----------------------------
+function loadPointCloudPotree(path) {
+ viewer.scene.view.yaw = 0;
+ viewer.scene.view.pitch = 0;
-//------------------------lädt Punktwolke im Potree Format-----------------------------
-function loadPointCloud(path) {
- viewer.scene.view.yaw = 0;
- viewer.scene.view.pitch = 0;
-
- if (currentPointCloud) {
- const index = viewer.scene.pointclouds.indexOf(currentPointCloud);
- if (index !== -1) viewer.scene.pointclouds.splice(index, 1);
- if (currentPointCloud.parent) currentPointCloud.parent.remove(currentPointCloud);
- currentPointCloud = null;
- viewer.render();
+ // vorhandene Punktwolke aus der Szene entfernen
+ if (currentPointCloud) {
+ const index = viewer.scene.pointclouds.indexOf(currentPointCloud);
+ if (index !== -1)
+ viewer.scene.pointclouds.splice(index, 1);
+ if (currentPointCloud.parent){
+ currentPointCloud.parent.remove(currentPointCloud);
}
+ currentPointCloud = null;
+ viewer.render();
+ }
- if (!path || !isVisible) return;
+ if (!path || !isVisible)
+ return;
- Potree.loadPointCloud(path, "punktwolke", function(e) {
- currentPointCloud = e.pointcloud;
- viewer.scene.addPointCloud(currentPointCloud);
+ Potree.loadPointCloud(path, "punktwolke", function (e) {
+ currentPointCloud = e.pointcloud;
+ viewer.scene.addPointCloud(currentPointCloud);
- let material = currentPointCloud.material;
- material.size = 1;
- material.pointSizeType = Potree.PointSizeType.ADAPTIVE;
-
- // 1. Three.js zwingen, die Wolke sofort in der 3D-Welt zu platzieren
- currentPointCloud.updateMatrixWorld(true);
+ let material = currentPointCloud.material;
+ material.size = 1;
+ material.pointSizeType = Potree.PointSizeType.ADAPTIVE;
- // 2. POTREE WECKRUF
- viewer.update(viewer.clock.getDelta(), Number.MAX_VALUE);
-
- // --- HIER IST DIE KORREKTUR ---
- // Erzwinge den aktuell ausgewählten Farbmodus (z.B. elevation)
- // auf das frisch generierte Material der neuen Punktwolke!
- applyColorMode();
+ // 1. Three.js zwingen, die Wolke sofort in der 3D-Welt zu platzieren
+ currentPointCloud.updateMatrixWorld(true);
- // 3. Jetzt die Kamera berechnen und setzen
- syncCamera();
+ // 2. POTREE WECKRUF
+ viewer.update(viewer.clock.getDelta(), Number.MAX_VALUE);
- // 4. Ein zweites Mal synchronisieren
- requestAnimationFrame(() => {
- syncCamera();
- });
+ // --- HIER IST DIE KORREKTUR ---
+ // Erzwinge den aktuell ausgewählten Farbmodus (z.B. elevation)
+ // auf das frisch generierte Material der neuen Punktwolke!
+ applyColorMode();
+
+ // 3. Jetzt die Kamera berechnen und setzen
+ syncCamera();
+
+ // 4. Ein zweites Mal synchronisieren
+ requestAnimationFrame(() => {
+ syncCamera();
});
+ });
}
// Variable, um Endlosschleifen zu verhindern
let isSyncing = false;
-/*
- Kamera von Potree und MapLibre syncronisieren
-*/
+//------------------ Kamera von Potree und MapLibre syncronisieren ------------------------------------
function syncCamera() {
+ if (!currentPointCloud || isSyncing || currentRenderer !== "potree")
+ return;
+ isSyncing = true;
+ const transform = map.transform;
- if (!currentPointCloud || isSyncing || currentRenderer!== 'potree') return;
- isSyncing = true;
+ // 1. Dimensionen auf den Pixel genau angleichen
+ if (viewer.renderer) {
+ viewer.renderer.setSize(map.getCanvas().clientWidth, map.getCanvas().clientHeight,);
+ }
- const transform = map.transform;
-
- // 1. Dimensionen auf den Pixel genau angleichen
- if (viewer.renderer) {
- viewer.renderer.setSize(map.getCanvas().clientWidth, map.getCanvas().clientHeight);
- }
+ // 2. Mathematische Parameter aus dem MapLibre-Kern extrahieren
+ const pitch = (transform.pitch * Math.PI) / 180;
+ const bearing = (transform.bearing * Math.PI) / 180;
+ const mapCenter = map.getCenter();
+ const [utmX, utmY] = proj4("EPSG:4326", "EPSG:25832", [mapCenter.lng, mapCenter.lat,]);
- // 2. Mathematische Parameter aus dem MapLibre-Kern extrahieren
- const pitch = transform.pitch * Math.PI / 180;
- const bearing = transform.bearing * Math.PI / 180;
+ // MapLibres exakte mathematische Kameradistanz nutzen
+ const distanceInMeters = transform.cameraToCenterDistance / transform.pixelsPerMeter;
+ const target = new THREE.Vector3(utmX, utmY, 0);
+ const offset = new THREE.Vector3(0, -distanceInMeters * Math.sin(pitch), distanceInMeters * Math.cos(pitch),);
+ offset.applyAxisAngle(new THREE.Vector3(0, 0, 1), -bearing);
+ const cameraPosition = target.clone().add(offset);
- const mapCenter = map.getCenter();
- const [utmX, utmY] = proj4("EPSG:4326", "EPSG:25832", [mapCenter.lng, mapCenter.lat]);
+ // 3. Potree-Kamera absolut starr setzen
+ viewer.scene.view.position.copy(cameraPosition);
+ viewer.scene.view.lookAt(target);
+ viewer.setFOV(transform.fov);
- // WICHTIG: Nutze MapLibres exakte mathematische Kameradistanz
- const distanceInMeters = transform.cameraToCenterDistance / transform.pixelsPerMeter;
+ // 4. Potree rendern
+ viewer.renderer.resetState();
+ viewer.render();
- const target = new THREE.Vector3(utmX, utmY, 0);
- const offset = new THREE.Vector3(
- 0,
- -distanceInMeters * Math.sin(pitch),
- distanceInMeters * Math.cos(pitch)
- );
-
- offset.applyAxisAngle(new THREE.Vector3(0, 0, 1), -bearing);
- const cameraPosition = target.clone().add(offset);
-
- // 3. Potree-Kamera absolut starr setzen
- viewer.scene.view.position.copy(cameraPosition);
- viewer.scene.view.lookAt(target);
-
- viewer.setFOV(transform.fov);
-
- // 4. Potree rendern
- viewer.renderer.resetState();
- viewer.render();
-
- isSyncing = false;
+ isSyncing = false;
}
-const originalRequestAnimationFrame = window.requestAnimationFrame;
-const hookRenderLoop = () => {
- // Erzwinge die Kamerasynchronisation bei jedem Karten-Update
- syncCamera();
-};
-// Verwendet MapLibres internes Repaint-System, um absolut latenzfrei zu synchronisieren
-map.on('movestart', () => {
- map.getCanvasContainer().style.cursor = 'grabbing';
+// Kartenbewegungs-Events: Kamera-Synchronisation
+map.on("movestart", () => {
+ map.getCanvasContainer().style.cursor = "grabbing";
});
-// bei jeder Kartenbwegeung die Kameras synchronisieren
-map.on('zoom', syncCamera);
-map.on('move', syncCamera);
-map.on('rotate', syncCamera);
-map.on('pitch', syncCamera);
-map.on('draw', syncCamera);
+// bei jeder Kartenbewegung die Kameras synchronisieren
+map.on("zoom", syncCamera);
+map.on("move", syncCamera);
+map.on("rotate", syncCamera);
+map.on("pitch", syncCamera);
+map.on("draw", syncCamera);
+
+// Potree-Canvas soll keine Mausereignisse abfangen, nur die MapLibre-Canvas
elRenderArea.style.pointerEvents = "none";
map.getCanvas().style.pointerEvents = "auto";
-/*
- Hintergrundkarte ändern, Optionen: hell, dunkel, 3D-Gebäudemodelle, Satellit, Terrain, Satellit+Terrain
-*/
+//---------------------- Hintergrundkarte ändern ---------------------------------------------------
function changeBaseMap(newMap) {
- var basemapStyle;
- switch(newMap) {
- case "openfree_dark":
- basemapStyle = "https://tiles.openfreemap.org/styles/dark";
- break;
- case "openfree_bright":
- basemapStyle = "https://tiles.openfreemap.org/styles/bright";
- break;
- case "openfree_liberty":
- basemapStyle = "https://tiles.openfreemap.org/styles/liberty";
- break;
- case "satellite":
- basemapStyle = {
- version: 8,
- sources: {
- "raster-tiles": {
- type: "raster",
- tiles: ["https://api.maptiler.com/tiles/satellite-v2/{z}/{x}/{y}.jpg?key=6mG881AthmTTWyLvFyjH"],
- tileSize: 256,
- attribution: "© MapTiler"
- }
- },
- layers: [{
- id: "satellite-layer",
- type: "raster",
- source: "raster-tiles"
- }]
- };
- break;
- case "terrain":
- basemapStyle = {
- version: 8,
- sources: {
- topo: {
- type: 'raster',
- url: 'https://api.maptiler.com/maps/topo-v4/tiles.json?key=6mG881AthmTTWyLvFyjH',
- tileSize: 256
- },
- terrainSource: {
- type: 'raster-dem',
- url: 'https://tiles.mapterhorn.com/tilejson.json'
- },
- hillshadeSource: {
- type: 'raster-dem',
- url: 'https://tiles.mapterhorn.com/tilejson.json'
- }
- },
- layers: [{
- id: 'topo',
- type: 'raster',
- source: 'topo'
- }, {
- id: 'hills',
- type: 'hillshade',
- source: 'hillshadeSource',
- layout: {
- visibility: 'visible'
- },
- paint: {
- 'hillshade-shadow-color': '#473B24'
- }
- }],
- terrain: {
- source: 'terrainSource',
- exaggeration: 1
- },
- sky: {}
- };
- break;
- case "satellite_terrain":
- basemapStyle = {
- version: 8,
- sources: {
- "raster-tiles": {
- type: "raster",
- tiles: ["https://api.maptiler.com/tiles/satellite-v2/{z}/{x}/{y}.jpg?key=6mG881AthmTTWyLvFyjH"],
- tileSize: 256,
- attribution: "© MapTiler"
- },
- terrainSource: {
- type: 'raster-dem',
- url: 'https://tiles.mapterhorn.com/tilejson.json'
- },
- hillshadeSource: {
- type: 'raster-dem',
- url: 'https://tiles.mapterhorn.com/tilejson.json'
- }
- },
- layers: [{
- id: 'raster-tiles',
- type: 'raster',
- source: 'raster-tiles'
- }, {
- id: 'hills',
- type: 'hillshade',
- source: 'hillshadeSource',
- layout: {
- visibility: 'visible'
- },
- paint: {
- 'hillshade-shadow-color': '#473B24'
- }
- }],
- terrain: {
- source: 'terrainSource',
- exaggeration: 1
- },
- sky: {}
- };
- break;
- }
- map.setStyle(basemapStyle);
+ var basemapStyle;
+ switch (newMap) {
+ // dunkle Karte
+ case "openfree_dark":
+ basemapStyle = "https://tiles.openfreemap.org/styles/dark";
+ break;
+
+ // helle Karte
+ case "openfree_bright":
+ basemapStyle = "https://tiles.openfreemap.org/styles/bright";
+ break;
+
+ // mit LOD1-GEbäudemodellen
+ case "openfree_liberty":
+ basemapStyle = "https://tiles.openfreemap.org/styles/liberty";
+ break;
+
+ // Satellitenbild
+ case "satellite":
+ basemapStyle = {
+ version: 8,
+ sources: {
+ "raster-tiles": {
+ type: "raster",
+ tiles: [
+ "https://api.maptiler.com/tiles/satellite-v2/{z}/{x}/{y}.jpg?key=6mG881AthmTTWyLvFyjH",
+ ],
+ tileSize: 256,
+ attribution: "© MapTiler",
+ },
+ },
+ layers: [
+ {
+ id: "satellite-layer",
+ type: "raster",
+ source: "raster-tiles",
+ },
+ ],
+ };
+ break;
+
+ // Gelände
+ case "terrain":
+ basemapStyle = {
+ version: 8,
+ sources: {
+ topo: {
+ type: "raster",
+ url: "https://api.maptiler.com/maps/topo-v4/tiles.json?key=6mG881AthmTTWyLvFyjH",
+ tileSize: 256,
+ },
+ terrainSource: {
+ type: "raster-dem",
+ url: "https://tiles.mapterhorn.com/tilejson.json",
+ },
+ hillshadeSource: {
+ type: "raster-dem",
+ url: "https://tiles.mapterhorn.com/tilejson.json",
+ },
+ },
+ layers: [
+ {
+ id: "topo",
+ type: "raster",
+ source: "topo",
+ },
+ {
+ id: "hills",
+ type: "hillshade",
+ source: "hillshadeSource",
+ layout: {
+ visibility: "visible",
+ },
+ paint: {
+ "hillshade-shadow-color": "#473B24",
+ },
+ },
+ ],
+ terrain: {
+ source: "terrainSource",
+ exaggeration: 1,
+ },
+ sky: {},
+ };
+ break;
+
+ // Gelände mit Satellitenbild
+ case "satellite_terrain":
+ basemapStyle = {
+ version: 8,
+ sources: {
+ "raster-tiles": {
+ type: "raster",
+ tiles: [
+ "https://api.maptiler.com/tiles/satellite-v2/{z}/{x}/{y}.jpg?key=6mG881AthmTTWyLvFyjH",
+ ],
+ tileSize: 256,
+ attribution: "© MapTiler",
+ },
+ terrainSource: {
+ type: "raster-dem",
+ url: "https://tiles.mapterhorn.com/tilejson.json",
+ },
+ hillshadeSource: {
+ type: "raster-dem",
+ url: "https://tiles.mapterhorn.com/tilejson.json",
+ },
+ },
+ layers: [
+ {
+ id: "raster-tiles",
+ type: "raster",
+ source: "raster-tiles",
+ },
+ {
+ id: "hills",
+ type: "hillshade",
+ source: "hillshadeSource",
+ layout: {
+ visibility: "visible",
+ },
+ paint: {
+ "hillshade-shadow-color": "#473B24",
+ },
+ },
+ ],
+ terrain: {
+ source: "terrainSource",
+ exaggeration: 1,
+ },
+ sky: {},
+ };
+ break;
+ }
+ map.setStyle(basemapStyle);
}
-//------------------------------------------------------Action-Listener und Event-Handler---------------------------------------------------------------------------------
-// Punktwolke aus/einblenden
-document.querySelector('#disable').addEventListener('click', function() {
- isVisible = !isVisible;
- //if (currentPointCloud)
- // currentPointCloud.visible = isVisible;
- applyVisibility();
-
- if(isVisible) {
- this.textContent = "Punktwolke ausblenden";
- this.classList.add("active-state");
- this.classList.remove("inactive-state");
- } else {
- this.textContent = "Punktwolke anzeigen";
- this.classList.add("inactive-state");
- this.classList.remove("active-state");
- }
+//----------------------------------Action-Listener und Event-Handler--------------------------------------
+
+// Punktwolke über Button aus/einblenden
+document.querySelector("#disable").addEventListener("click", function () {
+ isVisible = !isVisible;
+ applyVisibility();
+
+ if (isVisible) {
+ this.textContent = "Punktwolke ausblenden";
+ this.classList.add("active-state");
+ this.classList.remove("inactive-state");
+ } else {
+ this.textContent = "Punktwolke anzeigen";
+ this.classList.add("inactive-state");
+ this.classList.remove("active-state");
+ }
});
// Koordinaten an der Mausposition darstellen (auf 5 Nachkommastellen begrenzt)
-const coordinatesDiv = document.getElementById('coordinates');
-map.on('mousemove', (e) => {
- coordinatesDiv.innerHTML = `Lon: ${e.lngLat.lng.toFixed(5)}° | Lat: ${e.lngLat.lat.toFixed(5)}°`;
+const coordinatesDiv = document.getElementById("coordinates");
+map.on("mousemove", (e) => {
+ coordinatesDiv.innerHTML = `Lon: ${e.lngLat.lng.toFixed(5)}° | Lat: ${e.lngLat.lat.toFixed(5)}°`;
});
// Hintergrundkarte ändern, wenn anderes Element im DropDown gewählt wird
-document.querySelector('select[name="basemap"]').addEventListener('change', (e) => changeBaseMap(e.target.value));
-
+document.querySelector('select[name="basemap"]').addEventListener("change", (e) => {
+ changeBaseMap(e.target.value)
+});
// Punktwolke austauschen, wenn anderes Element im DropDown gewählt wird
-document.querySelector('select[name="pointcloud"]').addEventListener('change', (e) => {
- //loadPointCloud(getPointCloudFilesPOTREE()[e.target.value]);
+document.querySelector('select[name="pointcloud"]').addEventListener("change", (e) => {
currentPointcloudKey = e.target.value;
- loadCurrentPointCloud();
+ loadPointCloud();
});
// Kartenausschnitt auf Ursprung zurücksetzen
-document.getElementById("location").addEventListener("click", () => map.flyTo({center, zoom: 17}));
+document.getElementById("location").addEventListener("click", () => map.flyTo({ center, zoom: 17 }));
-document.getElementById("pointSizeSlider").oninput = function() {
- //viewer.setMinNodeSize(this.value);
- currentPointSize = Number(this.value);
-if (currentRenderer === 'potree') {
+// Punktgröße mit Slider anpassen
+document.getElementById("pointSizeSlider").oninput = function () {
+ currentPointSize = Number(this.value);
+ if (currentRenderer === "potree") {
viewer.setMinNodeSize(currentPointSize);
-} else if (lidarControl) {
- try { lidarControl.setPointSize(currentPointSize); } catch(e) {}
-}
+ } else if (lidarControl) {
+ try {
+ lidarControl.setPointSize(currentPointSize);
+ } catch (e) {}
+ }
};
+
+//--------------------------- Sidepannel ein/ausklappen ----------------------------------------------------
const closeButton = document.getElementById("closeSideBarButton");
const sidebar = document.getElementById("sidebar");
const openOuter = document.getElementById("openButtonOuter");
if (closeButton) {
- closeButton.addEventListener("click", () => {
- const rect = closeButton.getBoundingClientRect();
- sidebar.style.display = "none";
- openOuter.innerHTML = "";
- const openButton = document.getElementById("openSideBarButton");
- openButton.style.top = `${rect.top + window.scrollY - 2}px`;
- openButton.addEventListener("click", () => {
- sidebar.style.display = "flex";
- openOuter.innerHTML = "";
- });
+ closeButton.addEventListener("click", () => {
+ const rect = closeButton.getBoundingClientRect();
+ sidebar.style.display = "none";
+ openOuter.innerHTML = "";
+ const openButton = document.getElementById("openSideBarButton");
+ openButton.style.top = `${rect.top + window.scrollY - 2}px`;
+ openButton.addEventListener("click", () => {
+ sidebar.style.display = "flex";
+ openOuter.innerHTML = "";
});
+ });
}
-document.querySelectorAll('.qualityButtons').forEach(btn => {
- btn.addEventListener('click', () => {
- quality = btn.id;
- //if (currentPointCloud) loadPointCloud(getPointCloudFiles()[document.getElementById("pointcloud").value]);
- if (currentPointcloudKey) loadCurrentPointCloud();
- document.querySelectorAll('.qualityButtons').forEach(b => b.classList.remove('active'));
- btn.classList.add('active');
- });
+//------------------------- QUALITÄTS- UND FARB-BUTTONS ----------------------------------------------------
+// Qualitätsstufe wählen
+document.querySelectorAll(".qualityButtons").forEach((btn) => {
+ btn.addEventListener("click", () => {
+ quality = btn.id;
+ if (currentPointcloudKey)
+ loadPointCloud();
+ document.querySelectorAll(".qualityButtons").forEach((b) => b.classList.remove("active"));
+ btn.classList.add("active");
+ });
});
-document.querySelectorAll('.colorButtons').forEach(btn => {
- btn.addEventListener('click', () => {
- //if (!currentPointCloud) return; // Abbrechen, falls noch keine Wolke geladen ist
-
- document.querySelectorAll('.colorButtons').forEach(b => b.classList.remove('active'));
- btn.classList.add('active');
- currentColorMode = btn.id;
- applyColorMode();
- });
+// Farbmodus (rgb/elevation) wählen
+document.querySelectorAll(".colorButtons").forEach((btn) => {
+ btn.addEventListener("click", () => {
+ document.querySelectorAll(".colorButtons").forEach((b) => b.classList.remove("active"));
+ btn.classList.add("active");
+ currentColorMode = btn.id;
+ applyColorMode();
+ });
});
// Sobald die Karte das allererste Mal stabil steht, Kamera abgleichen
-map.once('idle', () => {
- syncCamera();
+map.once("idle", () => {
+ syncCamera();
});
+
+//--------------- INFO-PANEL (Texte & Bilder zu den Punktwolken) -------------------------------
let pointCloudInfo = {};
const infoPanel = document.getElementById("info-panel");
const infoPanelTitle = document.getElementById("info-panel-title");
const infoPanelText = document.getElementById("info-panel-text");
const openInfoPanel = document.getElementById("openInfoPanel");
const closeInfoPanel = document.getElementById("closeInfoPanel");
-
let currentImageIndex = 0;
-
+// Info-Panel mit Titel, Text und Bild/Bildern der gewählten Punktwolke befüllen
function updateInfoPanel() {
- const key = document.querySelector('select[name="pointcloud"]').value;
+ const key = document.querySelector('select[name="pointcloud"]').value;
+ const info = pointCloudInfo[key];
+ currentImageIndex = 0;
- const info = pointCloudInfo[key];
-
- currentImageIndex = 0;
-
- if (info) {
- infoPanelTitle.textContent = info.title;
- infoPanelText.textContent = info.text;
- updateImage(info);
- } else {
- infoPanelTitle.textContent = "Info";
- infoPanelText.textContent = "Bitte wählen Sie eine Punktwolke aus.";
- document.getElementById("info-panel-image").style.display = "none";
- document.getElementById("info-image-nav").style.display = "none";
- }
+ if (info) {
+ infoPanelTitle.textContent = info.title;
+ infoPanelText.textContent = info.text;
+ updateImage(info);
+ } else {
+ infoPanelTitle.textContent = "Info";
+ infoPanelText.textContent = "Bitte wählen Sie eine Punktwolke aus.";
+ document.getElementById("info-panel-image").style.display = "none";
+ document.getElementById("info-image-nav").style.display = "none";
+ }
}
+// aktuelles Bild + Bildzähler im Info-Panel anzeigen
function updateImage(info) {
- const img = document.getElementById("info-panel-image");
- const nav = document.getElementById("info-image-nav");
- const counter = document.getElementById("info-image-counter");
+ const img = document.getElementById("info-panel-image");
+ const nav = document.getElementById("info-image-nav");
+ const counter = document.getElementById("info-image-counter");
- img.src = info.images[currentImageIndex];
- img.style.display = "block";
+ img.src = info.images[currentImageIndex];
+ img.style.display = "block";
- if (info.images.length > 1) {
- nav.style.display = "flex";
- counter.textContent = `${currentImageIndex + 1} / ${info.images.length}`;
- } else {
- nav.style.display = "none";
- }
+ if (info.images.length > 1) {
+ nav.style.display = "flex";
+ counter.textContent = `${currentImageIndex + 1} / ${info.images.length}`;
+ } else {
+ nav.style.display = "none";
+ }
}
+// vorheriges Bild im Info-Panel anzeigen
document.getElementById("info-img-prev").addEventListener("click", () => {
- const key = document.querySelector('select[name="pointcloud"]').value;
- const info = pointCloudInfo[key];
- if (!info) return;
- currentImageIndex = (currentImageIndex - 1 + info.images.length) % info.images.length;
- updateImage(info);
+ const key = document.querySelector('select[name="pointcloud"]').value;
+ const info = pointCloudInfo[key];
+ if (!info)
+ return;
+ currentImageIndex = (currentImageIndex - 1 + info.images.length) % info.images.length;
+ updateImage(info);
});
+// nächstes Bild im Info-Panel anzeigen
document.getElementById("info-img-next").addEventListener("click", () => {
- const key = document.querySelector('select[name="pointcloud"]').value;
- const info = pointCloudInfo[key];
- if (!info) return;
- currentImageIndex = (currentImageIndex + 1) % info.images.length;
- updateImage(info);
+ const key = document.querySelector('select[name="pointcloud"]').value;
+ const info = pointCloudInfo[key];
+ if (!info)
+ return;
+ currentImageIndex = (currentImageIndex + 1) % info.images.length;
+ updateImage(info);
});
+// Info-Panel öffnen
openInfoPanel.addEventListener("click", () => {
- infoPanel.classList.add("open");
- //openInfoPanel.style.display = "none";
+ infoPanel.classList.add("open");
});
+// Info-Panel schließen
closeInfoPanel.addEventListener("click", () => {
- infoPanel.classList.remove("open");
- openInfoPanel.style.display = "flex";
+ infoPanel.classList.remove("open");
+ openInfoPanel.style.display = "flex";
});
-// Panel aktualisieren wenn Punktwolke gewechselt wird
+// Info-Panel aktualisieren, wenn Punktwolke gewechselt wird
document.querySelector('select[name="pointcloud"]').addEventListener("change", () => {
updateInfoPanel();
-});
+ });
-document.getElementById('rendererToggle').addEventListener('click', function() {
- const next = currentRenderer === 'deckgl' ? 'potree' : 'deckgl';
+//Renderer Toggle Button
+document.getElementById("rendererToggle").addEventListener("click", function () {
+ const next = currentRenderer === "deckgl" ? "potree" : "deckgl";
switchRenderer(next);
-});
-
+ });
\ No newline at end of file
diff --git a/style.css b/style.css
index c5965fb..f798e0e 100644
--- a/style.css
+++ b/style.css
@@ -1,59 +1,60 @@
-html, body {
+html,
+body {
height: 100%;
margin: 0;
}
-body{
- margin:0;
- overflow:hidden;
- font-family: 'Inter', sans-serif;
+body {
+ margin: 0;
+ overflow: hidden;
+ font-family: "Inter", sans-serif;
background: var(--bg);
color: var(--text);
}
-#main{
- width:100vw;
- height:100vh;
- position:relative;
+#main {
+ width: 100vw;
+ height: 100vh;
+ position: relative;
}
-#header{
- position:absolute;
- top:20px;
- left:50%;
- transform:translateX(-50%);
- z-index:30;
- padding:14px 28px;
+#header {
+ position: absolute;
+ top: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 30;
+ padding: 14px 28px;
border-radius: 20px;
- background:
+ background:
linear-gradient(
135deg,
rgba(200, 200, 200, 0.221) 10%,
rgba(79, 79, 79, 0.756) 60%,
rgba(47, 47, 47, 0.864) 100%
),
- rgba(24,24,27,0.78);
+ rgba(24, 24, 27, 0.78);
backdrop-filter: blur(16px);
- color:white;
- font-size:24px;
- font-weight:600;
+ color: white;
+ font-size: 24px;
+ font-weight: 600;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.536);
}
-.logos{
- margin-top:20px;
+.logos {
+ margin-top: 20px;
margin-left: 12px;
- opacity:0.8;
+ opacity: 0.8;
}
-.logos img{
- width:80px;
+.logos img {
+ width: 80px;
margin-right: 10px;
}
-.logos img:hover{
- transform:translateY(-1px);
- box-shadow: 0 6px 18px rgba(0,0,0,0.12);
+.logos img:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
}
#location-button {
@@ -67,9 +68,11 @@ body{
align-items: center;
justify-content: center;
background-color: #f8f9fa;
- border: none !important;
- border-radius: 4px;
- box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05);
+ border: none !important;
+ border-radius: 4px;
+ box-shadow:
+ 0 0 0 2px rgba(0, 0, 0, 0.1),
+ 0 4px 6px rgba(0, 0, 0, 0.05);
cursor: pointer;
box-sizing: border-box;
}
@@ -78,28 +81,28 @@ body{
background-color: #f4f4f4;
}
-#location{
- width:20px;
- height:20px;
- object-fit:contain;
+#location {
+ width: 20px;
+ height: 20px;
+ object-fit: contain;
margin-left: 1px;
margin-top: 1px;
cursor: pointer;
}
-#location:hover{
- transform:scale(1.05);
- background:rgb(233, 232, 232);
+#location:hover {
+ transform: scale(1.05);
+ background: rgb(233, 232, 232);
}
-#location-button:hover{
- background:rgb(233, 232, 232);
+#location-button:hover {
+ background: rgb(233, 232, 232);
}
#sidebar {
position: absolute;
top: 48%;
- transform:translateY(-50%);
+ transform: translateY(-50%);
left: 20px;
width: 210px;
padding: 22px;
@@ -107,13 +110,13 @@ body{
padding-top: 10px;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(18px);
- border: 1px solid rgba(255,255,255,0.3);
+ border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 24px;
- box-shadow: 0 10px 30px rgba(0,0,0,0.15);
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
z-index: 20;
- display: flex;
+ display: flex;
flex-direction: column;
- gap:8px;
+ gap: 8px;
}
#main {
@@ -126,9 +129,9 @@ body{
height: 100%;
}
-#potree_render_area{
- position:absolute;
- top:0;
+#potree_render_area {
+ position: absolute;
+ top: 0;
left: 0;
width: 100%;
height: 100%;
@@ -140,50 +143,49 @@ body{
background: transparent !important;
}
-select{
- appearance:none;
- -webkit-appearance:none;
- -moz-appearance:none;
- width:100%;
- padding:10px 16px;
- border:none;
- border-radius:14px;
- background:rgba(255,255,255,0.92);
- font-size:14px;
- font-weight:500;
- color:#0f172a;
+select {
+ appearance: none;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ width: 100%;
+ padding: 10px 16px;
+ border: none;
+ border-radius: 14px;
+ background: rgba(255, 255, 255, 0.92);
+ font-size: 14px;
+ font-weight: 500;
+ color: #0f172a;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.278);
- cursor:pointer;
- transition:0.2s;
-
+ cursor: pointer;
+ transition: 0.2s;
}
-.selectWrapper{
- position:relative;
- width:100%;
+.selectWrapper {
+ position: relative;
+ width: 100%;
}
-.selectArrow{
- position:absolute;
- right:14px;
- top:48%;
- transform:translateY(-50%);
- pointer-events:none;
- font-size:14px;
- color:#000000;
+.selectArrow {
+ position: absolute;
+ right: 14px;
+ top: 48%;
+ transform: translateY(-50%);
+ pointer-events: none;
+ font-size: 14px;
+ color: #000000;
}
-#disable{
- appearance:none;
- -webkit-appearance:none;
- -moz-appearance:none;
- width:100%;
- padding:10px 16px;
- border:none;
- border-radius:14px;
- font-size:14px;
- font-weight:500;
- background:
+#disable {
+ appearance: none;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ width: 100%;
+ padding: 10px 16px;
+ border: none;
+ border-radius: 14px;
+ font-size: 14px;
+ font-weight: 500;
+ background:
linear-gradient(
135deg,
rgba(18, 77, 216, 0.92) 10%,
@@ -191,16 +193,16 @@ select{
rgba(6, 45, 135, 0.92) 100%
),
rgba(6, 45, 135, 0.92);
- color: white;
+ color: white;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.278);
- cursor:pointer;
- transition:0.2s;
+ cursor: pointer;
+ transition: 0.2s;
margin-top: 8px;
margin-bottom: 10px;
}
#disable.active-state {
- background:
+ background:
linear-gradient(
135deg,
rgba(18, 77, 216, 0.92) 10%,
@@ -208,37 +210,39 @@ select{
rgba(6, 45, 135, 0.92) 100%
),
rgba(6, 45, 135, 0.92);
- color: white;
+ color: white;
}
#disable.inactive-state {
- background: rgba(255,255,255,0.92);
- color: #0f172a;
+ background: rgba(255, 255, 255, 0.92);
+ color: #0f172a;
}
-select:hover{
- transform:translateY(-1px);
- box-shadow: 0 6px 18px rgba(0,0,0,0.12);
+select:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
}
-select:focus{
- outline:none;
- box-shadow:0 0 0 4px rgba(37,99,235,0.15), 0 8px 24px rgba(0,0,0,0.12);
+select:focus {
+ outline: none;
+ box-shadow:
+ 0 0 0 4px rgba(37, 99, 235, 0.15),
+ 0 8px 24px rgba(0, 0, 0, 0.12);
}
-#disable:hover{
- transform:translateY(-1px);
- box-shadow: 0 6px 18px rgba(0,0,0,0.12);
+#disable:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
}
-*{
+* {
transition:
background 0.2s,
transform 0.01s,
opacity 0.2s;
}
-footer{
+footer {
z-index: 30;
position: absolute;
bottom: 8px;
@@ -246,13 +250,13 @@ footer{
font-size: small;
}
-.sideBarText{
-font-size:80%;
-margin:0;
-margin-bottom: -2px;
+.sideBarText {
+ font-size: 80%;
+ margin: 0;
+ margin-bottom: -2px;
}
-#pointSizeSlider{
+#pointSizeSlider {
width: 100%;
margin: 0;
padding: 0;
@@ -260,7 +264,7 @@ margin-bottom: -2px;
margin-bottom: 8px;
}
-input[type="range"]{
+input[type="range"] {
-webkit-appearance: none;
appearance: none;
width: 100%;
@@ -272,12 +276,12 @@ input[type="range"]{
outline: none;
}
-input[type="range"]::-webkit-slider-thumb{
+input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
- width:16px;
- height:16px;
- border-radius:50%;
- background:
+ width: 16px;
+ height: 16px;
+ border-radius: 50%;
+ background:
linear-gradient(
135deg,
rgba(18, 77, 216, 0.92) 10%,
@@ -285,106 +289,108 @@ input[type="range"]::-webkit-slider-thumb{
rgba(6, 45, 135, 0.92) 100%
),
rgba(6, 45, 135, 0.92);
- cursor:pointer;
+ cursor: pointer;
}
-.slider-labels{
- display:flex;
- justify-content:space-between;
- font-size:0.5rem;
- color:#868686;
- margin-bottom:0px;
- margin-top: -5px;
+.slider-labels {
+ display: flex;
+ justify-content: space-between;
+ font-size: 0.5rem;
+ color: #868686;
+ margin-bottom: 0px;
+ margin-top: -5px;
}
-#title{
+#title {
z-index: 30;
position: absolute;
top: 75px;
left: 50%;
- transform:translateX(-50%);
+ transform: translateX(-50%);
font-size: small;
color: #ffffff;
text-shadow: 1px 1.5px #00000059;
}
-#coordinates{
+#coordinates {
z-index: 30;
position: absolute;
bottom: 20px;
left: 50%;
- transform:translateX(-50%);
+ transform: translateX(-50%);
font-size: smaller;
color: #000000cf;
border: none;
border-radius: 14px;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.278);
- padding:8px;
+ padding: 8px;
border-radius: 15px;
background-color: rgba(255, 255, 255, 0.751);
backdrop-filter: blur(10px);
}
-.sideBarButtons{
- font-family:monospace;
- border:none;
- border-radius:10px;
- background:
+.sideBarButtons {
+ font-family: monospace;
+ border: none;
+ border-radius: 10px;
+ background:
linear-gradient(
135deg,
rgba(200, 200, 200, 0.221) 10%,
rgba(79, 79, 79, 0.756) 60%,
rgba(47, 47, 47, 0.864) 100%
),
- rgba(24,24,27,0.78);
- font-size:15px;
- color:#ffffff;
- box-shadow: 0 2px 10px rgba(0,0,0,0.08);
- cursor:pointer;
- transition:0.2s;
+ rgba(24, 24, 27, 0.78);
+ font-size: 15px;
+ color: #ffffff;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
+ cursor: pointer;
+ transition: 0.2s;
z-index: 30;
}
-#closeSideBarButton{
- align-self: flex-end;
+#closeSideBarButton {
+ align-self: flex-end;
right: 0%;
- padding:5px 15px;
-}
-
-#openSideBarButton{
-position: absolute;
- left: 5px;
- padding:5px 15px;
+ padding: 5px 15px;
}
-.buttonRow{
+#openSideBarButton {
+ position: absolute;
+ left: 5px;
+ padding: 5px 15px;
+}
+
+.buttonRow {
display: flex;
width: 100%;
border: none;
border-radius: 10px;
- overflow:hidden;
+ overflow: hidden;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.278);
margin-bottom: 10px;
- }
-
-.qualityButtons, .colorButtons{
- flex: 1;
- margin: 0;
- appearance:none;
- -webkit-appearance:none;
- -moz-appearance:none;
- border:none;
- background:rgba(255,255,255,0.92);
- box-shadow: 0 5px 10px rgba(0, 0, 0, 0.278);
- font-size:12px;
- color:#0f172a;
- padding:5px;
- cursor:pointer;
- transition:0.2s;
}
-.qualityButtons.active, .colorButtons.active{
- background:
+.qualityButtons,
+.colorButtons {
+ flex: 1;
+ margin: 0;
+ appearance: none;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ border: none;
+ background: rgba(255, 255, 255, 0.92);
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.278);
+ font-size: 12px;
+ color: #0f172a;
+ padding: 5px;
+ cursor: pointer;
+ transition: 0.2s;
+}
+
+.qualityButtons.active,
+.colorButtons.active {
+ background:
linear-gradient(
135deg,
rgba(18, 77, 216, 0.92) 10%,
@@ -392,182 +398,185 @@ position: absolute;
rgba(6, 45, 135, 0.92) 100%
),
rgba(6, 45, 135, 0.92);
- color: #ffffff;
+ color: #ffffff;
}
#potree_render_area {
pointer-events: none;
- }
+}
- #info-button-outer {
- position: absolute;
- top: 50%;
- right: 20px;
- transform: translateY(-50%);
- z-index: 30;
+#info-button-outer {
+ position: absolute;
+ top: 50%;
+ right: 20px;
+ transform: translateY(-50%);
+ z-index: 30;
}
#rendererToggle {
- width: 100%;
- padding: 10px 16px;
- border: none;
- border-radius: 14px;
- font-size: 13px;
- font-weight: 500;
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: space-between;
- box-shadow: 0 5px 10px rgba(0,0,0,0.278);
- transition: 0.2s;
+ width: 100%;
+ padding: 10px 16px;
+ border: none;
+ border-radius: 14px;
+ font-size: 13px;
+ font-weight: 500;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.278);
+ transition: 0.2s;
}
#rendererToggle[data-active="deckgl"] {
- background: linear-gradient(
- 135deg,
- rgba(18,77,216,0.92) 10%,
- rgba(13,61,175,0.92) 60%,
- rgba(6,45,135,0.92) 100%);
- color: #ffffff;
+ background: linear-gradient(
+ 135deg,
+ rgba(18, 77, 216, 0.92) 10%,
+ rgba(13, 61, 175, 0.92) 60%,
+ rgba(6, 45, 135, 0.92) 100%
+ );
+ color: #ffffff;
}
#rendererToggle[data-active="potree"] {
- background: linear-gradient(
- 135deg,
- rgba(22,163,74,0.92) 10%,
- rgba(15,118,54,0.92) 60%,
- rgba(6,78,32,0.92) 100%);
- color: #ffffff;
+ background: linear-gradient(
+ 135deg,
+ rgba(22, 163, 74, 0.92) 10%,
+ rgba(15, 118, 54, 0.92) 60%,
+ rgba(6, 78, 32, 0.92) 100%
+ );
+ color: #ffffff;
}
#rendererToggle:hover {
- transform: translateY(-1px);
- box-shadow: 0 6px 18px rgba(0,0,0,0.12);
+ transform: translateY(-1px);
+ box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
}
#rendererIcon {
- font-size: 16px;
+ font-size: 16px;
}
#openInfoPanel {
- margin-top: 12px;
- border: none;
- border-radius: 14px;
- width: 100%;
- padding: 10px 16px;
- font-size: 14px;
- font-weight: 500;
- cursor: pointer;
- background: rgba(255,255,255,0.9);
- box-shadow: 0 5px 10px rgba(0,0,0,0.278);
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 8px;
- color: #1e293b;
+ margin-top: 12px;
+ border: none;
+ border-radius: 14px;
+ width: 100%;
+ padding: 10px 16px;
+ font-size: 14px;
+ font-weight: 500;
+ cursor: pointer;
+ background: rgba(255, 255, 255, 0.9);
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.278);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ color: #1e293b;
}
#openInfoPanel:hover {
- background: rgb(233,232,232);
- transform: translateY(-1px);
+ background: rgb(233, 232, 232);
+ transform: translateY(-1px);
}
#openInfoPanel img {
- width: 16px;
- height: 16px;
- object-fit: contain;
+ width: 16px;
+ height: 16px;
+ object-fit: contain;
}
#info-panel {
- display: none;
- position: absolute;
- top: 48%;
- right: 20px;
- transform: translateY(-50%);
- width: 340px;
- padding: 18px 22px;
- background: rgba(255,255,255,0.9);
- backdrop-filter: blur(18px);
- border: 1px solid rgba(255,255,255,0.3);
- border-radius: 24px;
- box-shadow: 0 10px 30px rgba(0,0,0,0.15);
- z-index: 20;
- display: none;
- flex-direction: column;
- gap: 0;
+ display: none;
+ position: absolute;
+ top: 48%;
+ right: 20px;
+ transform: translateY(-50%);
+ width: 340px;
+ padding: 18px 22px;
+ background: rgba(255, 255, 255, 0.9);
+ backdrop-filter: blur(18px);
+ border: 1px solid rgba(255, 255, 255, 0.3);
+ border-radius: 24px;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
+ z-index: 20;
+ display: none;
+ flex-direction: column;
+ gap: 0;
}
#info-panel.open {
- display: flex;
+ display: flex;
}
#closeInfoPanel {
- align-self: flex-start;
- padding: 5px 15px;
- margin-bottom: 14px;
+ align-self: flex-start;
+ padding: 5px 15px;
+ margin-bottom: 14px;
}
#info-panel-title {
- margin: 0 0 14px 0;
- font-size: 14px;
- font-weight: 600;
- color: #0f172a;
+ margin: 0 0 14px 0;
+ font-size: 14px;
+ font-weight: 600;
+ color: #0f172a;
}
#info-panel-image {
- width: 100%;
- border-radius: 12px;
- object-fit: cover;
- max-height: 220px;
- margin-bottom: 14px;
+ width: 100%;
+ border-radius: 12px;
+ object-fit: cover;
+ max-height: 220px;
+ margin-bottom: 14px;
}
#info-image-nav {
- display: flex;
- align-items: center;
- justify-content: space-between;
- width: 100%;
- margin-bottom: 14px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ margin-bottom: 14px;
}
#info-panel-text {
- margin: 0;
- font-size: 13px;
- line-height: 1.6;
- color: #1e293b;
+ margin: 0;
+ font-size: 13px;
+ line-height: 1.6;
+ color: #1e293b;
}
-#info-img-prev, #info-img-next {
- border: none;
- background: rgba(255,255,255,0.9);
- border-radius: 8px;
- padding: 4px 10px;
- cursor: pointer;
- font-size: 16px;
- box-shadow: 0 2px 6px rgba(0,0,0,0.15);
+#info-img-prev,
+#info-img-next {
+ border: none;
+ background: rgba(255, 255, 255, 0.9);
+ border-radius: 8px;
+ padding: 4px 10px;
+ cursor: pointer;
+ font-size: 16px;
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}
-#info-img-prev:hover, #info-img-next:hover {
- background: rgb(233,232,232);
+#info-img-prev:hover,
+#info-img-next:hover {
+ background: rgb(233, 232, 232);
}
#info-image-counter {
- font-size: 12px;
- color: #555;
+ font-size: 12px;
+ color: #555;
}
.lidar-control-icon {
- display: none !important;
+ display: none !important;
}
.maplibregl-ctrl:has(.lidar-control-icon),
.maplibregl-ctrl-group:has(.lidar-control-icon),
button:has(.lidar-control-icon) {
- display: none !important;
- visibility: hidden !important;
- width: 0px !important;
- height: 0px !important;
- margin: 0 !important;
- padding: 0 !important;
- border: none !important;
+ display: none !important;
+ visibility: hidden !important;
+ width: 0px !important;
+ height: 0px !important;
+ margin: 0 !important;
+ padding: 0 !important;
+ border: none !important;
}
-