import { MathUtils, Flags } from '@uino/base-thing';
import { Utils } from '../common/Utils';
import { BaseCSSComponent } from './BaseCSSComponent';
let _position_1 = MathUtils.createVec3();
let _position_2 = MathUtils.createVec3();
const Flag = {
AutoRemove: 1 << 0,
AutoBind: 1 << 1
}
/**
* @class CSS2DComponent
* CSS 2D 组件。
* @memberof THING
* @extends THING..BaseCSSComponent
* @public
*/
class CSS2DComponent extends BaseCSSComponent {
constructor(options) {
super(options);
this._offset = null;
this._pivot = [0.5, 0.5];
this._flags = new Flags();
this._flags.enable(Flag.AutoRemove, true);
this._flags.enable(Flag.AutoBind, false);
this._factor = 1;
}
// #region Private
_isVisible(screenPosition) {
// Check whether behind camera
let z = screenPosition[2];
if (z > 1) {
return false;
}
return true;
}
// #endregion
// #region Overrides
onRemove() {
if (this._domElement && this.autoRemove) {
let parentNode = this._domElement.parentNode;
if (parentNode) {
parentNode.removeChild(this._domElement);
}
}
this._domElement = null;
super.onRemove();
}
onRender(renderLayout) {
let domElement = this._domElement;
if (!domElement) {
return;
}
// Get the center position of screen
let center;
if (this._offset) {
center = renderLayout.selfToWorld(this._offset, false, _position_1);
}
else {
center = renderLayout.getCenter(_position_1);
}
// Get the screen position
let screenPosition = renderLayout.worldToScreen(center, _position_2);
let isVisible = this._isVisible(screenPosition);
// Auto update visible state
if (this.updateDomElementVisibility(isVisible)) {
// Update Z-Index value
if (Utils.isNull(this._zIndex)) {
let zIndex = 1000 - Math.ceil(screenPosition[2] * 10000 - 9900);
domElement._setZIndex(zIndex);
}
// Get width and height by threshold
const threshold = 1.5;
let width = domElement._getOffsetWidth(threshold);
let height = domElement._getOffsetHeight(threshold);
// Get left and top position by pivot and size
let position = domElement._getPositionByPivot(this._delegate.domElement, width, height, screenPosition, this._pivot);
domElement._setLeft(position[0]);
domElement._setTop(position[1]);
}
}
// #endregion
/**
* 获取/设置是否在移除时自动移除 DOM 元素。
* @type {boolean}
* @public
* @example
* // 组件移除时自动移除 DOM 元素
* component.autoRemove = true;
*/
get autoRemove() {
return this._flags.has(Flag.AutoRemove);
}
set autoRemove(value) {
this._flags.enable(Flag.AutoRemove, value);
}
/**
* 获取/设置是否在添加到场景时自动绑定 DOM 元素。
* @type {boolean}
* @public
* @example
* // 添加到场景时自动绑定 DOM 元素
* component.autoBind = true;
*/
get autoBind() {
return this._flags.has(Flag.AutoBind);
}
set autoBind(value) {
if (this._flags.enable(Flag.AutoBind, value)) {
let app = this.object.app;
if (value) {
this._domElement.style.position = "absolute"; // Add absolute positioning
app.container.appendChild(this._domElement);
}
else {
app.container.removeChild(this._domElement);
}
}
}
/**
* 获取/设置对象在自身空间中的偏移量,null表示使用对象的边界框中心。
* @type {Array<number>}
* @public
* @example
* // 设置偏移量为 [10, 20]
* component.offset = [10, 20];
*/
get offset() {
return this._offset;
}
set offset(value) {
if (value) {
this._offset = value.slice(0);
}
else {
this._offset = null;
}
}
/**
* 获取/设置从左下角计算的轴心点。
* @type {Array<number>}
* @public
* @example
* // 设置轴心点为中心
* component.pivot = [0.5, 0.5];
*/
get pivot() {
return this._pivot;
}
set pivot(value) {
if (value) {
this._pivot = value.slice(0);
}
else {
this._pivot = [0.5, 0.5];
}
}
/**
* 获取/设置缩放因子。
* @type {number}
* @public
* @example
* // 设置缩放因子为 2
* component.factor = 2;
*/
get factor() {
return this._factor;
}
set factor(value) {
if (Utils.isValid(value)) {
this._factor = value;
if (this._domElement) {
this._domElement.style.transform = `scale(${value}, ${value})`
}
}
}
}
export { CSS2DComponent }