Last updated

Legend/Text on Grid planes

This tutorial demonstrates how to add a text/legend on a 3D Grid or Projection Widget .
Each plane of the legend can be customized separately if needed.

To use this feature, you simply need to create a GridLegend with the desired legend settings,
and add it to a Grid or a ProjectionWidget through the .addLegend() method.

# Add a legend on a 3D Grid

In this example you can see how to add the legend to a 3D Grid.

With the interface below, you can dynamically change some of the legend options.
For more options please refer to the GridLegend documentation.

import { DefaultColorProvider } from "@int/geotoolkit/util/DefaultColorProvider.ts";
import { Plot } from "@int/geotoolkit3d/Plot.ts";
import { Vector2, Vector3 } from "/node_modules/.vite/deps/three.js?v=2235af65";
import { Grid } from "@int/geotoolkit3d/scene/grid/Grid.ts";
import { CompassAxis } from "@int/geotoolkit3d/scene/compass/CompassAxis.ts";
import { GridLegend } from "@int/geotoolkit3d/scene/grid/legend/GridLegend.ts";
import { PointSet } from "@int/geotoolkit3d/scene/pointset/PointSet.ts";
import { MathUtil } from "@int/geotoolkit/util/MathUtil.ts";
import { AlignmentStyle, TextStyle } from "@int/geotoolkit/attributes/TextStyle.ts";
let __legendHandle;
const __legendDynamicOptions = {
  "sizeindevice": true,
  "nearside": false,
  "hideiftoolarge": true,
  "textscale": 1
};
function createScene(divElement) {
  const plot = createPlot(divElement);
  const pointSet = createPointSet();
  const grid = new Grid({ start: new Vector3(0, 0, 0), end: new Vector3(20, 20, 20) });
  plot.getRoot().add(grid);
  plot.getRoot().add(pointSet);
  const legend = createLegend();
  grid.addLegend(legend);
  __legendHandle = legend;
  return plot;
}
function createLegend() {
  const legendStyle = new TextStyle({
    "font": "15px Arial",
    "color": "white",
    "alignment": AlignmentStyle.Left
  });
  const titleStyle = new TextStyle({
    "font": "22px Arial",
    "color": "white",
    "alignment": AlignmentStyle.Center
  }).setFontWeight("bold");
  const blackOutline = {
    "enable": true,
    "innercolor": "white",
    "outlinecolor": "black",
    "thickness": 3
  };
  const gridTextOpts = {
    "planes": {
      "left": {
        "text": "SAMPLE LEGEND\n\nItem 1 - Item description\nItem 2 - Item description\nItem 3 - Item description\nItem 4 - Item description\n",
        "style": legendStyle,
        "outline": blackOutline,
        "textoffset": new Vector2(0.25, 0.66)
      },
      "back": {
        "text": "SAMPLE TITLE",
        "style": titleStyle,
        "outline": blackOutline,
        "textoffset": new Vector2(0.5, 0.875)
      },
      "front": { "text": "Sample text", "style": titleStyle },
      "right": { "text": "Sample text", "style": titleStyle }
    }
  };
  return new GridLegend(gridTextOpts);
}
function createPlot(divElement) {
  const lookAt = new Vector3(10, 10, 10);
  const position = new Vector3().copy(lookAt.clone()).sub(new Vector3(-20, 20, -5));
  const perspectivePlot = new Plot({
    "container": divElement,
    "camera": {
      "position": position,
      "lookat": lookAt
    }
  });
  perspectivePlot.getCompass().setCompassObject(new CompassAxis());
  return perspectivePlot;
}
function createPointSet() {
  const points = generatePoints();
  return new PointSet({
    "data": {
      "x": points["x"],
      "y": points["y"],
      "z": points["z"],
      "sizes": points["sizes"],
      "values": points["values"]
    },
    "symbolminsize": 0.15,
    "symbolmaxsize": 0.3,
    "colorprovider": new DefaultColorProvider({
      "values": [points["valmin"], 0.5 * points["valmin"] + points["valmax"], points["valmax"]],
      "colors": ["white", "orange", "red"]
    })
  });
}
function generatePoints() {
  const result = {
    "x": [],
    "y": [],
    "z": [],
    "sizes": [],
    "values": [],
    "valmin": Number.POSITIVE_INFINITY,
    "valmax": Number.NEGATIVE_INFINITY
  };
  for (let y = 0; y < 20; y++) {
    const yHeight = Math.cos(Math.PI * 2 * y / 20) + 5;
    for (let x = 0; x < 20; x++) {
      const xHeight = Math.sin(Math.PI * 2 * x / 20) - 4 + (x + y) / 3;
      result["x"].push(x);
      result["y"].push(y);
      const z = xHeight + yHeight;
      result["z"].push(z);
      const size = z / 10;
      result["sizes"].push(size);
      const value = z * (MathUtil.getSeededRandom(0, 1, 1) + size / 10);
      result["values"].push(value);
      result["valmin"] = Math.min(value, result["valmin"]);
      result["valmax"] = Math.max(value, result["valmax"]);
    }
  }
  return result;
}
function setLegendOptions(legend, options) {
  legend.setOptions({
    "planes": {
      "front": options,
      "left": options,
      "back": options,
      "right": options
    }
  });
}
function toggleSizeInDeviceButtonUI(isEnabled) {
  __legendDynamicOptions["sizeindevice"] = isEnabled;
  setLegendOptions(__legendHandle, __legendDynamicOptions);
}
function updateTextScale(value) {
  __legendDynamicOptions["textscale"] = value;
  setLegendOptions(__legendHandle, __legendDynamicOptions);
}
function toggleNearSideButtonUI(isEnabled) {
  __legendDynamicOptions["nearside"] = isEnabled;
  setLegendOptions(__legendHandle, __legendDynamicOptions);
}
function toggleHideIfTooLargeButtonUI(isEnabled) {
  __legendDynamicOptions["hideiftoolarge"] = isEnabled;
  setLegendOptions(__legendHandle, __legendDynamicOptions);
}
export { createScene, toggleHideIfTooLargeButtonUI, toggleNearSideButtonUI, toggleSizeInDeviceButtonUI, updateTextScale };

