Extensions

Source: display/Text.js

import { noop } from "../../common/utils/noop";
import { Texture } from "../textures/Texture";
import { layoutText } from "../utils/layoutText";
import { Image } from "./Image";

/**
 * Text drawable class
 * @extends {Image}
 */
export class Text extends Image {
  /**
   * Creates an instance of Text.
   * @constructor
   * @param {string} text
   * @param {object} options
   */
  constructor(text = "", options = {}) {
    const canvas = document.createElement("canvas");

    super(new Texture(canvas, true));

    this.$canvas = canvas;
    this.$ctx = canvas.getContext("2d", {
      alpha: true,
    });

    this.text = text;
    this.fontSize = options.fontSize ?? 12;
    this.lineHeight = options.lineHeight ?? 1.3;
    this.fontFamily = options.fontFamily ?? "sans-serif";
    this.fontColor = options.fontColor ?? "#000";
    this.align = options.align ?? "left";
  }

  /**  * Set/Get text
   * @type {string}
   */
  get text() {
    return this.$text;
  }

  set text(v) {
    this.$text = v;
    this.$updateFv = this.$updateTexture;
  }

  /**
   * Set/Get font size
   * @type {number}
   */
  get fontSize() {
    return this.$fontSize;
  }

  set fontSize(v) {
    this.$fontSize = v;
    this.$updateFv = this.$updateTexture;
  }

  /**
   * Set/Get font family
   * @type {string}
   */
  get fontFamily() {
    return this.$fontFamily;
  }

  set fontFamily(v) {
    this.$fontFamily = v;
    this.$updateFv = this.$updateTexture;
  }

  /**
   * Set/Get font color
   * @type {string}
   */
  get fontColor() {
    return this.$fontColor;
  }

  set fontColor(v) {
    this.$fontColor = v;
    this.$updateFv = this.$updateTexture;
  }

  /**
   * Set/Get text align
   * @type {string}
   */
  get align() {
    return this.$align;
  }

  set align(v) {
    this.$align = v;
    this.$updateFv = this.$updateTexture;
  }

  /**
   * Set/Get line height (multiplier of font size)
   * @type {number}
   */
  get lineHeight() {
    return this.$lineHeight;
  }

  set lineHeight(v) {
    this.$lineHeight = v;
    this.$updateFv = this.$updateTexture;
  }

  update() {
    super.update();
    this.transformUpdated ? this.$updateTexture() : this.$updateFv();
  }

  $updateTexture() {
    this.$updateFv = noop;

    const { $ctx, $canvas, $align, $fontSize, $lineHeight, transform } = this;
    const lineHeight = $lineHeight * $fontSize;
    const maxWidth = transform.width;

    $canvas.width = transform.width;
    $canvas.height = transform.height;

    $ctx.font = $fontSize + "px " + this.$fontFamily;
    $ctx.textBaseline = "top";
    $ctx.textAlign = $align;
    $ctx.fillStyle = this.$fontColor;

    const lines = layoutText($ctx, this.$text, maxWidth);
    const x = $align === "center" ? maxWidth / 2 : $align === "right" ? maxWidth : 0;

    for (let i = 0, l = lines.length; i < l; i++) {
      const line = lines[i];
      const y = lineHeight * i;

      $ctx.fillText(line, x, y);
    }

    this.texture.updateSize();
  }
}