You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
2.8 KiB
144 lines
2.8 KiB
'use strict'; |
|
|
|
// combine 2 matrixes |
|
// m1, m2 - [a, b, c, d, e, g] |
|
// |
|
function combine(m1, m2) { |
|
return [ |
|
m1[0] * m2[0] + m1[2] * m2[1], |
|
m1[1] * m2[0] + m1[3] * m2[1], |
|
m1[0] * m2[2] + m1[2] * m2[3], |
|
m1[1] * m2[2] + m1[3] * m2[3], |
|
m1[0] * m2[4] + m1[2] * m2[5] + m1[4], |
|
m1[1] * m2[4] + m1[3] * m2[5] + m1[5] |
|
]; |
|
} |
|
|
|
|
|
function Matrix() { |
|
if (!(this instanceof Matrix)) { return new Matrix(); } |
|
this.queue = []; // list of matrixes to apply |
|
this.cache = null; // combined matrix cache |
|
} |
|
|
|
|
|
Matrix.prototype.matrix = function (m) { |
|
if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0) { |
|
return this; |
|
} |
|
this.cache = null; |
|
this.queue.push(m); |
|
return this; |
|
}; |
|
|
|
|
|
Matrix.prototype.translate = function (tx, ty) { |
|
if (tx !== 0 || ty !== 0) { |
|
this.cache = null; |
|
this.queue.push([ 1, 0, 0, 1, tx, ty ]); |
|
} |
|
return this; |
|
}; |
|
|
|
|
|
Matrix.prototype.scale = function (sx, sy) { |
|
if (sx !== 1 || sy !== 1) { |
|
this.cache = null; |
|
this.queue.push([ sx, 0, 0, sy, 0, 0 ]); |
|
} |
|
return this; |
|
}; |
|
|
|
|
|
Matrix.prototype.rotate = function (angle, rx, ry) { |
|
var rad, cos, sin; |
|
|
|
if (angle !== 0) { |
|
this.translate(rx, ry); |
|
|
|
rad = angle * Math.PI / 180; |
|
cos = Math.cos(rad); |
|
sin = Math.sin(rad); |
|
|
|
this.queue.push([ cos, sin, -sin, cos, 0, 0 ]); |
|
this.cache = null; |
|
|
|
this.translate(-rx, -ry); |
|
} |
|
return this; |
|
}; |
|
|
|
|
|
Matrix.prototype.skewX = function (angle) { |
|
if (angle !== 0) { |
|
this.cache = null; |
|
this.queue.push([ 1, 0, Math.tan(angle * Math.PI / 180), 1, 0, 0 ]); |
|
} |
|
return this; |
|
}; |
|
|
|
|
|
Matrix.prototype.skewY = function (angle) { |
|
if (angle !== 0) { |
|
this.cache = null; |
|
this.queue.push([ 1, Math.tan(angle * Math.PI / 180), 0, 1, 0, 0 ]); |
|
} |
|
return this; |
|
}; |
|
|
|
|
|
// Flatten queue |
|
// |
|
Matrix.prototype.toArray = function () { |
|
if (this.cache) { |
|
return this.cache; |
|
} |
|
|
|
if (!this.queue.length) { |
|
this.cache = [ 1, 0, 0, 1, 0, 0 ]; |
|
return this.cache; |
|
} |
|
|
|
this.cache = this.queue[0]; |
|
|
|
if (this.queue.length === 1) { |
|
return this.cache; |
|
} |
|
|
|
for (var i = 1; i < this.queue.length; i++) { |
|
this.cache = combine(this.cache, this.queue[i]); |
|
} |
|
|
|
return this.cache; |
|
}; |
|
|
|
|
|
// Apply list of matrixes to (x,y) point. |
|
// If `isRelative` set, `translate` component of matrix will be skipped |
|
// |
|
Matrix.prototype.calc = function (x, y, isRelative) { |
|
var m; |
|
|
|
// Don't change point on empty transforms queue |
|
if (!this.queue.length) { return [ x, y ]; } |
|
|
|
// Calculate final matrix, if not exists |
|
// |
|
// NB. if you deside to apply transforms to point one-by-one, |
|
// they should be taken in reverse order |
|
|
|
if (!this.cache) { |
|
this.cache = this.toArray(); |
|
} |
|
|
|
m = this.cache; |
|
|
|
// Apply matrix to point |
|
return [ |
|
x * m[0] + y * m[2] + (isRelative ? 0 : m[4]), |
|
x * m[1] + y * m[3] + (isRelative ? 0 : m[5]) |
|
]; |
|
}; |
|
|
|
|
|
module.exports = Matrix;
|
|
|