createScene(document.querySelector('[ref="plot"]'));

# Add a legend on a Projection Widget

In this example you can see how to add the legend to a 3D Projection Widget.

With the interface below, you can dynamically change some of the legend options.
For more options, please refer to the GridLegend documentation.

import { DefaultColorProvider } from "@int/geotoolkit/util/DefaultColorProvider.ts";
import { Plot } from "@int/geotoolkit3d/Plot.ts";
import { Vector2, Vector3 } from "/node_modules/.vite/deps/three.js?v=2235af65";
import { GridLegend } from "@int/geotoolkit3d/scene/grid/legend/GridLegend.ts";
import { AlignmentStyle, TextStyle } from "@int/geotoolkit/attributes/TextStyle.ts";
import { ProjectionWidget } from "@int/geotoolkit3d/widgets/ProjectionWidget.ts";
import { Pipe } from "@int/geotoolkit3d/scene/well/Pipe.ts";
import { Wells } from "/src/code/Carnac3D/helpers/wells.ts";
const X_SCALE = 1;
const Y_SCALE = 1;
const Z_SCALE = 2;
const CAMERA_DISTANCE = -4500;
const DEFAULT_COLORPROVIDER = new DefaultColorProvider({
  "values": [0, 1, 2],
  "colors": ["green", "yellow", "red"]
});
const __legendDynamicOptions = {
  "sizeindevice": true,
  "nearside": false,
  "hideiftoolarge": true,
  "textscale": 1
};
let legend;
function createScene(divElement) {
  const plot = createPlot(divElement);
  const pipe = createPipe();
  plot.getRoot().add(pipe);
  const projectionWidget = new ProjectionWidget();
  projectionWidget.addMesh(pipe);
  plot.getRoot().add(projectionWidget);
  legend = createLegend();
  projectionWidget.addLegend(legend);
  return plot;
}
function createLegend() {
  const legendStyle = new TextStyle({
    "font": "13px Arial",
    "color": "white",
    "alignment": AlignmentStyle.Left
  });
  const titleStyle = new TextStyle({
    "font": "20px Arial",
    "color": "white",
    "alignment": AlignmentStyle.Center
  }).setFontWeight("bold");
  const blackOutline = {
    "enable": true,
    "innercolor": "white",
    "outlinecolor": "black",
    "thickness": 3
  };
  const gridTextOpts = {
    "planes": {
      "right": {
        "text": "SAMPLE LEGEND\n\nItem 1 - Item description\nItem 2 - Item description\nItem 3 - Item description\nItem 4 - Item description\n",
        "style": legendStyle,
        "outline": blackOutline,
        "textoffset": new Vector2(0.5, 0.66)
      },
      "back": {
        "text": "SAMPLE TITLE",
        "style": titleStyle,
        "outline": blackOutline,
        "textoffset": new Vector2(0.5, 0.875)
      },
      "front": { "text": "Sample text", "style": titleStyle, "outline": blackOutline },
      "left": { "text": "Sample text", "style": titleStyle, "outline": blackOutline }
    }
  };
  return new GridLegend(gridTextOpts);
}
function createPipe() {
  const data = Wells.getWell_pipe();
  const pipe = new Pipe({
    data,
    tubeprecision: 8,
    colorprovider: DEFAULT_COLORPROVIDER
  });
  pipe.position.set(456396.784, 678286319e-2, 0);
  return pipe;
}
function createPlot(divElement) {
  const center = new Vector3(457101.805, 6782420821e-3, -1466.69);
  return new Plot({
    "container": divElement,
    "camera": {
      "position": center.clone().add(new Vector3(CAMERA_DISTANCE, CAMERA_DISTANCE, 1e3)),
      "lookat": center.clone().add(new Vector3(0, 0, 180))
    },
    "scale": new Vector3(X_SCALE, Y_SCALE, Z_SCALE)
  });
}
function setLegendOptions(legend2, options) {
  legend2.setOptions({
    "planes": {
      "front": options,
      "left": options,
      "back": options,
      "right": options
    }
  });
}
function toggleSizeInDeviceButtonUI(isEnabled) {
  __legendDynamicOptions["sizeindevice"] = isEnabled;
  setLegendOptions(legend, __legendDynamicOptions);
}
function updateTextScale(value) {
  __legendDynamicOptions["textscale"] = value;
  setLegendOptions(legend, __legendDynamicOptions);
}
function toggleNearSideButtonUI(isEnabled) {
  __legendDynamicOptions["nearside"] = isEnabled;
  setLegendOptions(legend, __legendDynamicOptions);
}
function toggleHideIfTooLargeButtonUI(isEnabled) {
  __legendDynamicOptions["hideiftoolarge"] = isEnabled;
  setLegendOptions(legend, __legendDynamicOptions);
}
export { createScene, toggleHideIfTooLargeButtonUI, toggleNearSideButtonUI, toggleSizeInDeviceButtonUI, updateTextScale };

createScene(document.querySelector('[ref="plot"]'));