-
Notifications
You must be signed in to change notification settings - Fork 0
Snap之Matrix
何波 edited this page Jul 10, 2019
·
3 revisions
[TOC]
和css3的transform:matrix一样
<div style="transform:matrix(a,b,c,d,e,f)"></div>
<circle cx="20" cy="20" r="60" fill="#ff0000" transform="matrix(a,b,c,d,e,f)"></circle>function Matrix(a, b, c, d, e, f) {
if (b == null && objectToString.call(a) == "[object SVGMatrix]") {
this.a = a.a;
this.b = a.b;
this.c = a.c;
this.d = a.d;
this.e = a.e;
this.f = a.f;
return;
}
if (a != null) {
this.a = +a;
this.b = +b;
this.c = +c;
this.d = +d;
this.e = +e;
this.f = +f;
} else {
this.a = 1;
this.b = 0;
this.c = 0;
this.d = 1;
this.e = 0;
this.f = 0;
}
}Adds the given matrix to existing one
matrixproto.add = function (a, b, c, d, e, f) {
if (a && a instanceof Matrix) {
return this.add(a.a, a.b, a.c, a.d, a.e, a.f);
}
var aNew = a * this.a + b * this.c,
bNew = a * this.b + b * this.d;
this.e += e * this.a + f * this.c;
this.f += e * this.b + f * this.d;
this.c = c * this.a + d * this.c;
this.d = c * this.b + d * this.d;
this.a = aNew;
this.b = bNew;
return this;
};相当于createjs中Matrix2D.prepend方法。
示例:
let svg = Snap("#svg");
let c = svg.paper.circle(50, 50, 40);
let m1 = new Snap.Matrix(1,0,0,1,20,20);
c.transform(m1.toTransformString());
if (document.addEventListener) {
document.querySelector("#button").addEventListener("click", function() {
m1.add(1,0,0,1,-20,-20);
c.transform(m1.toTransformString());
});
}- x (number) horizontal offset distance
- y (number) vertical offset distance
Translate the matrix
matrixproto.translate = function (x, y) {
this.e += x * this.a + y * this.c;
this.f += x * this.b + y * this.d;
return this;
};等同于createjs中Matrix2D.translate方法
let svg = Snap("#svg");
let c = svg.paper.rect(20, 20, 60, 60, 10).attr({
fill: "#f00"
});
document.getElementById("button").onclick = function() {
let m = new Snap.Matrix();
m.translate(10, 10);
c.transform(m);
};- x (number) amount to be scaled, with
1resulting in no change - y (number) #optional amount to scale along the vertical axis. (Otherwise
xapplies to both axes.) - cx (number) #optional horizontal origin point from which to scale
- cy (number) #optional vertical origin point from which to scale
- Default cx, cy is the middle point of the element.
Scales the matrix
matrixproto.scale = function (x, y, cx, cy) {
y == null && (y = x);
(cx || cy) && this.translate(cx, cy); // 先移动原点
this.a *= x;
this.b *= x;
this.c *= y;
this.d *= y;
(cx || cy) && this.translate(-cx, -cy); //矩阵变换完再移回原点
return this;
};与createjs中的Matrix2D.scale比较,多了移动scale原点的translate操作
let svg = Snap("#svg");
let c = svg.paper.circle(60, 60, 60).attr({
fill: "#f00"
});
document.getElementById("button").onclick = function() {
let m = new Snap.Matrix();
let scale = Math.round((0.8 + 0.4 * Math.random()) * 100) / 100;
m.scale(scale, scale);
c.transform(m);
};- y (number) Angle to skew along the y-axis (in degrees).
- x (number) Angle to skew along the x-axis (in degrees).
Skews the matrix
matrixproto.skew = function (x, y) {
x = x || 0;
y = y || 0;
x = Snap.rad(x);
y = Snap.rad(y);
var c = math.tan(x).toFixed(9);
var b = math.tan(y).toFixed(9);
return this.add(1, b, c, 1, 0, 0);
};反转矩阵,使它执行相反的变换。
matrixproto.invert = function () {
var me = this,
x = me.a * me.d - me.b * me.c;
return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x);
};等同于createjs中Matrix2D.invert方法
Returns a copy of the matrix
matrixproto.clone = function () {
return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
};将矩阵分解成基本变换,这个函数牛!
matrixproto.split = function () {
var out = {};
// translation
out.dx = this.e;
out.dy = this.f;
// scale and shear
var row = [[this.a, this.b], [this.c, this.d]];
out.scalex = math.sqrt(norm(row[0]));
normalize(row[0]);
out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1];
row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear];
out.scaley = math.sqrt(norm(row[1]));
normalize(row[1]);
out.shear /= out.scaley;
if (this.determinant() < 0) {
out.scalex = -out.scalex;
}
// rotation
var sin = row[0][1],
cos = row[1][1];
if (cos < 0) {
out.rotate = Snap.deg(math.acos(cos));
if (sin < 0) {
out.rotate = 360 - out.rotate;
}
} else {
out.rotate = Snap.deg(math.asin(sin));
}
out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate);
out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate;
out.noRotation = !+out.shear.toFixed(9) && !out.rotate;
return out;
};示例:
let m = new Snap.Matrix(1,2,3,4,5,6);
console.dir(m.split())输出:
Object: {
dx: 5
dy: 6
isSimple: false
isSuperSimple: false
noRotation: false
rotate: 116.56505117707798
scalex: -2.23606797749979
scaley: 0.8944271909999159
shear: 5.5
}返回给定矩阵的使用transform表示的字符串。
matrixproto.toTransformString = function (shorter) {
var s = shorter || this.split();
if (!+s.shear.toFixed(9)) {
s.scalex = +s.scalex.toFixed(4);
s.scaley = +s.scaley.toFixed(4);
s.rotate = +s.rotate.toFixed(4);
return (s.dx || s.dy ? "t" + [+s.dx.toFixed(4), +s.dy.toFixed(4)] : E) +
(s.rotate ? "r" + [+s.rotate.toFixed(4), 0, 0] : E) +
(s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E);
} else {
return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)];
}
};示例:
let m1 = new Snap.Matrix(1,2,3,4,5,6)
let m2 = new Snap.Matrix(2,0,0,1,20,20)
console.log(m1.toTransformString()) // m1,2,3,4,5,6
console.log(m2.toTransformString()) // t20,20s2,1,0,0