lazy-widgets
Version:
Typescript retained mode GUI for the HTML canvas API
60 lines • 2.78 kB
JavaScript
import { Msg } from '../core/Strings.js';
import { AsyncImageBitmap } from './AsyncImageBitmap.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 TextImageBitmap extends AsyncImageBitmap {
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 = -1;
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.max(ascent - hangingBaseline, descent);
this.height = hangingBaseline + pad * 2;
this.width = Math.max(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, this.width * 0.5, this.height - pad);
createImageBitmap(canvas).then((bitmap) => {
this._presentationHash++;
this._bitmap = bitmap;
});
}
get bitmap() {
return this._bitmap;
}
get presentationHash() {
return this._presentationHash;
}
}
//# sourceMappingURL=TextImageBitmap.js.map