Add and remove layers in a Map.

Add / Remove
?

Toggling a layer removes / adds it to the map.

100% Map style by Stamen Design, © OpenStreetMap contributors

Use the addLayer() and removeLayer() methods to add and remove layers in a Map.

index.js
import { Vector3 } from "three";
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 ColorLayer from "@giro3d/giro3d/core/layer/ColorLayer.js";
import Map from "@giro3d/giro3d/entities/Map.js";
import Inspector from "@giro3d/giro3d/gui/Inspector.js";
import WmtsSource from "@giro3d/giro3d/sources/WmtsSource.js";
import ElevationLayer from "@giro3d/giro3d/core/layer/ElevationLayer.js";
import BilFormat from "@giro3d/giro3d/formats/BilFormat.js";

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];
}

Instance.registerCRS(
  "EPSG:2154",
  "+proj=lcc +lat_0=46.5 +lon_0=3 +lat_1=49 +lat_2=44 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
);
Instance.registerCRS(
  "IGNF:WGS84G",
  'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]',
);
const extent = new Extent(
  "EPSG:2154",
  -111629.52,
  1275028.84,
  5976033.79,
  7230161.64,
);

const instance = new Instance({
  target: "view",
  crs: extent.crs,
  backgroundColor: "black",
});

const camPos = new Vector3(220295, 6810219, 409065);
instance.view.camera.position.set(camPos.x, camPos.y, camPos.z);

const controls = new MapControls(instance.view.camera, instance.domElement);
instance.view.setControls(controls);

controls.target.set(camPos.x, camPos.y + 1, 0);

const map = new Map({
  extent,
  backgroundColor: "gray",
  maxSubdivisionLevel: 13,
  hillshading: {
    enabled: true,
    zFactor: 8,
  },
  terrain: false,
});
instance.add(map);

const capabilitiesUrl =
  "https://data.geopf.fr/wmts?SERVICE=WMTS&VERSION=1.0.0&REQUEST=GetCapabilities";

let layers = {};

WmtsSource.fromCapabilities(capabilitiesUrl, {
  layer: "HR.ORTHOIMAGERY.ORTHOPHOTOS",
})
  .then((orthophotoWmts) => {
    const layer = new ColorLayer({
      name: "orthophotos",
      extent: map.extent,
      source: orthophotoWmts,
    });
    layers["orthophotos"] = layer;
    layer.userData.zOrder = 0;
    map.addLayer(layer);
  })
  .catch(console.error);

WmtsSource.fromCapabilities(capabilitiesUrl, {
  layer: "GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2",
})
  .then((planIgn) => {
    const layer = new ColorLayer({
      name: "plan",
      extent: map.extent,
      source: planIgn,
      opacity: 0.2,
    });
    layers["plan"] = layer;
    layer.userData.zOrder = 1;
    map.addLayer(layer);
  })
  .catch(console.error);

WmtsSource.fromCapabilities(capabilitiesUrl, {
  layer: "ELEVATION.ELEVATIONGRIDCOVERAGE.HIGHRES",
  format: new BilFormat(),
  noDataValue: -1000,
})
  .then((elevationWmts) => {
    const layer = new ElevationLayer({
      name: "terrain",
      extent: map.extent,
      // We don't need the full resolution of terrain because we are not using any shading
      resolutionFactor: 0.5,
      minmax: { min: 0, max: 5000 },
      noDataOptions: {
        replaceNoData: false,
      },
      source: elevationWmts,
    });
    layers["terrain"] = layer;
    map.addLayer(layer);
  })
  .catch(console.error);

function bindLayerToggle(layerName) {
  bindToggle(layerName, (state) => {
    if (state) {
      map.addLayer(layers[layerName]);
    } else {
      map.removeLayer(layers[layerName]);
    }

    map.sortColorLayers((a, b) => a.userData.zOrder - b.userData.zOrder);
    instance.notifyChange(map);
  });
}

bindLayerToggle("terrain");
bindLayerToggle("plan");
bindLayerToggle("orthophotos");

Inspector.attach("inspector", instance);
index.html
<!doctype html>
<html lang="en">
  <head>
    <title>Add / Remove layers</title>
    <meta charset="UTF-8" />
    <meta name="name" content="add_remove_layers" />
    <meta name="description" content="Add and remove layers in a Map." />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link rel="icon" href="https://giro3d.org/images/favicon.svg" />
    <link
      href="https://giro3d.org/assets/bootstrap-custom.css"
      rel="stylesheet"
    />
    <script src="https://giro3d.org/assets/bootstrap.bundle.min.js"></script>
    <link
      rel="stylesheet"
      type="text/css"
      href="https://giro3d.org/next/css/example.css"
    />
  </head>

  <body>
    <div id="view" class="m-0 p-0 w-100 h-100"></div>
    <div
      id="inspector"
      class="position-absolute top-0 start-0 mh-100 overflow-auto"
    ></div>

    <div class="side-pane-with-status-bar">
      <div class="card">
        <h5 class="card-header" style="width: 12rem">Add / Remove</h5>

        <!-- tooltip -->
        <span
          class="badge bg-secondary position-absolute top-0 end-0 m-2"
          data-bs-toggle="popover"
          data-bs-content="tooltip"
          >?</span
        >

        <p class="card-text d-none" id="tooltip">
          Toggling a layer removes / adds it to the map.
        </p>

        <div class="card-body">
          <fieldset>
            <div class="form-check form-switch">
              <input
                class="form-check-input"
                type="checkbox"
                checked="true"
                role="switch"
                id="plan"
                autocomplete="off"
              />
              <label class="form-check-label" for="plan">Plan</label>
            </div>
            <div class="form-check form-switch">
              <input
                class="form-check-input"
                type="checkbox"
                checked="true"
                role="switch"
                id="orthophotos"
                autocomplete="off"
              />
              <label class="form-check-label" for="orthophotos"
                >Orthophoto</label
              >
            </div>
            <div class="form-check form-switch">
              <input
                class="form-check-input"
                type="checkbox"
                checked="true"
                role="switch"
                id="terrain"
                autocomplete="off"
              />
              <label class="form-check-label" for="terrain">Terrain</label>
            </div>
          </fieldset>
        </div>
      </div>
    </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": "add_remove_layers",
    "dependencies": {
        "@giro3d/giro3d": "git+https://gitlab.com/giro3d/giro3d.git"
    },
    "devDependencies": {
        "vite": "^3.2.3"
    },
    "scripts": {
        "start": "vite",
        "build": "vite build"
    }
}