204 lines
6.0 KiB
JavaScript
204 lines
6.0 KiB
JavaScript
SVG.Matrix = SVG.invent({
|
|
// Initialize
|
|
create: function(source) {
|
|
var i, base = arrayToMatrix([1, 0, 0, 1, 0, 0])
|
|
|
|
// ensure source as object
|
|
source = source instanceof SVG.Element ?
|
|
source.matrixify() :
|
|
typeof source === 'string' ?
|
|
arrayToMatrix(source.split(SVG.regex.delimiter).map(parseFloat)) :
|
|
arguments.length == 6 ?
|
|
arrayToMatrix([].slice.call(arguments)) :
|
|
Array.isArray(source) ?
|
|
arrayToMatrix(source) :
|
|
typeof source === 'object' ?
|
|
source : base
|
|
|
|
// merge source
|
|
for (i = abcdef.length - 1; i >= 0; --i)
|
|
this[abcdef[i]] = source[abcdef[i]] != null ?
|
|
source[abcdef[i]] : base[abcdef[i]]
|
|
}
|
|
|
|
// Add methods
|
|
, extend: {
|
|
// Extract individual transformations
|
|
extract: function() {
|
|
// find delta transform points
|
|
var px = deltaTransformPoint(this, 0, 1)
|
|
, py = deltaTransformPoint(this, 1, 0)
|
|
, skewX = 180 / Math.PI * Math.atan2(px.y, px.x) - 90
|
|
|
|
return {
|
|
// translation
|
|
x: this.e
|
|
, y: this.f
|
|
, transformedX:(this.e * Math.cos(skewX * Math.PI / 180) + this.f * Math.sin(skewX * Math.PI / 180)) / Math.sqrt(this.a * this.a + this.b * this.b)
|
|
, transformedY:(this.f * Math.cos(skewX * Math.PI / 180) + this.e * Math.sin(-skewX * Math.PI / 180)) / Math.sqrt(this.c * this.c + this.d * this.d)
|
|
// skew
|
|
, skewX: -skewX
|
|
, skewY: 180 / Math.PI * Math.atan2(py.y, py.x)
|
|
// scale
|
|
, scaleX: Math.sqrt(this.a * this.a + this.b * this.b)
|
|
, scaleY: Math.sqrt(this.c * this.c + this.d * this.d)
|
|
// rotation
|
|
, rotation: skewX
|
|
, a: this.a
|
|
, b: this.b
|
|
, c: this.c
|
|
, d: this.d
|
|
, e: this.e
|
|
, f: this.f
|
|
, matrix: new SVG.Matrix(this)
|
|
}
|
|
}
|
|
// Clone matrix
|
|
, clone: function() {
|
|
return new SVG.Matrix(this)
|
|
}
|
|
// Morph one matrix into another
|
|
, morph: function(matrix) {
|
|
// store new destination
|
|
this.destination = new SVG.Matrix(matrix)
|
|
|
|
return this
|
|
}
|
|
// Get morphed matrix at a given position
|
|
, at: function(pos) {
|
|
// make sure a destination is defined
|
|
if (!this.destination) return this
|
|
|
|
// calculate morphed matrix at a given position
|
|
var matrix = new SVG.Matrix({
|
|
a: this.a + (this.destination.a - this.a) * pos
|
|
, b: this.b + (this.destination.b - this.b) * pos
|
|
, c: this.c + (this.destination.c - this.c) * pos
|
|
, d: this.d + (this.destination.d - this.d) * pos
|
|
, e: this.e + (this.destination.e - this.e) * pos
|
|
, f: this.f + (this.destination.f - this.f) * pos
|
|
})
|
|
|
|
return matrix
|
|
}
|
|
// Multiplies by given matrix
|
|
, multiply: function(matrix) {
|
|
return new SVG.Matrix(this.native().multiply(parseMatrix(matrix).native()))
|
|
}
|
|
// Inverses matrix
|
|
, inverse: function() {
|
|
return new SVG.Matrix(this.native().inverse())
|
|
}
|
|
// Translate matrix
|
|
, translate: function(x, y) {
|
|
return new SVG.Matrix(this.native().translate(x || 0, y || 0))
|
|
}
|
|
// Scale matrix
|
|
, scale: function(x, y, cx, cy) {
|
|
// support uniformal scale
|
|
if (arguments.length == 1) {
|
|
y = x
|
|
} else if (arguments.length == 3) {
|
|
cy = cx
|
|
cx = y
|
|
y = x
|
|
}
|
|
|
|
return this.around(cx, cy, new SVG.Matrix(x, 0, 0, y, 0, 0))
|
|
}
|
|
// Rotate matrix
|
|
, rotate: function(r, cx, cy) {
|
|
// convert degrees to radians
|
|
r = SVG.utils.radians(r)
|
|
|
|
return this.around(cx, cy, new SVG.Matrix(Math.cos(r), Math.sin(r), -Math.sin(r), Math.cos(r), 0, 0))
|
|
}
|
|
// Flip matrix on x or y, at a given offset
|
|
, flip: function(a, o) {
|
|
return a == 'x' ?
|
|
this.scale(-1, 1, o, 0) :
|
|
a == 'y' ?
|
|
this.scale(1, -1, 0, o) :
|
|
this.scale(-1, -1, a, o != null ? o : a)
|
|
}
|
|
// Skew
|
|
, skew: function(x, y, cx, cy) {
|
|
// support uniformal skew
|
|
if (arguments.length == 1) {
|
|
y = x
|
|
} else if (arguments.length == 3) {
|
|
cy = cx
|
|
cx = y
|
|
y = x
|
|
}
|
|
|
|
// convert degrees to radians
|
|
x = SVG.utils.radians(x)
|
|
y = SVG.utils.radians(y)
|
|
|
|
return this.around(cx, cy, new SVG.Matrix(1, Math.tan(y), Math.tan(x), 1, 0, 0))
|
|
}
|
|
// SkewX
|
|
, skewX: function(x, cx, cy) {
|
|
return this.skew(x, 0, cx, cy)
|
|
}
|
|
// SkewY
|
|
, skewY: function(y, cx, cy) {
|
|
return this.skew(0, y, cx, cy)
|
|
}
|
|
// Transform around a center point
|
|
, around: function(cx, cy, matrix) {
|
|
return this
|
|
.multiply(new SVG.Matrix(1, 0, 0, 1, cx || 0, cy || 0))
|
|
.multiply(matrix)
|
|
.multiply(new SVG.Matrix(1, 0, 0, 1, -cx || 0, -cy || 0))
|
|
}
|
|
// Convert to native SVGMatrix
|
|
, native: function() {
|
|
// create new matrix
|
|
var matrix = SVG.parser.native.createSVGMatrix()
|
|
|
|
// update with current values
|
|
for (var i = abcdef.length - 1; i >= 0; i--)
|
|
matrix[abcdef[i]] = this[abcdef[i]]
|
|
|
|
return matrix
|
|
}
|
|
// Convert matrix to string
|
|
, toString: function() {
|
|
// Construct the matrix directly, avoid values that are too small
|
|
return 'matrix(' + float32String(this.a) + ',' + float32String(this.b)
|
|
+ ',' + float32String(this.c) + ',' + float32String(this.d)
|
|
+ ',' + float32String(this.e) + ',' + float32String(this.f)
|
|
+ ')'
|
|
}
|
|
}
|
|
|
|
// Define parent
|
|
, parent: SVG.Element
|
|
|
|
// Add parent method
|
|
, construct: {
|
|
// Get current matrix
|
|
ctm: function() {
|
|
return new SVG.Matrix(this.node.getCTM())
|
|
},
|
|
// Get current screen matrix
|
|
screenCTM: function() {
|
|
/* https://bugzilla.mozilla.org/show_bug.cgi?id=1344537
|
|
This is needed because FF does not return the transformation matrix
|
|
for the inner coordinate system when getScreenCTM() is called on nested svgs.
|
|
However all other Browsers do that */
|
|
if(this instanceof SVG.Nested) {
|
|
var rect = this.rect(1,1)
|
|
var m = rect.node.getScreenCTM()
|
|
rect.remove()
|
|
return new SVG.Matrix(m)
|
|
}
|
|
return new SVG.Matrix(this.node.getScreenCTM())
|
|
}
|
|
|
|
}
|
|
|
|
})
|