123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- var matrix = require("../core/matrix");
- var vector = require("../core/vector");
- /**
- * 提供变换扩展
- * @module zrender/mixin/Transformable
- * @author pissang (https://www.github.com/pissang)
- */
- var mIdentity = matrix.identity;
- var EPSILON = 5e-5;
- function isNotAroundZero(val) {
- return val > EPSILON || val < -EPSILON;
- }
- /**
- * @alias module:zrender/mixin/Transformable
- * @constructor
- */
- var Transformable = function (opts) {
- opts = opts || {}; // If there are no given position, rotation, scale
- if (!opts.position) {
- /**
- * 平移
- * @type {Array.<number>}
- * @default [0, 0]
- */
- this.position = [0, 0];
- }
- if (opts.rotation == null) {
- /**
- * 旋转
- * @type {Array.<number>}
- * @default 0
- */
- this.rotation = 0;
- }
- if (!opts.scale) {
- /**
- * 缩放
- * @type {Array.<number>}
- * @default [1, 1]
- */
- this.scale = [1, 1];
- }
- /**
- * 旋转和缩放的原点
- * @type {Array.<number>}
- * @default null
- */
- this.origin = this.origin || null;
- };
- var transformableProto = Transformable.prototype;
- transformableProto.transform = null;
- /**
- * 判断是否需要有坐标变换
- * 如果有坐标变换, 则从position, rotation, scale以及父节点的transform计算出自身的transform矩阵
- */
- transformableProto.needLocalTransform = function () {
- return isNotAroundZero(this.rotation) || isNotAroundZero(this.position[0]) || isNotAroundZero(this.position[1]) || isNotAroundZero(this.scale[0] - 1) || isNotAroundZero(this.scale[1] - 1);
- };
- var scaleTmp = [];
- transformableProto.updateTransform = function () {
- var parent = this.parent;
- var parentHasTransform = parent && parent.transform;
- var needLocalTransform = this.needLocalTransform();
- var m = this.transform;
- if (!(needLocalTransform || parentHasTransform)) {
- m && mIdentity(m);
- return;
- }
- m = m || matrix.create();
- if (needLocalTransform) {
- this.getLocalTransform(m);
- } else {
- mIdentity(m);
- } // 应用父节点变换
- if (parentHasTransform) {
- if (needLocalTransform) {
- matrix.mul(m, parent.transform, m);
- } else {
- matrix.copy(m, parent.transform);
- }
- } // 保存这个变换矩阵
- this.transform = m;
- var globalScaleRatio = this.globalScaleRatio;
- if (globalScaleRatio != null && globalScaleRatio !== 1) {
- this.getGlobalScale(scaleTmp);
- var relX = scaleTmp[0] < 0 ? -1 : 1;
- var relY = scaleTmp[1] < 0 ? -1 : 1;
- var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0;
- var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0;
- m[0] *= sx;
- m[1] *= sx;
- m[2] *= sy;
- m[3] *= sy;
- }
- this.invTransform = this.invTransform || matrix.create();
- matrix.invert(this.invTransform, m);
- };
- transformableProto.getLocalTransform = function (m) {
- return Transformable.getLocalTransform(this, m);
- };
- /**
- * 将自己的transform应用到context上
- * @param {CanvasRenderingContext2D} ctx
- */
- transformableProto.setTransform = function (ctx) {
- var m = this.transform;
- var dpr = ctx.dpr || 1;
- if (m) {
- ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]);
- } else {
- ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
- }
- };
- transformableProto.restoreTransform = function (ctx) {
- var dpr = ctx.dpr || 1;
- ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
- };
- var tmpTransform = [];
- var originTransform = matrix.create();
- transformableProto.setLocalTransform = function (m) {
- if (!m) {
- // TODO return or set identity?
- return;
- }
- var sx = m[0] * m[0] + m[1] * m[1];
- var sy = m[2] * m[2] + m[3] * m[3];
- var position = this.position;
- var scale = this.scale;
- if (isNotAroundZero(sx - 1)) {
- sx = Math.sqrt(sx);
- }
- if (isNotAroundZero(sy - 1)) {
- sy = Math.sqrt(sy);
- }
- if (m[0] < 0) {
- sx = -sx;
- }
- if (m[3] < 0) {
- sy = -sy;
- }
- position[0] = m[4];
- position[1] = m[5];
- scale[0] = sx;
- scale[1] = sy;
- this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);
- };
- /**
- * 分解`transform`矩阵到`position`, `rotation`, `scale`
- */
- transformableProto.decomposeTransform = function () {
- if (!this.transform) {
- return;
- }
- var parent = this.parent;
- var m = this.transform;
- if (parent && parent.transform) {
- // Get local transform and decompose them to position, scale, rotation
- matrix.mul(tmpTransform, parent.invTransform, m);
- m = tmpTransform;
- }
- var origin = this.origin;
- if (origin && (origin[0] || origin[1])) {
- originTransform[4] = origin[0];
- originTransform[5] = origin[1];
- matrix.mul(tmpTransform, m, originTransform);
- tmpTransform[4] -= origin[0];
- tmpTransform[5] -= origin[1];
- m = tmpTransform;
- }
- this.setLocalTransform(m);
- };
- /**
- * Get global scale
- * @return {Array.<number>}
- */
- transformableProto.getGlobalScale = function (out) {
- var m = this.transform;
- out = out || [];
- if (!m) {
- out[0] = 1;
- out[1] = 1;
- return out;
- }
- out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]);
- out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]);
- if (m[0] < 0) {
- out[0] = -out[0];
- }
- if (m[3] < 0) {
- out[1] = -out[1];
- }
- return out;
- };
- /**
- * 变换坐标位置到 shape 的局部坐标空间
- * @method
- * @param {number} x
- * @param {number} y
- * @return {Array.<number>}
- */
- transformableProto.transformCoordToLocal = function (x, y) {
- var v2 = [x, y];
- var invTransform = this.invTransform;
- if (invTransform) {
- vector.applyTransform(v2, v2, invTransform);
- }
- return v2;
- };
- /**
- * 变换局部坐标位置到全局坐标空间
- * @method
- * @param {number} x
- * @param {number} y
- * @return {Array.<number>}
- */
- transformableProto.transformCoordToGlobal = function (x, y) {
- var v2 = [x, y];
- var transform = this.transform;
- if (transform) {
- vector.applyTransform(v2, v2, transform);
- }
- return v2;
- };
- /**
- * @static
- * @param {Object} target
- * @param {Array.<number>} target.origin
- * @param {number} target.rotation
- * @param {Array.<number>} target.position
- * @param {Array.<number>} [m]
- */
- Transformable.getLocalTransform = function (target, m) {
- m = m || [];
- mIdentity(m);
- var origin = target.origin;
- var scale = target.scale || [1, 1];
- var rotation = target.rotation || 0;
- var position = target.position || [0, 0];
- if (origin) {
- // Translate to origin
- m[4] -= origin[0];
- m[5] -= origin[1];
- }
- matrix.scale(m, m, scale);
- if (rotation) {
- matrix.rotate(m, m, rotation);
- }
- if (origin) {
- // Translate back from origin
- m[4] += origin[0];
- m[5] += origin[1];
- }
- m[4] += position[0];
- m[5] += position[1];
- return m;
- };
- var _default = Transformable;
- module.exports = _default;
|