ReCreateJS/txtjs

View on GitHub
src/TextContainer.ts

Summary

Maintainability
A
3 hrs
Test Coverage
B
80%
import FontLoader from "./FontLoader";
import Case from "./Case";
import { ConstructObj, Style } from "./Interfaces";
import Accessibility from "./Accessibility";
import Character from "./Character";

/**
 * Common aspects of top-level Text classes
 */
export default abstract class TextContainer extends createjs.Container {
  text = "";
  original: ConstructObj = null;
  style: Style[] = null;
  font = "belinda";
  characterCase: Case = Case.NORMAL;

  //accessibility
  accessibilityText: string = null;
  accessibilityPriority = 2;
  accessibilityId: number = null;

  protected loadFonts() {
    const fonts = [this.font].concat(this.fontsFromCharacterStyles(this.style));
    FontLoader.load(this, fonts);
  }

  //called when text is rendered
  complete() {
    //placeholder
  }

  //called when font has loaded
  fontLoaded() {
    this.layout();
  }

  //call stage.update to render canvas
  //overload to support deferred rendering
  render() {
    this.stage.update();
  }

  abstract layout();

  addAccessibility() {
    Accessibility.set(this);
  }

  private fontsFromCharacterStyles(styles) {
    const styleFonts = [];
    if (styles) {
      for (let i = 0; i < styles.length; ++i) {
        if (styles[i] != undefined && styles[i].font != undefined) {
          styleFonts.push(styles[i].font);
        }
      }
    }
    return styleFonts;
  }

  getCharCodeAt(index: number): number {
    if (this.characterCase == Case.NORMAL) {
      return this.text.charAt(index).charCodeAt(0);
    } else if (this.characterCase == Case.UPPER) {
      return this.text
        .charAt(index)
        .toUpperCase()
        .charCodeAt(0);
    } else if (this.characterCase == Case.LOWER) {
      return this.text
        .charAt(index)
        .toLowerCase()
        .charCodeAt(0);
    } else if (this.characterCase == Case.SMALL_CAPS) {
      return this.text
        .charAt(index)
        .toUpperCase()
        .charCodeAt(0);
    } else {
      //fallback case for unknown.
      return this.text.charAt(index).charCodeAt(0);
    }
  }

  // TODO: this code needs unit tests before it gets changed any further
  /**
   * Figure out how many characters a ligature covers,
   * and swap character glyph
   * @param char
   * @param ligTarget
   */
  protected ligatureSwap(char: Character, ligTarget: string) {
    let advanceBy = 0;
    const firstChar = ligTarget.charAt(0);
    const firstLigature = char._font.ligatures[firstChar];
    //1 char match
    if (firstLigature) {
      //2 char match
      if (firstLigature[ligTarget.charAt(1)]) {
        //3 char match
        if (firstLigature[ligTarget.charAt(1)][ligTarget.charAt(2)]) {
          //4 char match
          if (
            firstLigature[ligTarget.charAt(1)][ligTarget.charAt(2)][
              ligTarget.charAt(3)
            ]
          ) {
            //swap 4 char ligature
            char.setGlyph(
              firstLigature[ligTarget.charAt(1)][ligTarget.charAt(2)][
                ligTarget.charAt(3)
              ].glyph
            );
            advanceBy = 3;
          } else {
            //swap 3 char ligature
            char.setGlyph(
              firstLigature[ligTarget.charAt(1)][ligTarget.charAt(2)].glyph
            );
            advanceBy = 2;
          }
        } else {
          //swap 2 char ligature
          char.setGlyph(firstLigature[ligTarget.charAt(1)].glyph);
          advanceBy = 1;
        }
      }
    }
    return advanceBy;
  }
}