UNPKG

@mapgis/webclient-es6-mapboxgl

Version:

265 lines (238 loc) 9.22 kB
import { Common } from '@mapgis/webclient-es6-service'; const { Zondy } = Common; import {SUtil} from './SUtil'; /** * @private * @class Zondy.LevelRenderer.Transformable * @classdesc 可变换超类,所有支持 Canvas Transform 变换操作的类均是此类的子类。此类不可实例化。 */ class Transformable { /** * @function Zondy.LevelRenderer.Transformable.constructor * @description 构造函数。 */ constructor() { /** * @member {Array.<number>} Zondy.LevelRenderer.Transformable.prototype.position * @description 平移, 默认值:[0, 0]。 */ this.position = [0, 0]; /** * @member {Array.<number>} Zondy.LevelRenderer.Transformable.prototype.rotation * @description 旋转,可以通过数组二三项指定旋转的原点, 默认值:[0, 0, 0]。 */ this.rotation = [0, 0, 0]; /** * @member {Array.<number>} Zondy.LevelRenderer.Transformable.prototype.scale * @description 缩放,可以通过数组三四项指定缩放的原点, 默认值:[1, 1, 0, 0]。 */ this.scale = [1, 1, 0, 0]; /** * @member {boolean} Zondy.LevelRenderer.Transformable.prototype.needLocalTransform * @description 是否变换。默认值:false。 */ this.needLocalTransform = false; /** * @member {boolean} Zondy.LevelRenderer.Transformable.prototype.needTransform * @description 是否有坐标变换。默认值:false。 */ this.needTransform = false; this.CLASS_NAME = "Zondy.LevelRenderer.Transformable"; /** * @function Zondy.LevelRenderer.Transformable.prototype.lookAt * @description 设置图形的朝向。 */ this.lookAt = (function () { var v = SUtil.Util_vector.create(); // {Array{Number}|Float32Array} target return function (target) { if (!this.transform) { this.transform = SUtil.Util_matrix.create(); } var m = this.transform; SUtil.Util_vector.sub(v, target, this.position); if (isAroundZero(v[0]) && isAroundZero(v[1])) { return; } SUtil.Util_vector.normalize(v, v); // Y Axis // TODO Scale origin ? m[2] = v[0] * this.scale[1]; m[3] = v[1] * this.scale[1]; // X Axis m[0] = v[1] * this.scale[0]; m[1] = -v[0] * this.scale[0]; // Position m[4] = this.position[0]; m[5] = this.position[1]; this.decomposeTransform(); function isAroundZero(val) { var EPSILON = 5e-5; return val > -EPSILON && val < EPSILON; } }; })(); } /** * @function Zondy.LevelRenderer.Transformable.prototype.destroy * @description 销毁对象,释放资源。调用此函数后所有属性将被置为 null。 */ destroy() { this.position = null; this.rotation = null; this.scale = null; this.needLocalTransform = null; this.needTransform = null; } /** * @function Zondy.LevelRenderer.Transformable.prototype.updateNeedTransform * @description 更新 needLocalTransform */ updateNeedTransform() { this.needLocalTransform = isNotAroundZero(this.rotation[0]) || isNotAroundZero(this.position[0]) || isNotAroundZero(this.position[1]) || isNotAroundZero(this.scale[0] - 1) || isNotAroundZero(this.scale[1] - 1); function isNotAroundZero(val) { var EPSILON = 5e-5; return val > EPSILON || val < -EPSILON; } } /** * @function Zondy.LevelRenderer.Transformable.prototype.updateTransform * @description 判断是否需要有坐标变换,更新 needTransform 属性。如果有坐标变换, 则从 position, rotation, scale 以及父节点的 transform 计算出自身的 transform 矩阵 */ updateTransform() { this.updateNeedTransform(); if (this.parent) { this.needTransform = this.needLocalTransform || this.parent.needTransform; } else { this.needTransform = this.needLocalTransform; } if (!this.needTransform) { return; } var origin = [0, 0]; var m = this.transform || SUtil.Util_matrix.create(); SUtil.Util_matrix.identity(m); if (this.needLocalTransform) { if ( isNotAroundZero(this.scale[0]) || isNotAroundZero(this.scale[1]) ) { origin[0] = -this.scale[2] || 0; origin[1] = -this.scale[3] || 0; let haveOrigin = isNotAroundZero(origin[0]) || isNotAroundZero(origin[1]); if (haveOrigin) { SUtil.Util_matrix.translate( m, m, origin ); } SUtil.Util_matrix.scale(m, m, this.scale); if (haveOrigin) { origin[0] = -origin[0]; origin[1] = -origin[1]; SUtil.Util_matrix.translate( m, m, origin ); } } if (this.rotation instanceof Array) { if (this.rotation[0] !== 0) { origin[0] = -this.rotation[1] || 0; origin[1] = -this.rotation[2] || 0; let haveOrigin = isNotAroundZero(origin[0]) || isNotAroundZero(origin[1]); if (haveOrigin) { SUtil.Util_matrix.translate( m, m, origin ); } SUtil.Util_matrix.rotate(m, m, this.rotation[0]); if (haveOrigin) { origin[0] = -origin[0]; origin[1] = -origin[1]; SUtil.Util_matrix.translate( m, m, origin ); } } } else { if (this.rotation !== 0) { SUtil.Util_matrix.rotate(m, m, this.rotation); } } if ( isNotAroundZero(this.position[0]) || isNotAroundZero(this.position[1]) ) { SUtil.Util_matrix.translate(m, m, this.position); } } // 保存这个变换矩阵 this.transform = m; // 应用父节点变换 if (this.parent && this.parent.needTransform) { if (this.needLocalTransform) { SUtil.Util_matrix.mul(this.transform, this.parent.transform, this.transform); } else { SUtil.Util_matrix.copy(this.transform, this.parent.transform); } } function isNotAroundZero(val) { var EPSILON = 5e-5; return val > EPSILON || val < -EPSILON; } } /** * @function Zondy.LevelRenderer.Transformable.prototype.setTransform * @description 将自己的 transform 应用到 context 上。 * * @param {Context2D} ctx - Context2D 上下文。 */ setTransform(ctx) { if (this.needTransform) { var m = this.transform; ctx.transform( m[0], m[1], m[2], m[3], m[4], m[5] ); } } /** * @function Zondy.LevelRenderer.Transformable.prototype.decomposeTransform * @description 分解`transform`矩阵到`position`, `rotation`, `scale` 。 */ decomposeTransform() { if (!this.transform) { return; } var m = this.transform; var sx = m[0] * m[0] + m[1] * m[1]; var position = this.position; var scale = this.scale; var rotation = this.rotation; if (isNotAroundZero(sx - 1)) { sx = Math.sqrt(sx); } var sy = m[2] * m[2] + m[3] * m[3]; if (isNotAroundZero(sy - 1)) { sy = Math.sqrt(sy); } position[0] = m[4]; position[1] = m[5]; scale[0] = sx; scale[1] = sy; scale[2] = scale[3] = 0; rotation[0] = Math.atan2(-m[1] / sy, m[0] / sx); rotation[1] = rotation[2] = 0; function isNotAroundZero(val) { var EPSILON = 5e-5; return val > EPSILON || val < -EPSILON; } } } export {Transformable}; Zondy.LevelRenderer.Transformable = Transformable;