Track progress of data loading at various levels of the instance hierarchy.

  • Instance
  • Map (left)
  • Color layer
  • Elevation layer
  • Map (right)
  • Color layer
  • Elevation layer
100% © Mapbox

Use the loading and progress properties of various elements (Instance, Entity, Layer...) to track the loading of the data.
Each level of the hierarchy aggregates the state of its children (e.g the instance aggregates the state of all entities under its control).

index.js
import XYZ from 'ol/source/XYZ.js';
import { MapControls } from 'three/examples/jsm/controls/MapControls.js';

import Extent from '@giro3d/giro3d/core/geographic/Extent.js';
import Instance from '@giro3d/giro3d/core/Instance.js';
import TiledImageSource from '@giro3d/giro3d/sources/TiledImageSource.js';
import ColorLayer from '@giro3d/giro3d/core/layer/ColorLayer.js';
import ElevationLayer from '@giro3d/giro3d/core/layer/ElevationLayer.js';
import Interpretation from '@giro3d/giro3d/core/layer/Interpretation.js';
import Map from '@giro3d/giro3d/entities/Map.js';
import Inspector from '@giro3d/giro3d/gui/Inspector.js';



const extent = new Extent('EPSG:3857', -13611854, -13593262, 5806332, 5820603);

const viewerDiv = document.getElementById('viewerDiv');

const instance = new Instance(viewerDiv, { crs: 'EPSG:3857' });

function createMap(mapExtent, tileset) {
    const key =
        'pk.eyJ1IjoidG11Z3VldCIsImEiOiJjbGJ4dTNkOW0wYWx4M25ybWZ5YnpicHV6In0.KhDJ7W5N3d1z3ArrsDjX_A';
    const map = new Map(tileset, { extent: mapExtent, segments: 128 });
    instance.add(map);

    // Adds a XYZ elevation layer with MapBox terrain RGB tileset
    const elevationLayer = new ElevationLayer({
        name: 'xyz_elevation',
        extent,
        source: new TiledImageSource({
            source: new XYZ({
                url: `https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token=${key}`,
                projection: extent.crs(),
                crossOrigin: 'anonymous',
            }),
        }),
        interpretation: Interpretation.MapboxTerrainRGB,
    });
    map.addLayer(elevationLayer);

    // Adds a XYZ color layer with MapBox satellite tileset
    const colorLayer = new ColorLayer({
        name: 'xyz_color',
        extent,
        source: new TiledImageSource({
            source: new XYZ({
                url: `https://api.mapbox.com/v4/mapbox.${tileset}/{z}/{x}/{y}.webp?access_token=${key}`,
                projection: extent.crs(),
                crossOrigin: 'anonymous',
            }),
        }),
    });
    map.addLayer(colorLayer);

    return { map, colorLayer, elevationLayer };
}

const split = extent.split(2, 1);

const naip = createMap(split[0], 'naip');
const satellite = createMap(split[1], 'satellite');

// Sets the camera position
const center = extent.centerAsVector3();
instance.camera.camera3D.position.set(center.x, extent.north(), 10000);

// Creates controls
const controls = new MapControls(instance.camera.camera3D, instance.domElement);

// Then looks at extent's center
controls.target = center;
controls.saveState();

controls.enableDamping = true;
controls.dampingFactor = 0.2;
controls.maxPolarAngle = Math.PI / 2.3;

instance.useTHREEControls(controls);

Inspector.attach(document.getElementById('panelDiv'), instance);

const instanceProgress = document.getElementById('progress-instance');
const naipMapProgress = document.getElementById('progress-map1');
const color1Progress = document.getElementById('progress-color1');
const elevation1Progress = document.getElementById('progress-elevation1');
const satelliteMapProgress = document.getElementById('progress-map2');
const color2Progress = document.getElementById('progress-color2');
const elevation2Progress = document.getElementById('progress-elevation2');

function updateProgressBar(domElement, source) {
    domElement.style.width = `${Math.round(source.progress * 100)}%`;
}

// Let's poll the main loop: at each update, we can update the progress bars
instance.addEventListener('update-end', () => {
    updateProgressBar(instanceProgress, instance);

    updateProgressBar(naipMapProgress, naip.map);
    updateProgressBar(color1Progress, naip.colorLayer);
    updateProgressBar(elevation1Progress, naip.elevationLayer);

    updateProgressBar(satelliteMapProgress, satellite.map);
    updateProgressBar(color2Progress, satellite.colorLayer);
    updateProgressBar(elevation2Progress, satellite.elevationLayer);
});
index.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Giro3D - Tracking progress</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
  <style>
    body {
      padding: 0;
      margin: 0;
      width: 100vw;
      height: 100vh;
    }

    #viewerDiv {
      width: 100%;
      height: 100%;
    }

    #panelDiv {
      position: absolute;
      top: 0;
      left: 0;
    }
    
  </style>
</head>

<body>
  <div id="viewerDiv"></div>
  <div id="panelDiv"></div>
  <div class="m-2 position-absolute top-0 end-0">
    <ul class="list-group">
        <li class="list-group-item d-flex justify-content-between align-items-center">
            <span>Instance</span>
            <div class="progress" style="width: 100px">
                <div id="progress-instance" class="progress-bar" style="width: 100%"></div>
            </div>
        </li>

        <li class="list-group-item d-flex justify-content-between align-items-center">
            <span class="mx-3">Map (left)</span>
            <div class="progress" style="width: 100px">
                <div id="progress-map1" class="progress-bar" style="width: 100%"></div>
            </div>
        </li>

        <li class="list-group-item d-flex justify-content-between align-items-center">
            <span class="mx-5">Color layer</span>
            <div class="progress" style="width: 100px">
                <div id="progress-color1" class="progress-bar" style="width: 100%"></div>
            </div>
        </li>

        <li class="list-group-item d-flex justify-content-between align-items-center">
            <span class="mx-5">Elevation layer</span>
            <div class="progress" style="width: 100px">
                <div id="progress-elevation1" class="progress-bar" style="width: 100%"></div>
            </div>
        </li>

        <li class="list-group-item d-flex justify-content-between align-items-center">
            <span class="mx-3">Map (right)</span>
            <div class="progress" style="width: 100px">
                <div id="progress-map2" class="progress-bar" style="width: 100%"></div>
            </div>
        </li>

        <li class="list-group-item d-flex justify-content-between align-items-center">
            <span class="mx-5">Color layer</span>
            <div class="progress" style="width: 100px">
                <div id="progress-color2" class="progress-bar" style="width: 100%"></div>
            </div>
        </li>

        <li class="list-group-item d-flex justify-content-between align-items-center">
            <span class="mx-5">Elevation layer</span>
            <div class="progress" style="width: 100px">
                <div id="progress-elevation2" class="progress-bar" style="width: 100%"></div>
            </div>
        </li>
    </ul>
</div>

  <script type="module" src="index.js"></script>
  <script>
    /* activate popovers */
    const popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
    popoverTriggerList.map(
      // bootstrap is used as script in the template, disable warning about undef
      // eslint-disable-next-line no-undef
      popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl, {
        trigger: 'hover',
        placement: 'left',
        content: document.getElementById(popoverTriggerEl.getAttribute('data-bs-content')).innerHTML,
        html: true,
      }),
    );
  </script>
</body>

</html>
package.json
{
  "name": "tracking_progress",
  "dependencies": {
    "@giro3d/giro3d": "0.35.0"
  },
  "devDependencies": {
    "vite": "^3.2.3"
  },
  "scripts": {
    "start": "vite",
    "build": "vite build"
  }
}