entity_Label.ts#

CODE
import * as utils from "../utils/shared";
import {BaseBillboard, IBaseBillboardParams} from "./BaseBillboard";
import {LOCK_FREE, LOCK_UPDATE} from "./LabelWorker";
import {NumberArray4, Vec4} from "../math/Vec4";
import {FontAtlas} from "../utils/FontAtlas";
import {LabelHandler} from "./LabelHandler";
export interface ILabelParams extends IBaseBillboardParams {
text?: string;
face?: string;
size?: number;
opacity?: number;
outline?: number;
outlineColor?: string | NumberArray4 | Vec4;
align?: string;
isRTL?: boolean;
letterSpacing?: number;
}
const ALIGN: Record<string, number> = {
RIGHT: 0,
LEFT: 1,
CENTER: 2
};
/**
* Text align options.
* @readonly
* @enum {number}
*/
const STR2ALIGN: Record<string, number> = {
left: ALIGN.LEFT,
right: ALIGN.RIGHT,
center: ALIGN.CENTER
};
/**
* Billboard text label.
* @class
* @extends {BaseBillboard}
* @param {Object} [options] - Label options:
* @param {Vec3|Array.<number>} [options.position] - Billboard spatial position.
* @param {number} [options.rotation] - Screen angle rotation.
* @param {Vec4|string|Array.<number>} [options.color] - Billboard color.
* @param {Vec3|Array.<number>} [options.alignedAxis] - Billboard aligned vector.
* @param {Vec3|Array.<number>} [options.offset] - Billboard center screen offset.
* @param {boolean} [options.visibility] - Visibility.
* @param {string} [options.text] - Text string.
* @param {string} [options.face] - HTML5 font face.
* @param {number} [options.size] - Font size in pixels.
* @param {string} [options.style] - HTML5 font style. Example 'normal', 'italic'.
* @param {string} [options.weight] - HTML5 font weight. Example 'normal', 'bold'.
* @param {number} [options.outline] - Text outline size. 0 - no outline, 1 - maximum outline. Default 0.58.
* @param {Vec4|string|Array.<number>} [options.outlineColor] - Outline color.
* @param {string} [options.align] - Text horizontal align: "left", "right" and "center".
*/
class Label extends BaseBillboard {
public override _handler: LabelHandler | null;
/**
* Label text string.
* @protected
* @type {string}
*/
protected _text: string;
/**
* HTML5 font face.
* @private
* @type {string}
*/
protected _face: string;
/**
* Font size in pixels.
* @protected
* @type {number}
*/
protected _size: number;
/**
* Label outline.
* @protected
* @type {number}
*/
protected _outline: number;
/**
* Label outline color.
* @protected
* @type {Vec4}
*/
protected _outlineColor: Vec4;
/**
* Text horizontal align: "left", "right" and "center".
* @private
* @type {Label.ALIGN}
*/
protected _align: number;
/**
* Label font atlas index.
* @protected
* @type {number}
*/
protected _fontIndex: number;
/**
* Font atlas pointer.
* @private
* @type {FontAtlas}
*/
protected _fontAtlas: FontAtlas | null;
protected _isRTL: boolean;
protected _letterSpacing: number;
constructor(options: ILabelParams = {}) {
super(options);
this._handler = null;
this._text = options.text || "";
this._face = utils.defaultString(options.face, "arial");
this._size = options.size || 24;
this._outline = options.outline != undefined ? options.outline : 0.0;
this._outlineColor = utils.createColorRGBA(
options.outlineColor,
new Vec4(0.0, 0.0, 0.0, 1.0)
);
this._align = options.align ? STR2ALIGN[options.align.trim().toLowerCase()] as number || ALIGN.RIGHT : ALIGN.RIGHT;
this._fontIndex = 0;
this._fontAtlas = null;
this._isRTL = options.isRTL || false;
this._letterSpacing = options.letterSpacing || 0;
}
/**
* Set label text.
* @public
* @param {string} text - Text string.
* It can't be bigger than maximum labelHandler _maxLetters value.
*/
public setText(text: string) {
this._text = text.toString();
if (this._isReady && this._handler) {
this._handler.setText(this._handlerIndex, text, this._fontIndex, this._align, this._letterSpacing, this._isRTL);
}
}
/**
* Set text letter spacing.
* @public
* @param {number} spacing - Letter spacing.
*/
public setLetterSpacing(letterSpacing: number) {
this._letterSpacing = letterSpacing;
if (this._isReady && this._handler) {
this._handler.setText(this._handlerIndex, this._text, this._fontIndex, this._align, letterSpacing, this._isRTL);
}
}
/**
* Returns label text letter spacing.
* @public
* @param {number} spacing - Letter spacing.
*/
public getLetterSpacing(): number {
return this._letterSpacing;
}
/**
* Change text direction.
* @public
* @param {boolean} isRTL - Text string.
*/
public setRtl(isRTL: boolean) {
this._isRTL = isRTL;
if (this._isReady && this._handler) {
this._handler.setText(this._handlerIndex, this._text, this._fontIndex, this._align, this._letterSpacing, this._isRTL);
}
}
/**
* Gets current text string.
* @public
* @returns {string}
*/
public getText(): string {
return this._text;
}
/**
* Sets label text align. Could be center, left or right. Left is default.
* @public
* @param {string} align - Text align.
*/
public setAlign(align: string) {
this._align = STR2ALIGN[align.trim().toLowerCase()] as number;
if (this._isReady && this._handler) {
this._handler.setText(this._handlerIndex, this._text, this._fontIndex, this._align, this._letterSpacing, this._isRTL);
} else if (this._lockId !== LOCK_FREE) {
this._lockId = LOCK_UPDATE;
}
}
/**
* Gets label text current alignment.
* @public
* @returns {string}
*/
public getAlign(): number {
return this._align;
}
/**
* Sets font face family.
* @public
* @param {string} face - Font face family.
*/
public setFace(face: string) {
this._face = face.trim();
this.update();
}
/**
* Gets current font face.
* @public
* @returns {string}
*/
public getFace(): string {
return this._face;
}
/**
* Sets label font size in pixels.
* @public
* @param {number} size - Label size in pixels.
*/
public setSize(size: number) {
if (size !== this._size) {
this._size = size;
if (this._isReady && this._handler) {
this._handler.setSizeArr(this._handlerIndex, size);
} else if (this._lockId !== LOCK_FREE) {
this._lockId = LOCK_UPDATE;
}
}
}
/**
* Gets label size in pixels.
* @public
* @returns {number}
*/
public getSize(): number {
return this._size;
}
/**
* Sets text outline border size. Where 0 - is no outline, and 1 - is the maximum outline size.
* @public
* @param {number} outline - Text outline size.
*/
public setOutline(outline: number) {
this._outline = outline;
if (this._isReady && this._handler) {
this._handler.setOutlineArr(this._handlerIndex, outline);
} else if (this._lockId !== LOCK_FREE) {
this._lockId = LOCK_UPDATE;
}
}
/**
* Gets text current outline size.
* @public
* @returns {number}
*/
public getOutline(): number {
return this._outline;
}
/**
* Sets label opacity.
* @public
* @param {number} a - Label opacity.
*/
public override setOpacity(a: number) {
super.setOpacity(a);
this.setOutlineOpacity(a);
}
/**
* Sets text outline color.
* @public
* @param {number} r - Red.
* @param {number} g - Green.
* @param {number} b - Blue.
* @param {number} a - Alpha.
*/
public setOutlineColor(r: number, g: number, b: number, a: number) {
if (a !== this._outlineColor.w || r !== this._outlineColor.x || g !== this._outlineColor.y || b !== this._outlineColor.z) {
this._outlineColor.x = r;
this._outlineColor.y = g;
this._outlineColor.z = b;
this._outlineColor.w = a;
if (this._isReady && this._handler) {
this._handler.setOutlineColorArr(this._handlerIndex, this._outlineColor);
} else if (this._lockId !== LOCK_FREE) {
this._lockId = LOCK_UPDATE;
}
}
}
/**
* Sets text outline color.
* @public
* @param {Vec4} rgba - Color vector.
*/
public setOutlineColor4v(rgba: Vec4) {
this.setOutlineColor(rgba.x, rgba.y, rgba.z, rgba.w);
}
/**
* Sets text outline color HTML string.
* @public
* @param {string} color - HTML string color.
*/
public setOutlineColorHTML(color: string) {
this.setOutlineColor4v(utils.htmlColorToRgba(color));
}
/**
* Gets outline color vector.
* @public
* @returns {Vec4}
*/
public getOutlineColor(): Vec4 {
return this._outlineColor;
}
/**
* Sets outline opacity. Actually outline color alpha value.
* @public
* @param {number} opacity - Outline opacity.
*/
public setOutlineOpacity(opacity: number) {
if (opacity !== this._outlineColor.w) {
this._outlineColor.w = opacity;
if (this._isReady && this._handler) {
this._handler.setOutlineColorArr(this._handlerIndex, this._outlineColor);
} else if (this._lockId !== LOCK_FREE) {
this._lockId = LOCK_UPDATE;
}
}
}
/**
* Gets outline opacity value.
* @public
* @returns {number}
*/
public getOutlineOpacity(): number {
return this._outlineColor.w;
}
/**
* Updates label parameters.
* @public
*/
public async update() {
if (this._fontAtlas) {
const fontIndex = await this._fontAtlas.getFontIndex(this._face);
this._applyFontIndex(fontIndex);
}
}
protected _applyFontIndex(fontIndex: number) {
this._fontIndex = fontIndex;
if (this._isReady && this._handler) {
this._handler.setFontIndexArr(this._handlerIndex, this._fontIndex);
this._handler.setText(this._handlerIndex, this._text, this._fontIndex, this._align, this._letterSpacing, this._isRTL);
} else if (this._lockId !== LOCK_FREE) {
this._lockId = LOCK_UPDATE;
}
}
/**
* Assigns font atlas and update.
* @public
* @param {FontAtlas} fontAtlas - Font atlas.
*/
public assignFontAtlas(fontAtlas: FontAtlas) {
if (!this._fontAtlas) {
this._fontAtlas = fontAtlas;
}
this.update();
}
public override serializeWorkerData(workerId: number): Float32Array | null {
if (this._handler) {
return new Float32Array([
/*0*/workerId,
/*1*/this._handler!._maxLetters,
/*2*/this.getVisibility() ? 1 : 0,
/*3, 4, 5*/this._positionHigh.x, this._positionHigh.y, this._positionHigh.z,
/*6, 7, 8*/this._positionLow.x, this._positionLow.y, this._positionLow.z,
/*9*/this._size,
/*10, 11, 12*/this._offset.x, this._offset.y, this._offset.z,
/*13, 14, 15, 16*/this._color.x, this._color.y, this._color.z, this._color.w,
/*17*/this._rotation,
/*18, 19, 20*/this._alignedAxis.x, this._alignedAxis.y, this._alignedAxis.z,
/*21*/this._fontIndex,
/*22*/this._outline,
/*23, 24, 25, 26*/this._outlineColor.x, this._outlineColor.y, this._outlineColor.z, this._outlineColor.w,
/*27, 28, 29*/this._entity!._pickingColor.x, this._entity!._pickingColor.y, this._entity!._pickingColor.z
]);
}
return null;
}
}
export {Label, ALIGN};