UNPKG

lazy-widgets

Version:

Typescript retained mode GUI for the HTML canvas API

64 lines 3.09 kB
import { Msg } from '../core/Strings.js'; import { AsyncMedia } from './AsyncMedia.js'; import { BackingMediaEventType } from './BackingMediaEventType.js'; import { incrementUint31 } from './incrementUint31.js'; import { measureTextDims } from './measureTextDims.js'; /** * Renders text as an ImageBitmap, which can then be used in widgets that * consume a {@link BackingMediaSource}, like {@link Icon}. Useful for using * font icons instead of images. * * Height is retreived by measuring the fontBoundingBoxAscent and * fontBoundingBoxDescent (falling back to actualBoundingBoxAscent and * actualBoundingBoxDescent), as well as the hangingBaseline (falling back to * the actualBoundingBoxAscent of the `M` character). Width is measured from the * text being rendered, however, it's set to be the same as the height if it's * smaller than the height to avoid issues with thin font icons (such as * vertical ellipsis). The font is assumed to already be loaded by the time this * class is instantiated. * * Throws if a scratch canvas can't be created. */ export class TextMedia extends AsyncMedia { constructor(text, font, fillStyle, options) { var _a, _b, _c, _d; super(); this.text = text; this.font = font; this.fillStyle = fillStyle; this._bitmap = null; this._presentationHash = 0; const metrics = measureTextDims(text, font); const ascent = (_a = metrics.fontBoundingBoxAscent) !== null && _a !== void 0 ? _a : metrics.actualBoundingBoxAscent; const descent = (_b = metrics.fontBoundingBoxDescent) !== null && _b !== void 0 ? _b : metrics.actualBoundingBoxDescent; const hangingBaseline = (_c = metrics.hangingBaseline) !== null && _c !== void 0 ? _c : measureTextDims('M', font).actualBoundingBoxAscent; const pad = Math.ceil(Math.max(ascent - hangingBaseline, descent)); this.height = Math.ceil(hangingBaseline + pad * 2); this.width = Math.max(Math.ceil(metrics.width), this.height); this.resolution = (_d = options === null || options === void 0 ? void 0 : options.resolution) !== null && _d !== void 0 ? _d : 1; const canvas = document.createElement('canvas'); canvas.width = this.width; canvas.height = this.height; const context = canvas.getContext('2d'); if (!context) { throw new Error(Msg.CANVAS_CONTEXT); } context.textAlign = 'center'; context.font = font; context.fillStyle = fillStyle; context.fillText(text, Math.trunc(this.width * 0.5), this.height - pad); createImageBitmap(canvas).then((bitmap) => { this._presentationHash = incrementUint31(this._presentationHash); this._bitmap = bitmap; this.dispatchEvent(BackingMediaEventType.Loaded); this.dispatchEvent(BackingMediaEventType.Dirty); }); } get currentFrame() { return this._bitmap; } get presentationHash() { return this._presentationHash; } } //# sourceMappingURL=TextMedia.js.map