Skip to content

API Reference ​

@tecack/frontend ​

createTecack() ​

Creates Tecack instance for drawing on canvas.

  • Type ​

    ts
    function createTecack(options?: TecackOptions): Tecack;
    function createTecack(options?: TecackOptions): Tecack;
  • Example ​

    ts
    import { createTecack } from "@tecack/frontend";
    
    const tecack = createTecack();
    import { createTecack } from "@tecack/frontend";
    
    const tecack = createTecack();

TecackOptions.backgroundPainter ​

  • Type ​

    ts
    export interface TecackOptions {
      backgroundPainter?: (el: HTMLCanvasElement) => void;
    }
    export interface TecackOptions {
      backgroundPainter?: (el: HTMLCanvasElement) => void;
    }
  • Example ​

    if you want to paint fixed background, configure background painter

    ts
    import { createTecack } from "@tecack/frontend";
    
    const tecack = createTecack({
      backgroundPainter: canvas => {
        const ctx = canvas.getContext("2d");
        if (!ctx) return;
        const [w, h] = [el.width, el.height];
        ctx.fillStyle = "#ccc";
        ctx.fillRect(0, 0, w, h);
      },
    });
    import { createTecack } from "@tecack/frontend";
    
    const tecack = createTecack({
      backgroundPainter: canvas => {
        const ctx = canvas.getContext("2d");
        if (!ctx) return;
        const [w, h] = [el.width, el.height];
        ctx.fillStyle = "#ccc";
        ctx.fillRect(0, 0, w, h);
      },
    });

Tecack.mount() ​

Mounts Tecack instance to canvas element.

  • Type ​

    ts
    function mount(selector: string): void | InitializeError;
    function mount(selector: string): void | InitializeError;
  • Example ​

    ts
    import { createTecack, InitializeError } from "@tecack/frontend";
    
    const tecack = createTecack();
    const res = tecack.mount("#my-canvas");
    if (res instanceof InitializeError) {
      // handle error
    }
    import { createTecack, InitializeError } from "@tecack/frontend";
    
    const tecack = createTecack();
    const res = tecack.mount("#my-canvas");
    if (res instanceof InitializeError) {
      // handle error
    }

Tecack.unmount() ​

unmounts canvas element from Tecack instance.

