Source: primitives/label.js

import {
  applyTextSpriteTextureSettings,
  createTextSprite,
  releaseTextSprite,
  setTextSpriteHeight,
} from '../textSprite';

/**
 * Bitmap labels, this is used with {@link Glyph} to
 * provide labels.
 *
 * @param {String} textIn - Text to be displayed dwith the label.
 * @param {THREE.Color} colour - Colour to be set for the label.
 *
 * @class
 * @author Alan Wu
 * @return {Label}
 */
const Label = function (textIn, colourIn) {
  let text = textIn;
  let sprite = undefined;
  const position = [0, 0, 0];
  let colour = colourIn;
  let size = 1.0;
  let fontWeight = 500;
  const textHeight = 0.012;
  //The canvas resolution is chosen from the size of the text on screen
  sprite = createTextSprite(
    text,
    textHeight,
    colourIn ? colourIn.getStyle() : undefined,
    'Asap',
    fontWeight,
  );
  sprite.center.x = -0.05;
  sprite.center.y = 0;
  //SpriteText replaces the texture whenever the text, colour or size
  //changes, the settings need to be re-applied to the new texture.
  const applyTextureSettings = () => {
    applyTextSpriteTextureSettings(sprite);
  };

  /**
   * Get the current position in an array containing the x, y and z
   * coordinates.
   *
   * @return {Array}
   */
  this.getPosition = () => {
    if (sprite) return [sprite.position.x, sprite.position.y, sprite.position.z];
    return [0, 0, 0];
  };

  /**
   * Set the position of the label in  3D coordinates.
   *
   * @param {Number} x - x coordinate to be set.
   * @param {Number} y - y coordinate to be set.
   * @param {Number} z - z coordinate to be set.
   */
  this.setPosition = (x, y, z) => {
    position[0] = x;
    position[1] = y;
    position[2] = z;

    if (sprite) {
      sprite.position.set(x, y, z);
    }
  };

  /**
   * Set the colour of the label
   *
   * @param {THREE.Color} colour - colour to be set
   */
  this.setColour = (colourIn) => {
    if (colourIn) {
      //Changing the colour redraws the canvas and creates a new texture,
      //only do it when the colour has changed.
      const style = colourIn.getStyle();
      if (style !== sprite.color) {
        sprite.color = style;
        applyTextureSettings();
      }
      colour = colourIn;
    }
  };

  /**
   * Scale the label.
   *
   * @param {Number} scaling - Scale to be set.
   */
  this.setScale = (scaling) => {
    if (sprite && scaling > 0.0) sprite.scale.set(scaling, scaling, 1.0);
  };

  /**
   * Set depth test for sprite object.
   *
   * @param {Boolean} flag - Enable/disable depth test
   */
  this.setDepthTest = (flag) => {
    if (flag && flag !== sprite.material.depthTest) {
      sprite.material.depthTest = flag;
    }
  };

  /**
   * Set a new text for the label.
   *
   * @param {Number} scaling - Scale to be set.
   */
  this.setSize = (sizeIn) => {
    if (sizeIn > 0.0) {
      //Redraw at the resolution matching the new size
      setTextSpriteHeight(sprite, textHeight * sizeIn);
      size = sizeIn;
    }
  };

  /**
   * Set a new text for the label.
   *
   * @param {Number} scaling - Scale to be set.
   */
  this.setFontWeight = (fontWeightIn) => {
    if (fontWeightIn && fontWeightIn !== fontWeight) {
      sprite.fontWeight = fontWeightIn;
      applyTextureSettings();
      fontWeight = fontWeightIn;
    }
  };

  /**
   * Set a new text for the label.
   *
   * @param {Number} scaling - Scale to be set.
   */
  this.setText = (textIn) => {
    if (textIn && textIn !== sprite.text) {
      //Force teh texture to update
      const canvas = sprite._canvas;
      if (sprite.material && sprite.material.map) {
        sprite.material.map.dispose();
      }
      if (sprite._canvas) {
        const ctx = sprite._canvas.getContext('2d');
        if (ctx) {
          ctx.clearRect(0, 0, sprite._canvas.width, sprite._canvas.height);
        }
        sprite._canvas.width = 1;
        sprite._canvas.height = 1;
      }
      sprite.text = textIn;
      setTextSpriteHeight(sprite, textHeight * size);
      text = textIn;
      if (sprite.material && sprite.material.map) {
        applyTextureSettings();
        sprite.material.map.needsUpdate = true;
      }
    }
  };

  /**
   * Set visibility of the label.
   *
   * @param {Boolean} flag - Visibility to set
   */
  this.setVisibility = (flag) => {
    sprite.visible = flag;
  };

  /**
   * Free up the memory
   */
  this.dispose = () => {
    if (sprite) {
      releaseTextSprite(sprite);
      sprite.removeFromParent();
      if (sprite.material) {
        sprite.material.map?.dispose();
        sprite.material.dispose();
      }
      //Release the canvas memory
      if (sprite._canvas) {
        sprite._canvas.width = 0;
        sprite._canvas.height = 0;
      }
    }
  };

  /**
   * Get the intrnal sprite.
   *
   * @return {THREE.Sprite}
   */
  this.getSprite = () => {
    return sprite;
  };

  /**
   * Get the text.
   *
   * @return {String}
   */
  this.getString = () => {
    return text;
  };
};

export { Label };