Source: objects/Label.js

import { Utils } from '../common/Utils'
import { Marker } from './Marker';
import { ImageTexture } from '../resources/ImageTexture';
import { CanvasRenderer } from '../renderers/CanvasRenderer';
import { AlignType, ImageWrapType, FontWeight } from '../const';

const __ = {
	private: Symbol('private'),
}

/**
 * @class Label
 * The text label object.
 * @memberof THING
 * @extends THING.Marker
 * @public
 */
class Label extends Marker {

	static canvasRenderer = null;

	/**
	 * The label object that show text in plane in scene.
	 * @param {Object} param The initial parameters.
	 */
	constructor(param = {}) {
		super(param);

		// Renderer
		Label.canvasRenderer = Label.canvasRenderer || new CanvasRenderer();

		this[__.private] = {};
		let _private = this[__.private];

		// The font info
		_private.text = '';
		_private.fontInfo = {};

		_private.image = new ImageTexture();
		_private.image.wrapType = ImageWrapType.ClampToEdge;

		_private.fontInfo = {
			type: 'Arial',
			size: 10,
			lineWidth: +Infinity,
			lineHeight: 0, // 0 indicates use font size as default
			color: '#FFFFFF',
			shadowColor: '#000000',
			shadowAlpha: 1,
			shadowAngle: 45,
			shadowBlur: 1,
			shadowDistance: 1,
			alignType: AlignType.Center,
			richText: false,
			fontWeight: FontWeight.Normal
		};

		// Sync text
		_private.text = Utils.parseValue(param['fontText'], _private.text);

		// Sync font info
		var fontInfo = _private.fontInfo;
		fontInfo.type = Utils.parseValue(param['fontType'], fontInfo.type);
		fontInfo.size = Utils.parseValue(param['fontSize'], fontInfo.size);
		fontInfo.lineWidth = Utils.parseValue(param['fontLineWidth'], fontInfo.lineWidth);
		fontInfo.lineHeight = Utils.parseValue(param['fontLineHeight'], fontInfo.lineHeight);
		fontInfo.color = Utils.parseColor(param['fontColor'], fontInfo.color);
		fontInfo.shadowColor = Utils.parseColor(param['fontShadowColor'], fontInfo.shadowColor);
		fontInfo.shadowAlpha = Utils.parseValue(param['fontShadowAlpha'], fontInfo.shadowAlpha);
		fontInfo.shadowAngle = Utils.parseValue(param['fontShadowAngle'], fontInfo.shadowAngle);
		fontInfo.shadowBlur = Utils.parseValue(param['fontShadowBlur'], fontInfo.shadowBlur);
		fontInfo.shadowDistance = Utils.parseValue(param['fontShadowDistance'], fontInfo.shadowDistance);
		fontInfo.alignType = Utils.parseValue(param['fontAlignType'], fontInfo.alignType);
		fontInfo.richText = Utils.parseValue(param['richText'], fontInfo.richText);
		fontInfo.fontWeight = Utils.parseValue(param['fontWeight'], fontInfo.fontWeight);

		// Set render order to high value for rendering in the end
		if (Utils.isNull(param['renderOrder'])) {
			this.renderOrder = 1000 * 1000;
		}

		this.autoFitBodyScale = Utils.parseValue(param['autoFitBodyScale'], true);
		this.scaleFactor = Utils.parseValue(param['scaleFactor'], 0.035);

		// Seems we need to dirty here to load resources
		this.setDirty(true);
	}

	// #region Private

	// #endregion

	// #region Overrides

	onCopy(object) {
		super.onCopy(object);

		let _private = this[__.private];

		_private.text = object.fontText;
		Object.assign(_private.fontInfo, object.fontInfo);

		this.onRefresh();
	}

	onLoadResource(options, resolve, reject) {
		super.onLoadResource(options, () => {
			this.onRefresh();

			resolve();
		}, reject);
	}

	onRefresh() {
		let _private = this[__.private];

		// Update text
		if (_private.text) {
			let canvasRenderer = Label.canvasRenderer;
			canvasRenderer.drawText(_private.text, _private.fontInfo);

			// Update image
			_private.image.resource = canvasRenderer.getImageData();
			if (this.style.image != _private.image) {
				this.style.image = _private.image;
			}
		}

		super.onRefresh();
	}

	// #endregion

	/**
	 * Get/Set font text.
	 * @type {String}
	 * @public
	 */
	get fontText() {
		let _private = this[__.private];

		return _private.text;
	}
	set fontText(value) {
		let _private = this[__.private];

		_private.text = value;

		this.setDirty();
	}

	/**
	 * Get font info.
	 * @type {Object}
	 * @private
	 */
	get fontInfo() {
		let _private = this[__.private];

		return _private.fontInfo;
	}