The contents of the tecack instance are retained, only the association with the DOM is removed.
(Discard retention of event listeners and $el's.)

In the default state, canvas is cleaned up and the drawing content is overwritten in the background if backgroundPainter is set.

  • Type ​

    ts
    function unmount(options?: {
      /** default: `true` */
      cleanCanvas?: boolean;
      /**
       * default: `false`
       *
       * When this option is enabled, the cleanCanvas option is ignored.
       */
      force?: boolean;
    }): void;
    function unmount(options?: {
      /** default: `true` */
      cleanCanvas?: boolean;
      /**
       * default: `false`
       *
       * When this option is enabled, the cleanCanvas option is ignored.
       */
      force?: boolean;
    }): void;
  • Example ​

    ts
    import { createTecack, InitializeError } from "@tecack/frontend";
    
    const tecack = createTecack();
    tecack.mount("#my-canvas");
    tecack.unmount();
    import { createTecack, InitializeError } from "@tecack/frontend";
    
    const tecack = createTecack();
    tecack.mount("#my-canvas");
    tecack.unmount();
    ts
    // setting cleanCanvas to false will keep the current canvas drawing state
    tecack.unmount({ cleanCanvas: false });
    // setting cleanCanvas to false will keep the current canvas drawing state
    tecack.unmount({ cleanCanvas: false });
    ts
    // umount the canvas with a complete cleanup (Background is not rendered.)
    tecack.unmount({ force: false });
    // umount the canvas with a complete cleanup (Background is not rendered.)
    tecack.unmount({ force: false });

Tecack.deleteLast() ​

Deletes last stroke from canvas and instance internal data.

  • Type ​

    ts
    function deleteLast(): void | CanvasCtxNotFoundError;
    function deleteLast(): void | CanvasCtxNotFoundError;
  • Example ​

    ts
    import { createTecack, CanvasCtxNotFoundError } from "@tecack/frontend";
    
    const tecack = createTecack();
    tecack.mount("#my-canvas");
    
    const deleteLastButton = document.getElementById("delete-last");
    deleteLastButton.addEventListener("click", () => {
      const res = tecack.deleteLast();
      if (res instanceof CanvasCtxNotFoundError) {
        // handle error
      }
    });
    import { createTecack, CanvasCtxNotFoundError } from "@tecack/frontend";
    
    const tecack = createTecack();
    tecack.mount("#my-canvas");
    
    const deleteLastButton = document.getElementById("delete-last");
    deleteLastButton.addEventListener("click", () => {
      const res = tecack.deleteLast();
      if (res instanceof CanvasCtxNotFoundError) {
        // handle error
      }
    });

Tecack.erase() ​

Erases all strokes from canvas and instance internal data.

  • Type ​

    ts
    function erase(): void | CanvasCtxNotFoundError;
    function erase(): void | CanvasCtxNotFoundError;
  • Example ​

    ts
    import { createTecack, CanvasCtxNotFoundError } from "@tecack/frontend";
    
    const tecack = createTecack();
    tecack.mount("#my-canvas");
    
    const eraseButton = document.getElementById("erase");
    eraseButton.addEventListener("click", () => {
      const res = tecack.erase();
      if (res instanceof CanvasCtxNotFoundError) {
        // handle error
      }
    });
    import { createTecack, CanvasCtxNotFoundError } from "@tecack/frontend";
    
    const tecack = createTecack();
    tecack.mount("#my-canvas");
    
    const eraseButton = document.getElementById("erase");
    eraseButton.addEventListener("click", () => {
      const res = tecack.erase();
      if (res instanceof CanvasCtxNotFoundError) {
        // handle error
      }
    });

Tecack.getStrokes() ​

Get strokes data from instance internal.
You can use this data for restore strokes or backend recognition.

  • Type ​

    ts
    function getStrokes(): Readonly<Array<TecackStroke>>;
    function getStrokes(): Readonly<Array<TecackStroke>>;
  • Example ​

    ts
    import { createTecack } from "@tecack/frontend";
    
    const tecack = createTecack();
    tecack.mount("#my-canvas");
    
    const strokes = tecack.getStrokes();
    console.log(strokes);
    import { createTecack } from "@tecack/frontend";
    
    const tecack = createTecack();
    tecack.mount("#my-canvas");
    
    const strokes = tecack.getStrokes();
    console.log(strokes);
    ts
    import { recognize } from "@tecack/backend";
    
    const strokes = tecack.getStrokes();
    const candidates = recognize(strokes);
    import { recognize } from "@tecack/backend";
    
    const strokes = tecack.getStrokes();
    const candidates = recognize(strokes);

Tecack.restoreFromStrokes() ​

Restores canvas strokes and internal data from existing strokes data.

  • Type ​

    ts
    function restoreFromStrokes(
      strokesMut: Readonly<Array<TecackStroke>>,
      options?: {
        /** default: `true` */
        withDraw: boolean;
      },
    ): void;
    function restoreFromStrokes(
      strokesMut: Readonly<Array<TecackStroke>>,
      options?: {
        /** default: `true` */
        withDraw: boolean;
      },
    ): void;
  • Example ​

    ts
    const strokes = JSON.parse(localStorage.getItem("strokes"));
    tecack.restoreFromStrokes(strokes);
    const strokes = JSON.parse(localStorage.getItem("strokes"));
    tecack.restoreFromStrokes(strokes);

Tecack.drawStrokeOrder() ​

It draws the stroke order on the strokes entered into the Canvas.

  • Type ​

    ts
    function drawStrokeOrder(options?: DrawStrokeOrderOptions): void | CanvasCtxNotFoundError;
    function drawStrokeOrder(options?: DrawStrokeOrderOptions): void | CanvasCtxNotFoundError;
  • Example ​

    ts
    tecack.drawStrokeOrder();
    tecack.drawStrokeOrder();

DrawStrokeOrderOptions ​

Options for Tecack.drawStrokeOrder()

  • Type ​

    ts
    export interface DrawStrokeOrderOptions {
      withColor?: boolean;
      colorSet?: Array<string>;
      font?: {
        family?: string;
        size?: string;
      };
    }
    export interface DrawStrokeOrderOptions {
      withColor?: boolean;
      colorSet?: Array<string>;
      font?: {
        family?: string;
        size?: string;
      };
    }

DrawStrokeOrderOptions.withColor ​

When withColor is enabled, it draws each stroke in a different color.
This is to make it easier to understand which stroke order corresponds to which stroke.
Please refer to the colorSet to see which colors will be used for the drawing.

default: false

DrawStrokeOrderOptions.colorSet ​

This is the set of colors used when withColor is enabled.
The index of the color set (array) corresponds to the stroke order, and if the stroke order exceeds the length of the color set, it will cycle through.

WARNING

Please note that the colors (strings) registered as colorSet must be six-digit hexadecimal numbers starting with #.
(Shortened three-digit notation, specific color names, and rgb notation cannot be used.)

default:

ts
// prettier-ignore
/** based on https://kanjivg.tagaini.net/viewer.html */
[
  "#bf0000", "#bf5600", "#bfac00", "#7cbf00", "#26bf00",
  "#00bf2f", "#00bf85", "#00a2bf", "#004cbf", "#0900bf",
  "#5f00bf", "#b500bf", "#bf0072", "#bf001c", "#bf2626",
  "#bf6b26", "#bfaf26", "#89bf26", "#44bf26", "#26bf4c",
  "#26bf91", "#26a8bf", "#2663bf", "#2d26bf", "#7226bf",
  "#b726bf", "#bf2682", "#bf263d", "#bf4c4c", "#bf804c",
]
// prettier-ignore
/** based on https://kanjivg.tagaini.net/viewer.html */
[
  "#bf0000", "#bf5600", "#bfac00", "#7cbf00", "#26bf00",
  "#00bf2f", "#00bf85", "#00a2bf", "#004cbf", "#0900bf",
  "#5f00bf", "#b500bf", "#bf0072", "#bf001c", "#bf2626",
  "#bf6b26", "#bfaf26", "#89bf26", "#44bf26", "#26bf4c",
  "#26bf91", "#26a8bf", "#2663bf", "#2d26bf", "#7226bf",
  "#b726bf", "#bf2682", "#bf263d", "#bf4c4c", "#bf804c",
]

DrawStrokeOrderOptions.font ​

This is the font used when drawing the stroke order.

default:

ts
{
  family: "helvetica", // inspired by https://kanjivg.tagaini.net
  size: "16px",
}
{
  family: "helvetica", // inspired by https://kanjivg.tagaini.net
  size: "16px",
}

@tecack/backend ​

recognize() ​

Recognizes strokes data and returns candidates.

  • Type ​

    ts
    function recognize(
      input: Readonly<Array<TecackStroke>>, 
      dataset: Readonly<Array<TecackDataset>>
    ): string[];
    function recognize(
      input: Readonly<Array<TecackStroke>>, 
      dataset: Readonly<Array<TecackDataset>>
    ): string[];
  • Example ​

    ts
    import { recognize } from "@tecack/backend";
    import { KANJI_DATASET } from "@tecack/dataset";
    
    const candidates = recognize(strokes, [...KANJI_DATASET, ...myDataset]);
    import { recognize } from "@tecack/backend";
    import { KANJI_DATASET } from "@tecack/dataset";
    
    const candidates = recognize(strokes, [...KANJI_DATASET, ...myDataset]);

@tecack/shared ​

encodeStroke() / decodeStroke() ​

Encodes Array<TecackStroke> data to minimize size.
And, decodes encoded string.

  • Type ​

    ts
    function encodeStroke(strokes: Readonly<Array<TecackStroke>>): string;
    function decodeStroke(encoded: string): Array<TecackStroke> | DecodeError;
    function encodeStroke(strokes: Readonly<Array<TecackStroke>>): string;
    function decodeStroke(encoded: string): Array<TecackStroke> | DecodeError;
  • Example ​

    ts
    // on client
    import { encodeStroke } from "@tecack/shared";
    
    const recBtn = document.getElementById("recognize-btn");
    recBtn.addEventListener("click", async () => {
      const strokes = tecack.getStrokes();
      const encoded = encodeStroke(strokes); // here
      const res = await fetch("http://my-api.dev/recognize", {
        method: "POST",
        body: JSON.stringify({ strokes: encoded }),
      });
    });
    // on client
    import { encodeStroke } from "@tecack/shared";
    
    const recBtn = document.getElementById("recognize-btn");
    recBtn.addEventListener("click", async () => {
      const strokes = tecack.getStrokes();
      const encoded = encodeStroke(strokes); // here
      const res = await fetch("http://my-api.dev/recognize", {
        method: "POST",
        body: JSON.stringify({ strokes: encoded }),
      });
    });
    ts
    // on server
    import { decodeStroke } from "@tecack/shared";
    import { recognize } from "@tecack/backend";
    import { KANJI_DATASET } from "@tecack/dataset";
    
    // ex1: recognize
    app.post("/recognize", async c => {
      const req = await c.req.json();
      const decoded = decodeStroke(req.strokes); // here
      if (decoded instanceof DecodeError) {
        return c.json({ error: decoded.message });
      }
      const candidate = recognize(decoded, KANJI_DATA_SET);
      return c.json(candidate);
    });
    
    // ex2: save to database as encoded text data
    app.post("/save-stroke", async c => {
      const req = await c.req.json();
      await myDb.save(req.strokes); // save to database as encoded text data
      return c.json({ ok: true });
    });
    // on server
    import { decodeStroke } from "@tecack/shared";
    import { recognize } from "@tecack/backend";
    import { KANJI_DATASET } from "@tecack/dataset";
    
    // ex1: recognize
    app.post("/recognize", async c => {
      const req = await c.req.json();
      const decoded = decodeStroke(req.strokes); // here
      if (decoded instanceof DecodeError) {
        return c.json({ error: decoded.message });
      }
      const candidate = recognize(decoded, KANJI_DATA_SET);
      return c.json(candidate);
    });
    
    // ex2: save to database as encoded text data
    app.post("/save-stroke", async c => {
      const req = await c.req.json();
      await myDb.save(req.strokes); // save to database as encoded text data
      return c.json({ ok: true });
    });