Adaptive labels are displayed at the intersection of grid lines and the
viewport's edges.
Use the label-created event to customize the DOM element of labels.
If enabled, the ticks start at the lower-left (south-west) corner of the grid.
If disabled, the ticks start at the origin point of the coordinate system.
The AxisGrid is useful to get a grasp of a dataset's volume in 3D space, including is height. The relative origin mode is useful to get a grasp of the dataset's size, with the absolute origin mode displays coordinates in the local CRS.
index.js
import colormap from "colormap";import { Color, DoubleSide } from "three";import { MapControls } from "three/examples/jsm/controls/MapControls.js";import XYZ from "ol/source/XYZ.js";import Extent from "@giro3d/giro3d/core/geographic/Extent.js";import Instance from "@giro3d/giro3d/core/Instance.js";import ElevationLayer from "@giro3d/giro3d/core/layer/ElevationLayer.js";import TiledImageSource from "@giro3d/giro3d/sources/TiledImageSource.js";import Map from "@giro3d/giro3d/entities/Map.js";import AxisGrid, { TickOrigin } from "@giro3d/giro3d/entities/AxisGrid.js";import Inspector from "@giro3d/giro3d/gui/Inspector.js";import Interpretation from "@giro3d/giro3d/core/layer/Interpretation.js";import GeoTIFFFormat from "@giro3d/giro3d/formats/GeoTIFFFormat.js";import ColorMap, { ColorMapMode } from "@giro3d/giro3d/core/ColorMap.js";function bindSlider(id, onChange) { const element = document.getElementById(id); if (!(element instanceof HTMLInputElement)) { throw new Error( "invalid binding element: expected HTMLInputElement, got: " + element.constructor.name, ); } element.oninput = function oninput() { onChange(element.valueAsNumber); }; const setValue = (v, min, max, step) => { if (min != null && max != null) { element.min = min.toString(); element.max = max.toString(); if (step != null) { element.step = step; } } element.valueAsNumber = v; onChange(element.valueAsNumber); }; const initialValue = element.valueAsNumber; return [setValue, initialValue, element];}function bindToggle(id, onChange) { const element = document.getElementById(id); if (!(element instanceof HTMLInputElement)) { throw new Error( "invalid binding element: expected HTMLButtonElement, got: " + element.constructor.name, ); } element.oninput = function oninput() { onChange(element.checked); }; const callback = (v) => { element.checked = v; onChange(element.checked); }; return [callback, element.checked, element];}function bindColorPicker(id, onChange) { const element = document.getElementById(id); if (!(element instanceof HTMLInputElement)) { throw new Error( "invalid binding element: expected HTMLInputElement, got: " + element.constructor.name, ); } element.oninput = function oninput() { // Let's change the classification color with the color picker value const hexColor = element.value; onChange(new Color(hexColor)); }; const externalFunction = (v) => { element.value = `#${new Color(v).getHexString()}`; onChange(element.value); }; return [externalFunction, new Color(element.value), element];}const x = -13602000;const y = 5812000;const halfWidth = 2500;const extent = new Extent( "EPSG:3857", x - halfWidth, x + halfWidth, y - halfWidth, y + halfWidth,);const instance = new Instance({ target: "view", crs: extent.crs, backgroundColor: null,});const map = new Map({ extent, lighting: true, discardNoData: true, side: DoubleSide, backgroundColor: "white",});const params = { useCustomCss: false,};instance.add(map);const source = new TiledImageSource({ source: new XYZ({ minZoom: 10, maxZoom: 16, url: "https://3d.oslandia.com/dem/MtStHelens-tiles/{z}/{x}/{y}.tif", }), format: new GeoTIFFFormat(),});const floor = 1100;const ceiling = 2500;const values = colormap({ colormap: "viridis", nshades: 256 });const colors = values.map((v) => new Color(v));const dem = new ElevationLayer({ name: "dem", extent, interpretation: Interpretation.Raw, source, colorMap: new ColorMap({ colors, min: floor, max: ceiling, mode: ColorMapMode.Elevation, }),});map.addLayer(dem);// Create an axis grid that encompasses the Map.const axisGrid = new AxisGrid({ volume: { extent: extent.withRelativeMargin(0.1), floor, ceiling, }, ticks: { x: 1000, y: 1000, z: 200, },});const onLabelCreated = ({ label }) => { if (params.useCustomCss) { label.classList.add("badge"); label.classList.add("rounded-pill"); label.classList.add("text-bg-light"); }};// Let's customize the labels with bootstrap classes// In you own application, you can use your own CSS classes of coursesaxisGrid.addEventListener("label-created", onLabelCreated);instance.add(axisGrid);instance.view.camera.position.set(-13594700, 5819700, 7300);const controls = new MapControls(instance.view.camera, instance.domElement);controls.target.set(-13603000, 5811000, 0);instance.view.setControls(controls);function bindAxisStep(axis) { bindSlider(`${axis}-axis-step`, (v) => { axisGrid.ticks[axis] = v; axisGrid.refresh(); instance.notifyChange(axisGrid); });}bindAxisStep("x");bindAxisStep("y");bindAxisStep("z");bindColorPicker("color", (color) => { axisGrid.color = color; instance.notifyChange(axisGrid);});bindToggle("entity", (v) => { axisGrid.visible = v; instance.notifyChange(axisGrid);});bindToggle("origin", (v) => { axisGrid.origin = v ? TickOrigin.Relative : TickOrigin.Absolute; axisGrid.refresh(); instance.notifyChange(axisGrid);});bindToggle("ceiling", (v) => { axisGrid.showCeilingGrid = v; instance.notifyChange(axisGrid);});bindToggle("floor", (v) => { axisGrid.showFloorGrid = v; instance.notifyChange(axisGrid);});bindToggle("sides", (v) => { axisGrid.showSideGrids = v; instance.notifyChange(axisGrid);});bindToggle("adaptive-labels", (v) => { axisGrid.adaptiveLabels = v; instance.notifyChange(axisGrid);});bindToggle("custom-css", (v) => { params.useCustomCss = v; axisGrid.refresh(); instance.notifyChange(axisGrid);});document.getElementById("randomize-position").onclick = () => { const current = axisGrid.volume.extent; const dims = current.dimensions(); const center = current.centerAsVector3(); const range = 5000; center.set( center.x + (Math.random() - 0.5) * range, center.y + (Math.random() - 0.5) * range, 0, ); const newExtent = new Extent( current.crs, center.x - dims.x / 2, center.x + dims.x / 2, center.y - dims.y / 2, center.y + dims.y / 2, ); axisGrid.volume.extent = newExtent; axisGrid.refresh(); instance.notifyChange(axisGrid);};Inspector.attach("inspector", instance);