	/**
	 * Get/Set font type.
	 * @type {String}
	 * @public
	 */
	get fontType() {
		let _private = this[__.private];

		return _private.fontInfo.type;
	}
	set fontType(value) {
		let _private = this[__.private];

		_private.fontInfo.type = value;

		this.setDirty();
	}

	/**
	 * Get/Set font size.
	 * @type {Number}
	 * @public
	 */
	get fontSize() {
		let _private = this[__.private];

		return _private.fontInfo.size;
	}
	set fontSize(value) {
		let _private = this[__.private];

		_private.fontInfo.size = value;

		this.setDirty();
	}

	/**
	 * Get/Set font line width.
	 * @type {Number}
	 * @public
	 */
	get fontLineWidth() {
		let _private = this[__.private];

		return _private.fontInfo.lineWidth;
	}
	set fontLineWidth(value) {
		let _private = this[__.private];

		_private.fontInfo.lineWidth = value;

		this.setDirty();
	}

	/**
	 * Get/Set font line height, 0 indicates use font size auto.
	 * @type {Number}
	 * @public
	 */
	get fontLineHeight() {
		let _private = this[__.private];

		return _private.fontInfo.lineHeight;
	}
	set fontLineHeight(value) {
		let _private = this[__.private];

		_private.fontInfo.lineHeight = value;

		this.setDirty();
	}

	/**
	 * Get/Set font color.
	 * @type {Number|String|Array<Number>}
	 * @public
	 */
	get fontColor() {
		let _private = this[__.private];

		return Utils.colorToHexString(_private.fontInfo.color);
	}
	set fontColor(value) {
		let _private = this[__.private];

		_private.fontInfo.color = Utils.parseColor(value);

		this.setDirty();
	}

	/**
	 * Get/Set font shadow color.
	 * @type {Number|String|Array<Number>}
	 * @public
	 */
	get fontShadowColor() {
		let _private = this[__.private];

		return Utils.colorToHexString(_private.fontInfo.shadowColor);
	}
	set fontShadowColor(value) {
		let _private = this[__.private];

		_private.fontInfo.shadowColor = Utils.parseColor(value);

		this.setDirty();
	}

	/**
	 * Get/Set font shadow alpha.
	 * @type {Number}
	 * @public
	 */
	get fontShadowAlpha() {
		let _private = this[__.private];

		return _private.fontInfo.shadowAlpha;
	}
	set fontShadowAlpha(value) {
		let _private = this[__.private];

		_private.fontInfo.shadowAlpha = value;

		this.setDirty();
	}

	/**
	 * Get/Set font shadow angle.
	 * @type {Number}
	 * @public
	 */
	get fontShadowAngle() {
		let _private = this[__.private];

		return _private.fontInfo.shadowAngle;
	}
	set fontShadowAngle(value) {
		let _private = this[__.private];

		_private.fontInfo.shadowAngle = value;

		this.setDirty();
	}

	/**
	 * Get/Set font shadow blur.
	 * @type {Number}
	 * @public
	 */
	get fontShadowBlur() {
		let _private = this[__.private];

		return _private.fontInfo.shadowBlur;
	}
	set fontShadowBlur(value) {
		let _private = this[__.private];

		_private.fontInfo.shadowBlur = value;

		this.setDirty();
	}

	/**
	 * Get/Set font shadow distance.
	 * @type {Number}
	 * @public
	 */
	get fontShadowDistance() {
		let _private = this[__.private];

		return _private.fontInfo.shadowDistance;
	}
	set fontShadowDistance(value) {
		let _private = this[__.private];

		_private.fontInfo.shadowDistance = value;

		this.setDirty();
	}

	/**
	 * Get/Set font align type.
	 * @type {AlignType}
	 * @public
	 */
	get fontAlignType() {
		let _private = this[__.private];

		return _private.fontInfo.alignType;
	}
	set fontAlignType(value) {
		let _private = this[__.private];

		_private.fontInfo.alignType = value;

		this.setDirty();
	}

	/**
	 * Enable/Disable rich text.
	 * @type {Boolean}
	 * @public
	 */
	get richText() {
		let _private = this[__.private];

		return _private.fontInfo.richText;
	}
	set richText(value) {
		let _private = this[__.private];

		_private.fontInfo.richText = value;

		this.setDirty();
	}

	get isLabel() {
		return true;
	}

	/**
	 * Get/Set font weight.
	 * @type {FontWeight}
	 * @public
	 */
	get fontWeight() {
		let _private = this[__.private];

		return _private.fontInfo.fontWeight;
	}
	set fontWeight(value) {
		let _private = this[__.private];

		_private.fontInfo.fontWeight = value;

		this.setDirty();
	}

}

export { Label }