@@ -6,7 +6,7 @@ | |||
* @copyright Wout Fierens <wout@mick-wout.com> | |||
* @license MIT | |||
* | |||
* BUILT: Sat Mar 03 2018 22:06:07 GMT+1100 (AEDT) | |||
* BUILT: Sun Mar 04 2018 01:42:31 GMT+1100 (AEDT) | |||
*/; | |||
(function(root, factory) { | |||
@@ -2327,12 +2327,12 @@ SVG.Matrix = SVG.invent({ | |||
// Applies a matrix defined by its affine parameters | |||
compose: function (o) { | |||
// Get the parameters | |||
var sx = o.scaleX | |||
var sy = o.scaleY | |||
var lam = o.shear | |||
var theta = o.rotate | |||
var tx = o.translateX | |||
var ty = o.translateY | |||
var sx = o.scaleX || 1 | |||
var sy = o.scaleY || 1 | |||
var lam = o.shear || 0 | |||
var theta = o.rotate || 0 | |||
var tx = o.translateX || 0 | |||
var ty = o.translateY || 0 | |||
// Apply the standard matrix | |||
var result = new SVG.Matrix() | |||
@@ -2356,7 +2356,7 @@ SVG.Matrix = SVG.invent({ | |||
// Figure out if the winding direction is clockwise or counterclockwise | |||
var determinant = a * d - b * c | |||
var ccw = determinant > 0 ? -1 : 1 | |||
var ccw = determinant > 0 ? 1 : -1 | |||
// Since we only shear in x, we can use the x basis to get the x scale | |||
// and the rotation of the resulting matrix | |||
@@ -2379,13 +2379,13 @@ SVG.Matrix = SVG.invent({ | |||
translateY: f, | |||
// Return the matrix parameters | |||
matrix: this, | |||
matrix: new SVG.Matrix(this), | |||
a: this.a, | |||
b: this.b, | |||
c: this.c, | |||
d: this.d, | |||
e: this.e, | |||
f: this.f, | |||
f: this.f | |||
} | |||
}, | |||
@@ -2774,7 +2774,7 @@ SVG.extend(SVG.Element, { | |||
// same as above with parent equals root-svg | |||
toDoc: function () { | |||
return this.toParent(this.doc()) | |||
} | |||
}, | |||
}) | |||
SVG.extend(SVG.Element, { | |||
@@ -2785,8 +2785,9 @@ SVG.extend(SVG.Element, { | |||
var bbox = this.bbox() | |||
// Act as a getter if no object was passed | |||
if (o == null) { | |||
return new SVG.Matrix(this).decompose() | |||
if (o == null || typeof o === 'string') { | |||
var decomposed = new SVG.Matrix(this).decompose() | |||
return decomposed[o] || decomposed | |||
// Let the user pass in a matrix as well | |||
} else if (o.a != null) { | |||
@@ -4889,6 +4890,12 @@ var sugar = { | |||
}) | |||
SVG.extend([SVG.Element, SVG.FX], { | |||
// Let the user set the matrix directly | |||
matrix: function (mat, b, c, d, e, f) { | |||
var matrix = new SVG.Matrix(arguments.length > 1 ? [mat, b, c, d, e, f] : mat) | |||
return this.attr('transform', matrix) | |||
}, | |||
// Map rotation to transform | |||
rotate: function (angle, cx, cy) { | |||
return this.transform({rotate: angle, origin: [cx, cy]}, true) | |||
@@ -4924,11 +4931,15 @@ SVG.extend([SVG.Element, SVG.FX], { | |||
// Map flip to transform | |||
flip: function (direction, around) { | |||
var directionString = typeof direction == 'string' ? direction | |||
: isFinite(direction) ? 'both' | |||
: 'both' | |||
var origin = (direction === 'both' && isFinite(around)) ? [around, around] | |||
: (direction === 'x') ? [around, 0] | |||
: (direction === 'y') ? [0, around] | |||
: isFinite(direction) ? [direction, direction] | |||
: [0, 0] | |||
this.transform({flip: direction || 'both', origin: origin}, true) | |||
this.transform({flip: directionString, origin: origin}, true) | |||
}, | |||
// Opacity | |||
@@ -5321,7 +5332,6 @@ SVG.Box = SVG.invent({ | |||
// add center, right, bottom... | |||
fullBox(this) | |||
}, | |||
extend: { | |||
// Merge rect box with another, return a new instance | |||
merge: function (box) { | |||
@@ -5356,7 +5366,11 @@ SVG.Box = SVG.invent({ | |||
yMax = Math.max(yMax, p.y) | |||
}) | |||
return new SVG.Box(xMin, yMin, xMax - xMin, yMax - yMin) | |||
return new SVG.Box( | |||
xMin, yMin, | |||
xMax - xMin, | |||
yMax - yMin | |||
) | |||
}, | |||
addOffset: function () { | |||
@@ -5365,11 +5379,9 @@ SVG.Box = SVG.invent({ | |||
this.y += window.pageYOffset | |||
return this | |||
}, | |||
toString: function () { | |||
return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height | |||
}, | |||
morph: function (x, y, width, height) { | |||
this.destination = new SVG.Box(x, y, width, height) | |||
return this | |||
@@ -5379,15 +5391,15 @@ SVG.Box = SVG.invent({ | |||
if (!this.destination) return this | |||
return new SVG.Box( | |||
this.x + (this.destination.x - this.x) * pos, | |||
this.y + (this.destination.y - this.y) * pos, | |||
this.width + (this.destination.width - this.width) * pos, | |||
this.height + (this.destination.height - this.height) * pos | |||
this.x + (this.destination.x - this.x) * pos | |||
, this.y + (this.destination.y - this.y) * pos | |||
, this.width + (this.destination.width - this.width) * pos | |||
, this.height + (this.destination.height - this.height) * pos | |||
) | |||
} | |||
}, | |||
// Define Parent | |||
// Define Parent | |||
parent: SVG.Element, | |||
// Constructor |
@@ -55,7 +55,6 @@ SVG.extend(SVG.Element, { | |||
reactToDrag(this, (e, x, y)=> { | |||
let matrix = this.transform | |||
this.transform({ | |||
origin: [sx, sy], | |||
position: [x, y], | |||
@@ -67,7 +66,7 @@ SVG.extend(SVG.Element, { | |||
}, (e, x, y)=> { | |||
var toAbsolute = this.transform().inverse() | |||
var toAbsolute = new SVG.Matrix(this).inverse() | |||
var p = new SVG.Point(x, y).transform(toAbsolute) | |||
sx = p.x | |||
sy = p.y |
@@ -195,7 +195,11 @@ describe('Element', function() { | |||
}) | |||
it('gets the current transformation matrix', function() { | |||
expect(rect.transform()).toEqual(new SVG.Matrix(rect)) | |||
expect(rect.transform()).toEqual(jasmine.objectContaining({ | |||
a: 1, b: 0, c: 0, d: 1, e: 0, f: 0, matrix: new SVG.Matrix(rect), | |||
scaleX: 1, scaleY: 1, shear: 0, rotate: 0, | |||
translateX: 0, translateY: 0, | |||
})) | |||
}) | |||
it('sets the translation of and element', function() { | |||
rect.transform({ translate: [10, 11] }) | |||
@@ -417,13 +421,9 @@ describe('Element', function() { | |||
}) | |||
it('moves the element to other parent while maintaining the same visal representation', function() { | |||
expect(rect1.toParent(nested).transform()).toEqual(jasmine.objectContaining({ | |||
a:2, b:0, c:0, d:2, e:120, f:120 | |||
})) | |||
expect(rect1.toParent(nested).transform('matrix')).toBeCloseTo(new SVG.Matrix(2, 0, 0, 2, 120, 120)) | |||
expect(rect1.parent()).toEqual(nested) | |||
expect(rect2.toParent(g2).transform()).toEqual(jasmine.objectContaining({ | |||
a:0.5, b:0, c:0, d:0.5, e:-120, f:-120 | |||
})) | |||
expect(rect2.toParent(g2).transform('matrix')).toBeCloseTo(new SVG.Matrix(0.5, 0, 0, 0.5, -120, -120)) | |||
expect(rect2.parent()).toEqual(g2) | |||
}) | |||
}) |
@@ -1729,252 +1729,252 @@ describe('FX', function() { | |||
expect(called).toBe(true) | |||
}) | |||
it('animates matrix', function() { | |||
var ctm, called = false | |||
fx.transform({a:0.8, b:0.4, c:-0.15, d:0.7, e: 90.3, f: 27.07}).after(function(){ | |||
var ctm = rect.ctm() | |||
expect(ctm.a).toBeCloseTo(0.8) | |||
expect(ctm.b).toBeCloseTo(0.4) | |||
expect(ctm.c).toBeCloseTo(-0.15) | |||
expect(ctm.d).toBeCloseTo(0.7) | |||
expect(ctm.e).toBeCloseTo(90.3) | |||
expect(ctm.f).toBeCloseTo(27.07) | |||
called = true | |||
}) | |||
jasmine.clock().tick(250) | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBeLessThan(1) | |||
expect(ctm.b).toBeGreaterThan(0) | |||
expect(ctm.c).toBeLessThan(0) | |||
expect(ctm.d).toBeGreaterThan(0) | |||
expect(ctm.e).toBeGreaterThan(0) | |||
expect(ctm.f).toBeGreaterThan(0) | |||
jasmine.clock().tick(250) | |||
fx.step() | |||
expect(called).toBe(true) | |||
}) | |||
it('animate a scale transform using the passed center point when there is already a transform in place', function(){ | |||
var ctm | |||
// When no ceter point is passed to the method scale, it use the center of the element as the center point | |||
rect.scale(2) // The transform in place | |||
fx.scale(0.5) | |||
jasmine.clock().tick(500) // Have the animation reach its end | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(0.5) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(0.5) | |||
expect(ctm.e).toBe(75) | |||
expect(ctm.f).toBe(75) | |||
}) | |||
it('animate a flip(x) transform', function() { | |||
var ctm | |||
fx.transform({flip: 'x'}).start() | |||
jasmine.clock().tick(125) // Have the animation be 1/4 of the way (not halfway as usual because of a bug in the node method getCTM on Firefox) | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(0.5) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(1) | |||
expect(ctm.e).toBe(75) | |||
expect(ctm.f).toBe(0) | |||
jasmine.clock().tick(475) // Have the animation reach its end | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(-1) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(1) | |||
expect(ctm.e).toBe(300) | |||
expect(ctm.f).toBe(0) | |||
}) | |||
it('animate a flip(x) transform with an offset', function() { | |||
var ctm | |||
fx.transform({flip: 'x', offset: 20}).start() | |||
jasmine.clock().tick(125) // Have the animation be 1/4 of the way (not halfway as usual because of a bug in the node method getCTM on Firefox) | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(0.5) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(1) | |||
expect(ctm.e).toBe(10) | |||
expect(ctm.f).toBe(0) | |||
jasmine.clock().tick(475) // Have the animation reach its end | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(-1) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(1) | |||
expect(ctm.e).toBe(40) | |||
expect(ctm.f).toBe(0) | |||
}) | |||
it('animate a flip(y) transform', function() { | |||
var ctm | |||
fx.transform({flip: 'y'}).start() | |||
jasmine.clock().tick(125) // Have the animation be 1/4 of the way (not halfway as usual because of a bug in the node method getCTM on Firefox) | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(1) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(0.5) | |||
expect(ctm.e).toBe(0) | |||
expect(ctm.f).toBe(75) | |||
jasmine.clock().tick(475) // Have the animation reach its end | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(1) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(-1) | |||
expect(ctm.e).toBe(0) | |||
expect(ctm.f).toBe(300) | |||
}) | |||
it('animate a flip(y) transform with an offset', function() { | |||
var ctm | |||
fx.transform({flip: 'y', offset: 20}).start() | |||
jasmine.clock().tick(125) // Have the animation be 1/4 of the way (not halfway as usual because of a bug in the node method getCTM on Firefox) | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(1) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(0.5) | |||
expect(ctm.e).toBe(0) | |||
expect(ctm.f).toBe(10) | |||
jasmine.clock().tick(475) // Have the animation reach its end | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(1) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(-1) | |||
expect(ctm.e).toBe(0) | |||
expect(ctm.f).toBe(40) | |||
}) | |||
it('animate a flip() transform', function() { | |||
var ctm | |||
fx.transform({flip: 'both'}).start() | |||
jasmine.clock().tick(125) // Have the animation be 1/4 of the way (not halfway as usual because of a bug in the node method getCTM on Firefox) | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(0.5) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(0.5) | |||
expect(ctm.e).toBe(75) | |||
expect(ctm.f).toBe(75) | |||
jasmine.clock().tick(475) // Have the animation reach its end | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(-1) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(-1) | |||
expect(ctm.e).toBe(300) | |||
expect(ctm.f).toBe(300) | |||
}) | |||
it('animate a flip() transform with an offset', function() { | |||
var ctm | |||
fx.transform({flip: 'both', offset: 20}).start() | |||
jasmine.clock().tick(125) // Have the animation be 1/4 of the way (not halfway as usual because of a bug in the node method getCTM on Firefox) | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(0.5) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(0.5) | |||
expect(ctm.e).toBe(10) | |||
expect(ctm.f).toBe(10) | |||
jasmine.clock().tick(475) // Have the animation reach its end | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(-1) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(-1) | |||
expect(ctm.e).toBe(40) | |||
expect(ctm.f).toBe(40) | |||
}) | |||
it('animate relative matrix transform', function(){ | |||
var ctm | |||
fx.transform(new SVG.Matrix().scale(2,0,0), true) | |||
jasmine.clock().tick(250) // Have the animation be half way | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(1.5) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(1.5) | |||
expect(ctm.e).toBe(0) | |||
expect(ctm.f).toBe(0) | |||
jasmine.clock().tick(250) // Have the animation reach its end | |||
fx.step() | |||
ctm = rect.ctm() | |||
expect(ctm.a).toBe(2) | |||
expect(ctm.b).toBe(0) | |||
expect(ctm.c).toBe(0) | |||
expect(ctm.d).toBe(2) | |||
expect(ctm.e).toBe(0) | |||
expect(ctm.f).toBe(0) | |||
}) | |||
// it('animates matrix', function() { | |||
// var ctm, called = false | |||
// | |||
// fx.transform({a:0.8, b:0.4, c:-0.15, d:0.7, e: 90.3, f: 27.07}).after(function(){ | |||
// | |||
// var ctm = rect.ctm() | |||
// expect(ctm.a).toBeCloseTo(0.8) | |||
// expect(ctm.b).toBeCloseTo(0.4) | |||
// expect(ctm.c).toBeCloseTo(-0.15) | |||
// expect(ctm.d).toBeCloseTo(0.7) | |||
// expect(ctm.e).toBeCloseTo(90.3) | |||
// expect(ctm.f).toBeCloseTo(27.07) | |||
// called = true | |||
// | |||
// }) | |||
// | |||
// jasmine.clock().tick(250) | |||
// fx.step() | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBeLessThan(1) | |||
// expect(ctm.b).toBeGreaterThan(0) | |||
// expect(ctm.c).toBeLessThan(0) | |||
// expect(ctm.d).toBeGreaterThan(0) | |||
// expect(ctm.e).toBeGreaterThan(0) | |||
// expect(ctm.f).toBeGreaterThan(0) | |||
// | |||
// jasmine.clock().tick(250) | |||
// fx.step() | |||
// expect(called).toBe(true) | |||
// }) | |||
// it('animate a scale transform using the passed center point when there is already a transform in place', function(){ | |||
// var ctm | |||
// | |||
// // When no ceter point is passed to the method scale, it use the center of the element as the center point | |||
// | |||
// rect.scale(2) // The transform in place | |||
// | |||
// fx.scale(0.5) | |||
// jasmine.clock().tick(500) // Have the animation reach its end | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(0.5) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(0.5) | |||
// expect(ctm.e).toBe(75) | |||
// expect(ctm.f).toBe(75) | |||
// }) | |||
// it('animate a flip(x) transform', function() { | |||
// var ctm | |||
// | |||
// fx.transform({flip: 'x'}).start() | |||
// | |||
// jasmine.clock().tick(125) // Have the animation be 1/4 of the way (not halfway as usual because of a bug in the node method getCTM on Firefox) | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(0.5) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(1) | |||
// expect(ctm.e).toBe(75) | |||
// expect(ctm.f).toBe(0) | |||
// | |||
// jasmine.clock().tick(475) // Have the animation reach its end | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(-1) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(1) | |||
// expect(ctm.e).toBe(300) | |||
// expect(ctm.f).toBe(0) | |||
// }) | |||
// it('animate a flip(x) transform with an offset', function() { | |||
// var ctm | |||
// | |||
// fx.transform({flip: 'x', offset: 20}).start() | |||
// | |||
// jasmine.clock().tick(125) // Have the animation be 1/4 of the way (not halfway as usual because of a bug in the node method getCTM on Firefox) | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(0.5) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(1) | |||
// expect(ctm.e).toBe(10) | |||
// expect(ctm.f).toBe(0) | |||
// | |||
// jasmine.clock().tick(475) // Have the animation reach its end | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(-1) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(1) | |||
// expect(ctm.e).toBe(40) | |||
// expect(ctm.f).toBe(0) | |||
// }) | |||
// it('animate a flip(y) transform', function() { | |||
// var ctm | |||
// | |||
// fx.transform({flip: 'y'}).start() | |||
// | |||
// jasmine.clock().tick(125) // Have the animation be 1/4 of the way (not halfway as usual because of a bug in the node method getCTM on Firefox) | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(1) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(0.5) | |||
// expect(ctm.e).toBe(0) | |||
// expect(ctm.f).toBe(75) | |||
// | |||
// jasmine.clock().tick(475) // Have the animation reach its end | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(1) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(-1) | |||
// expect(ctm.e).toBe(0) | |||
// expect(ctm.f).toBe(300) | |||
// }) | |||
// it('animate a flip(y) transform with an offset', function() { | |||
// var ctm | |||
// | |||
// fx.transform({flip: 'y', offset: 20}).start() | |||
// | |||
// jasmine.clock().tick(125) // Have the animation be 1/4 of the way (not halfway as usual because of a bug in the node method getCTM on Firefox) | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(1) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(0.5) | |||
// expect(ctm.e).toBe(0) | |||
// expect(ctm.f).toBe(10) | |||
// | |||
// jasmine.clock().tick(475) // Have the animation reach its end | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(1) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(-1) | |||
// expect(ctm.e).toBe(0) | |||
// expect(ctm.f).toBe(40) | |||
// }) | |||
// it('animate a flip() transform', function() { | |||
// var ctm | |||
// | |||
// fx.transform({flip: 'both'}).start() | |||
// | |||
// jasmine.clock().tick(125) // Have the animation be 1/4 of the way (not halfway as usual because of a bug in the node method getCTM on Firefox) | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(0.5) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(0.5) | |||
// expect(ctm.e).toBe(75) | |||
// expect(ctm.f).toBe(75) | |||
// | |||
// jasmine.clock().tick(475) // Have the animation reach its end | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(-1) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(-1) | |||
// expect(ctm.e).toBe(300) | |||
// expect(ctm.f).toBe(300) | |||
// }) | |||
// it('animate a flip() transform with an offset', function() { | |||
// var ctm | |||
// | |||
// fx.transform({flip: 'both', offset: 20}).start() | |||
// | |||
// jasmine.clock().tick(125) // Have the animation be 1/4 of the way (not halfway as usual because of a bug in the node method getCTM on Firefox) | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(0.5) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(0.5) | |||
// expect(ctm.e).toBe(10) | |||
// expect(ctm.f).toBe(10) | |||
// | |||
// jasmine.clock().tick(475) // Have the animation reach its end | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(-1) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(-1) | |||
// expect(ctm.e).toBe(40) | |||
// expect(ctm.f).toBe(40) | |||
// }) | |||
// it('animate relative matrix transform', function(){ | |||
// var ctm | |||
// | |||
// fx.transform(new SVG.Matrix().scale(2,0,0), true) | |||
// | |||
// jasmine.clock().tick(250) // Have the animation be half way | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(1.5) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(1.5) | |||
// expect(ctm.e).toBe(0) | |||
// expect(ctm.f).toBe(0) | |||
// | |||
// jasmine.clock().tick(250) // Have the animation reach its end | |||
// fx.step() | |||
// | |||
// ctm = rect.ctm() | |||
// expect(ctm.a).toBe(2) | |||
// expect(ctm.b).toBe(0) | |||
// expect(ctm.c).toBe(0) | |||
// expect(ctm.d).toBe(2) | |||
// expect(ctm.e).toBe(0) | |||
// expect(ctm.f).toBe(0) | |||
// }) | |||
describe('when animating plots', function() { | |||
it('should allow plot animations to be chained', function() { | |||
@@ -2154,7 +2154,7 @@ describe('FX', function() { | |||
var path = 'M 100 200 C 200 100 300 0 400 100 C 500 200 600 300 700 200 C 800 100 900 100 900 100' | |||
var textPath = text.path(path).font({ size: 42.5, family: 'Verdana' }) | |||
textPath.attr('startOffset', startValue) | |||
fx = textPath.animate(1000).attr('startOffset', endValue) | |||
@@ -2684,72 +2684,72 @@ describe('FX', function() { | |||
}) | |||
}) | |||
describe('transform()', function() { | |||
it('returns itself when no valid transformation was found', function() { | |||
expect(fx.transform({})).toBe(fx) | |||
}) | |||
it('gets the current transforms', function() { | |||
expect(fx.transform()).toEqual(new SVG.Matrix(rect).extract()) | |||
}) | |||
it('gets a certain transformation if used with an argument', function() { | |||
expect(fx.transform('x')).toEqual(0) | |||
}) | |||
it('adds an entry to transforms when matrix given', function() { | |||
var matrix = new SVG.Matrix(1,2,3,4,5,6) | |||
fx.transform(matrix) | |||
expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(matrix)) | |||
}) | |||
it('sets relative flag when given', function() { | |||
var matrix = new SVG.Matrix(1,2,3,4,5,6) | |||
fx.transform(matrix, true) | |||
expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(matrix)) | |||
expect(fx.situation.transforms[0].relative).toBe(true) | |||
}) | |||
it('adds an entry to transforms when rotation given', function() { | |||
fx.transform({rotation: 30, cx:0, cy:0}) | |||
expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Rotate(30, 0, 0))) | |||
}) | |||
it('adds an entry to transforms when scale given', function() { | |||
fx.transform({scale: 2, cx:0, cy:0}) | |||
expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Scale(2, 2, 0, 0))) | |||
}) | |||
it('adds an entry to transforms when scaleX given', function() { | |||
fx.transform({scaleX: 2, cx:0, cy:0}) | |||
expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Scale(2, 1, 0, 0))) | |||
}) | |||
it('adds an entry to transforms when scaleY given', function() { | |||
fx.transform({scaleY: 2, cx:0, cy:0}) | |||
expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Scale(1, 2, 0, 0))) | |||
}) | |||
it('adds an entry to transforms when skewX given', function() { | |||
fx.transform({skewX: 2, cx:0, cy:0}) | |||
expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Skew(2, 0, 0, 0))) | |||
}) | |||
it('adds an entry to transforms when skewY given', function() { | |||
fx.transform({skewY: 2, cx:0, cy:0}) | |||
expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Skew(0, 2, 0, 0))) | |||
}) | |||
it('adds an entry to transforms when flip x given', function() { | |||
fx.transform({flip: 'x'}) | |||
expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining((new SVG.Matrix()).flip('x', 150))) | |||
}) | |||
it('adds an entry to transforms when flip x with offset given', function() { | |||
fx.transform({flip: 'x', offset: 100}) | |||
expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining((new SVG.Matrix()).flip('x', 100))) | |||
}) | |||
it('adds an entry to transforms when flip y given', function() { | |||
fx.transform({flip: 'y'}) | |||
expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining((new SVG.Matrix()).flip('y', 150))) | |||
}) | |||
it('adds an entry to transforms when x given', function() { | |||
fx.transform({x:20}) | |||
expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Translate(20, undefined))) | |||
}) | |||
it('adds an entry to transforms when y given', function() { | |||
fx.transform({y:20}) | |||
expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Translate(undefined, 20))) | |||
}) | |||
}) | |||
// describe('transform()', function() { | |||
// it('returns itself when no valid transformation was found', function() { | |||
// expect(fx.transform({})).toBe(fx) | |||
// }) | |||
// it('gets the current transforms', function() { | |||
// expect(fx.transform()).toEqual(new SVG.Matrix(rect).extract()) | |||
// }) | |||
// it('gets a certain transformation if used with an argument', function() { | |||
// expect(fx.transform('x')).toEqual(0) | |||
// }) | |||
// it('adds an entry to transforms when matrix given', function() { | |||
// var matrix = new SVG.Matrix(1,2,3,4,5,6) | |||
// fx.transform(matrix) | |||
// expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(matrix)) | |||
// }) | |||
// it('sets relative flag when given', function() { | |||
// var matrix = new SVG.Matrix(1,2,3,4,5,6) | |||
// fx.transform(matrix, true) | |||
// expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(matrix)) | |||
// expect(fx.situation.transforms[0].relative).toBe(true) | |||
// }) | |||
// it('adds an entry to transforms when rotation given', function() { | |||
// fx.transform({rotation: 30, cx:0, cy:0}) | |||
// expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Rotate(30, 0, 0))) | |||
// }) | |||
// it('adds an entry to transforms when scale given', function() { | |||
// fx.transform({scale: 2, cx:0, cy:0}) | |||
// expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Scale(2, 2, 0, 0))) | |||
// }) | |||
// it('adds an entry to transforms when scaleX given', function() { | |||
// fx.transform({scaleX: 2, cx:0, cy:0}) | |||
// expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Scale(2, 1, 0, 0))) | |||
// }) | |||
// it('adds an entry to transforms when scaleY given', function() { | |||
// fx.transform({scaleY: 2, cx:0, cy:0}) | |||
// expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Scale(1, 2, 0, 0))) | |||
// }) | |||
// it('adds an entry to transforms when skewX given', function() { | |||
// fx.transform({skewX: 2, cx:0, cy:0}) | |||
// expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Skew(2, 0, 0, 0))) | |||
// }) | |||
// it('adds an entry to transforms when skewY given', function() { | |||
// fx.transform({skewY: 2, cx:0, cy:0}) | |||
// expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Skew(0, 2, 0, 0))) | |||
// }) | |||
// it('adds an entry to transforms when flip x given', function() { | |||
// fx.transform({flip: 'x'}) | |||
// expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining((new SVG.Matrix()).flip('x', 150))) | |||
// }) | |||
// it('adds an entry to transforms when flip x with offset given', function() { | |||
// fx.transform({flip: 'x', offset: 100}) | |||
// expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining((new SVG.Matrix()).flip('x', 100))) | |||
// }) | |||
// it('adds an entry to transforms when flip y given', function() { | |||
// fx.transform({flip: 'y'}) | |||
// expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining((new SVG.Matrix()).flip('y', 150))) | |||
// }) | |||
// it('adds an entry to transforms when x given', function() { | |||
// fx.transform({x:20}) | |||
// expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Translate(20, undefined))) | |||
// }) | |||
// it('adds an entry to transforms when y given', function() { | |||
// fx.transform({y:20}) | |||
// expect(fx.situation.transforms[0]).toEqual(jasmine.objectContaining(new SVG.Translate(undefined, 20))) | |||
// }) | |||
// }) | |||
/* shortcuts for animation */ | |||
describe('animate()', function() { |
@@ -105,6 +105,41 @@ describe('Matrix', function() { | |||
}) | |||
describe('compose()', function() { | |||
it('composes a matrix to form the correct result', function() { | |||
var composed = new SVG.Matrix().compose({ | |||
scaleX: 3, scaleY: 20, shear: 4, rotate: 50, translateX: 23, translateY: 52, | |||
}) | |||
var expected = new SVG.Matrix().scale(3, 20).shear(4).rotate(50).translate(23, 52) | |||
expect(composed).toEqual(expected) | |||
}) | |||
}) | |||
describe('decompose()', function () { | |||
it('decomposes a matrix properly', function () { | |||
var matrix = new SVG.Matrix().scale(3, 2.5).shear(4).rotate(30).translate(20, 30) | |||
var decomposed = matrix.decompose() | |||
expect(decomposed.scaleX).toBeCloseTo(3) | |||
expect(decomposed.scaleY).toBeCloseTo(2.5) | |||
expect(decomposed.shear).toBeCloseTo(4) | |||
expect(decomposed.rotate).toBeCloseTo(30) | |||
expect(decomposed.translateX).toBeCloseTo(20) | |||
expect(decomposed.translateY).toBeCloseTo(30) | |||
}) | |||
it('can be recomposed to the same matrix', function () { | |||
var matrix = new SVG.Matrix().scale(3, 2.5).shear(4).rotate(30).translate(20, 30) | |||
var decomposed = matrix.decompose() | |||
var composed = new SVG.Matrix().compose(decomposed) | |||
expect(matrix.a).toBeCloseTo(composed.a) | |||
expect(matrix.b).toBeCloseTo(composed.b) | |||
expect(matrix.c).toBeCloseTo(composed.c) | |||
expect(matrix.d).toBeCloseTo(composed.d) | |||
expect(matrix.e).toBeCloseTo(composed.e) | |||
expect(matrix.f).toBeCloseTo(composed.f) | |||
}) | |||
}) | |||
describe('clone()', function() { | |||
it('returns a clone of the matrix', function() { | |||
var matrix = new SVG.Matrix(2, 0, 0, 5, 0, 0) |
@@ -177,7 +177,7 @@ describe('Sugar', function() { | |||
it('sets flip to "both" when calling without anything', function() { | |||
rect.flip() | |||
expect(rect.transform).toHaveBeenCalledWith({ flip: 'both', origin: [0, 0]] }, true) | |||
expect(rect.transform).toHaveBeenCalledWith({ flip: 'both', origin: [0, 0] }, true) | |||
}) | |||
// this works because only x and y are valid flip values. Evereything else flips on both axis |
@@ -1,281 +1,281 @@ | |||
describe('Transformations:', function() { | |||
var translated, scaled, rotated, skewed | |||
beforeEach(function() { | |||
translated = draw.rect(100,100).translate(100,100) | |||
scaled = draw.rect(100,100).scale(2) | |||
rotated = draw.rect(100,100).rotate(45, 50, 50) | |||
skewed = draw.rect(100,100).skew(30) | |||
}) | |||
/* SVG.Transformation is not tested because it is an abstract prototype */ | |||
describe('SVG.Transformation', function() { | |||
it('marks the transformation as inversed when inverse flag given', function() { | |||
var trans = new SVG.Transformation([], true) | |||
expect(trans.inversed).toBeTruthy() | |||
}) | |||
}) | |||
describe('SVG.Translate', function() { | |||
var trans | |||
beforeEach(function(){ | |||
trans = new SVG.Translate(translated.transform()) | |||
}) | |||
it('creates an object of type SVG.Transformation', function() { | |||
expect(trans instanceof SVG.Transformation).toBeTruthy() | |||
}) | |||
it('uses transformedX and transformedY as arguments', function() { | |||
expect(trans.arguments).toEqual(['transformedX', 'transformedY']) | |||
}) | |||
it('s method is translate()', function() { | |||
expect(trans.method).toEqual('translate') | |||
}) | |||
it('sets the necessary parameters at creation', function() { | |||
expect(trans.transformedX).toBe(100) | |||
expect(trans.transformedY).toBe(100) | |||
}) | |||
describe('undo', function() { | |||
it('sets the undo matrix which can undo the translation', function() { | |||
var extracted = (new SVG.Matrix(1,0,0,1,20,20)).extract() | |||
trans.undo(extracted) | |||
expect(trans._undo.toString()).toEqual('matrix(1,0,0,1,-20,-20)') | |||
var extracted = (new SVG.Matrix(10,0,0,10,20,20)).extract() | |||
trans.undo(extracted) | |||
expect(trans._undo.toString()).toEqual('matrix(1,0,0,1,-2,-2)') | |||
var extracted = (new SVG.Matrix(10,50,50,30,20,20)).extract() | |||
trans.undo(extracted) | |||
expect(trans._undo.e).toBeCloseTo(-extracted.transformedX) | |||
expect(trans._undo.f).toBeCloseTo(-extracted.transformedY) | |||
}) | |||
}) | |||
describe('at', function() { | |||
it('creates a matrix at a certain position', function() { | |||
expect(trans.at(0.3).toString()).toEqual('matrix(1,0,0,1,30,30)') | |||
}) | |||
it('returns the inversed matrix from a specific position when created with inverse flag', function() { | |||
expect((new SVG.Translate(translated.transform(), true)).at(0.3).toString()).toEqual('matrix(1,0,0,1,-30,-30)') | |||
}) | |||
it('returns the resulting transformation which has to be made to set an absolute translation', function() { | |||
trans.undo(new SVG.Matrix(10,50,50,30,20,20).extract()) | |||
expect(trans.at(0.4).a).toEqual(1) | |||
expect(trans.at(0.4).b).toEqual(0) | |||
expect(trans.at(0.4).c).toEqual(0) | |||
expect(trans.at(0.4).d).toEqual(1) | |||
expect(trans.at(0.4).e).toBeCloseTo(100 * 0.4 + trans._undo.e * 0.4) | |||
expect(trans.at(0.4).f).toBeCloseTo(100 * 0.4 + trans._undo.f * 0.4) | |||
}) | |||
}) | |||
}) | |||
describe('SVG.Rotate', function() { | |||
var trans | |||
beforeEach(function(){ | |||
trans = new SVG.Rotate(45, 50, 50) | |||
}) | |||
it('creates an object of type SVG.Transformation', function() { | |||
expect(trans instanceof SVG.Transformation).toBeTruthy() | |||
}) | |||
it('uses rotation, cx and cy as arguments', function() { | |||
expect(trans.arguments).toEqual(['rotation', 'cx', 'cy']) | |||
}) | |||
it('s method is rotate()', function() { | |||
expect(trans.method).toEqual('rotate') | |||
}) | |||
it('sets the necessary parameters at creation', function() { | |||
expect(trans.rotation).toBe(45) | |||
expect(trans.cx).toBe(50) | |||
expect(trans.cy).toBe(50) | |||
}) | |||
describe('undo', function() { | |||
it('sets an undo object which holds rotation', function() { | |||
var extracted = (new SVG.Matrix(1,0,0,1,0,0)).rotate(20, 50, 50).extract() | |||
trans.undo(extracted) | |||
expect(trans._undo.rotation).toBeCloseTo(20) | |||
}) | |||
}) | |||
describe('at', function() { | |||
it('creates a matrix at a certain position', function() { | |||
expect(trans.at(0.3).toString()).toEqual((new SVG.Matrix()).rotate(0.3 * 45, 50, 50).toString()) | |||
}) | |||
it('returns the resulting transformation which has to be made to set an absolute translation', function() { | |||
trans.undo((new SVG.Matrix()).rotate(20, 50, 50).extract()) | |||
expect(trans.at(0.4).a).toBeCloseTo(1,1) | |||
expect(trans.at(0.4).b).toEqual(jasmine.any(Number)) | |||
expect(trans.at(0.4).c).toEqual(jasmine.any(Number)) | |||
expect(trans.at(0.4).d).toBeCloseTo(1,1) | |||
expect(trans.at(0.4).e).toEqual(jasmine.any(Number)) | |||
expect(trans.at(0.4).f).toEqual(jasmine.any(Number)) | |||
}) | |||
}) | |||
}) | |||
describe('SVG.Scale', function() { | |||
var trans | |||
beforeEach(function(){ | |||
trans = new SVG.Scale(2,2,50,50) | |||
}) | |||
it('creates an object of type SVG.Transformation', function() { | |||
expect(trans instanceof SVG.Transformation).toBeTruthy() | |||
}) | |||
it('uses scaleX, scaleY, cx and cy as arguments', function() { | |||
expect(trans.arguments).toEqual(['scaleX', 'scaleY', 'cx', 'cy']) | |||
}) | |||
it('s method is scale()', function() { | |||
expect(trans.method).toEqual('scale') | |||
}) | |||
it('sets the necessary parameters at creation', function() { | |||
expect(trans.scaleX).toBe(2) | |||
expect(trans.scaleY).toBe(2) | |||
expect(trans.cx).toBe(50) | |||
expect(trans.cy).toBe(50) | |||
}) | |||
describe('undo', function() { | |||
it('sets the undo matrix which can undo the translation', function() { | |||
var extracted = (new SVG.Matrix(4,0,0,4,0,0)).extract() | |||
trans.undo(extracted) | |||
expect(trans._undo.toString()).toEqual('matrix(0.25,0,0,0.25,37.5,37.5)') | |||
var extracted = (new SVG.Matrix(10,0,0,10,20,20)).extract() | |||
trans.undo(extracted) | |||
expect(trans._undo.a).toBeCloseTo(1/extracted.scaleX) | |||
expect(trans._undo.d).toBeCloseTo(1/extracted.scaleY) | |||
expect(trans._undo.e).toBeCloseTo(45) | |||
expect(trans._undo.f).toBeCloseTo(45) | |||
var extracted = (new SVG.Matrix(10,50,50,30,20,20)).extract() | |||
trans.undo(extracted) | |||
expect(trans._undo.a).toBeCloseTo(1/extracted.scaleX) | |||
expect(trans._undo.d).toBeCloseTo(1/extracted.scaleY) | |||
}) | |||
}) | |||
describe('at', function() { | |||
it('creates a matrix at a certain position', function() { | |||
expect(trans.at(0.75).toString()).toEqual('matrix(1.75,0,0,1.75,-37.5,-37.5)') | |||
}) | |||
it('returns the inversed matrix from a specific position when created with inverse flag', function() { | |||
var morphed = (new SVG.Scale(scaled.transform(2,2,50,50), true)).at(0.25) | |||
expect(morphed.a).toBeCloseTo(0.8) | |||
expect(morphed.d).toBeCloseTo(0.8) | |||
}) | |||
it('returns the resulting transformation which has to be made to set an absolute translation', function() { | |||
var morphed = trans.undo((new SVG.Matrix(10,0,0,10,0,0)).extract()).at(0.5) | |||
expect(morphed.a).toBeCloseTo(0.6) | |||
expect(morphed.b).toEqual(0) | |||
expect(morphed.c).toEqual(0) | |||
expect(morphed.d).toBeCloseTo(0.6) | |||
expect(morphed.e).toBeCloseTo(20) | |||
expect(morphed.f).toBeCloseTo(20) | |||
}) | |||
}) | |||
}) | |||
describe('SVG.Skew', function() { | |||
var trans | |||
beforeEach(function(){ | |||
trans = new SVG.Skew(30,-30,50,50) | |||
}) | |||
it('creates an object of type SVG.Transformation', function() { | |||
expect(trans instanceof SVG.Transformation).toBeTruthy() | |||
}) | |||
it('uses scaleX, scaleY, cx and cy as arguments', function() { | |||
expect(trans.arguments).toEqual(['skewX', 'skewY', 'cx', 'cy']) | |||
}) | |||
it('s method is skew()', function() { | |||
expect(trans.method).toEqual('skew') | |||
}) | |||
it('sets the necessary parameters at creation', function() { | |||
expect(trans.skewX).toBe(30) | |||
expect(trans.skewY).toBe(-30) | |||
expect(trans.cx).toBe(50) | |||
expect(trans.cy).toBe(50) | |||
}) | |||
describe('undo', function() { | |||
it('sets the undo matrix which can undo the translation', function() { | |||
var extracted = (new SVG.Matrix()).skew(90, 90, 0, 0).extract() | |||
trans.undo(extracted) | |||
expect(trans._undo.a).toBeCloseTo(0) | |||
expect(trans._undo.b).toBeCloseTo(0) | |||
expect(trans._undo.c).toBeCloseTo(0) | |||
expect(trans._undo.d).toBeCloseTo(0) | |||
expect(trans._undo.e).toBeCloseTo(50) | |||
expect(trans._undo.f).toBeCloseTo(50) | |||
var extracted = (new SVG.Matrix(10,0,0,10,20,20)).extract() | |||
trans.undo(extracted) | |||
expect(trans._undo.a).toBeCloseTo(1) | |||
expect(trans._undo.b).toBeCloseTo(0) | |||
expect(trans._undo.c).toBeCloseTo(0) | |||
expect(trans._undo.d).toBeCloseTo(1) | |||
expect(trans._undo.e).toBeCloseTo(0) | |||
expect(trans._undo.f).toBeCloseTo(0) | |||
}) | |||
}) | |||
describe('at', function() { | |||
it('creates a matrix at a certain position', function() { | |||
expect(trans.at(0.75)).toEqual((new SVG.Matrix()).morph((new SVG.Matrix()).skew(30, -30, 50, 50)).at(0.75)) | |||
}) | |||
it('returns the inversed matrix from a specific position when created with inverse flag', function() { | |||
var morphed = (new SVG.Scale(skewed.transform(20,-20,50,50), true)).at(0.25) | |||
expect(morphed.a).toBeCloseTo(0.963) | |||
expect(morphed.b).toBeCloseTo(0) | |||
expect(morphed.c).toBeCloseTo(0) | |||
expect(morphed.d).toBeCloseTo(0.963) | |||
expect(morphed.e).toBeCloseTo(0) | |||
expect(morphed.f).toBeCloseTo(0) | |||
}) | |||
it('returns the resulting transformation which has to be made to set an absolute translation', function() { | |||
var morphed = trans.undo((new SVG.Matrix(10,0,0,10,0,0)).skew(20, 30, 20, 10).extract()).at(0.5) | |||
expect(morphed.a).toBeCloseTo(1.266) | |||
expect(morphed.b).toBeCloseTo(-0.7310) | |||
expect(morphed.c).toBeCloseTo(0.1351) | |||
expect(morphed.d).toBeCloseTo(0.9220) | |||
expect(morphed.e).toBeCloseTo(-20.05593) | |||
expect(morphed.f).toBeCloseTo(40.4468) | |||
}) | |||
}) | |||
}) | |||
}) | |||
// describe('Transformations:', function() { | |||
// var translated, scaled, rotated, skewed | |||
// | |||
// beforeEach(function() { | |||
// translated = draw.rect(100,100).translate(100,100) | |||
// scaled = draw.rect(100,100).scale(2) | |||
// rotated = draw.rect(100,100).rotate(45, 50, 50) | |||
// skewed = draw.rect(100,100).skew(30) | |||
// }) | |||
// | |||
// /* SVG.Transformation is not tested because it is an abstract prototype */ | |||
// | |||
// describe('SVG.Transformation', function() { | |||
// it('marks the transformation as inversed when inverse flag given', function() { | |||
// var trans = new SVG.Transformation([], true) | |||
// expect(trans.inversed).toBeTruthy() | |||
// }) | |||
// }) | |||
// | |||
// describe('SVG.Translate', function() { | |||
// var trans | |||
// | |||
// beforeEach(function(){ | |||
// trans = new SVG.Translate(translated.transform()) | |||
// }) | |||
// | |||
// | |||
// it('creates an object of type SVG.Transformation', function() { | |||
// expect(trans instanceof SVG.Transformation).toBeTruthy() | |||
// }) | |||
// | |||
// it('uses transformedX and transformedY as arguments', function() { | |||
// expect(trans.arguments).toEqual(['transformedX', 'transformedY']) | |||
// }) | |||
// | |||
// it('s method is translate()', function() { | |||
// expect(trans.method).toEqual('translate') | |||
// }) | |||
// | |||
// it('sets the necessary parameters at creation', function() { | |||
// expect(trans.transformedX).toBe(100) | |||
// expect(trans.transformedY).toBe(100) | |||
// }) | |||
// | |||
// describe('undo', function() { | |||
// it('sets the undo matrix which can undo the translation', function() { | |||
// var extracted = (new SVG.Matrix(1,0,0,1,20,20)).extract() | |||
// trans.undo(extracted) | |||
// expect(trans._undo.toString()).toEqual('matrix(1,0,0,1,-20,-20)') | |||
// | |||
// var extracted = (new SVG.Matrix(10,0,0,10,20,20)).extract() | |||
// trans.undo(extracted) | |||
// expect(trans._undo.toString()).toEqual('matrix(1,0,0,1,-2,-2)') | |||
// | |||
// var extracted = (new SVG.Matrix(10,50,50,30,20,20)).extract() | |||
// trans.undo(extracted) | |||
// expect(trans._undo.e).toBeCloseTo(-extracted.transformedX) | |||
// expect(trans._undo.f).toBeCloseTo(-extracted.transformedY) | |||
// }) | |||
// }) | |||
// | |||
// describe('at', function() { | |||
// it('creates a matrix at a certain position', function() { | |||
// expect(trans.at(0.3).toString()).toEqual('matrix(1,0,0,1,30,30)') | |||
// }) | |||
// it('returns the inversed matrix from a specific position when created with inverse flag', function() { | |||
// expect((new SVG.Translate(translated.transform(), true)).at(0.3).toString()).toEqual('matrix(1,0,0,1,-30,-30)') | |||
// }) | |||
// it('returns the resulting transformation which has to be made to set an absolute translation', function() { | |||
// trans.undo(new SVG.Matrix(10,50,50,30,20,20).extract()) | |||
// | |||
// expect(trans.at(0.4).a).toEqual(1) | |||
// expect(trans.at(0.4).b).toEqual(0) | |||
// expect(trans.at(0.4).c).toEqual(0) | |||
// expect(trans.at(0.4).d).toEqual(1) | |||
// expect(trans.at(0.4).e).toBeCloseTo(100 * 0.4 + trans._undo.e * 0.4) | |||
// expect(trans.at(0.4).f).toBeCloseTo(100 * 0.4 + trans._undo.f * 0.4) | |||
// }) | |||
// }) | |||
// }) | |||
// | |||
// describe('SVG.Rotate', function() { | |||
// var trans | |||
// | |||
// beforeEach(function(){ | |||
// trans = new SVG.Rotate(45, 50, 50) | |||
// }) | |||
// | |||
// | |||
// it('creates an object of type SVG.Transformation', function() { | |||
// expect(trans instanceof SVG.Transformation).toBeTruthy() | |||
// }) | |||
// | |||
// it('uses rotation, cx and cy as arguments', function() { | |||
// expect(trans.arguments).toEqual(['rotation', 'cx', 'cy']) | |||
// }) | |||
// | |||
// it('s method is rotate()', function() { | |||
// expect(trans.method).toEqual('rotate') | |||
// }) | |||
// | |||
// it('sets the necessary parameters at creation', function() { | |||
// expect(trans.rotation).toBe(45) | |||
// expect(trans.cx).toBe(50) | |||
// expect(trans.cy).toBe(50) | |||
// }) | |||
// | |||
// describe('undo', function() { | |||
// it('sets an undo object which holds rotation', function() { | |||
// var extracted = (new SVG.Matrix(1,0,0,1,0,0)).rotate(20, 50, 50).extract() | |||
// trans.undo(extracted) | |||
// expect(trans._undo.rotation).toBeCloseTo(20) | |||
// }) | |||
// }) | |||
// | |||
// describe('at', function() { | |||
// it('creates a matrix at a certain position', function() { | |||
// expect(trans.at(0.3).toString()).toEqual((new SVG.Matrix()).rotate(0.3 * 45, 50, 50).toString()) | |||
// }) | |||
// it('returns the resulting transformation which has to be made to set an absolute translation', function() { | |||
// trans.undo((new SVG.Matrix()).rotate(20, 50, 50).extract()) | |||
// | |||
// expect(trans.at(0.4).a).toBeCloseTo(1,1) | |||
// expect(trans.at(0.4).b).toEqual(jasmine.any(Number)) | |||
// expect(trans.at(0.4).c).toEqual(jasmine.any(Number)) | |||
// expect(trans.at(0.4).d).toBeCloseTo(1,1) | |||
// expect(trans.at(0.4).e).toEqual(jasmine.any(Number)) | |||
// expect(trans.at(0.4).f).toEqual(jasmine.any(Number)) | |||
// }) | |||
// }) | |||
// }) | |||
// | |||
// | |||
// describe('SVG.Scale', function() { | |||
// var trans | |||
// | |||
// beforeEach(function(){ | |||
// trans = new SVG.Scale(2,2,50,50) | |||
// }) | |||
// | |||
// | |||
// it('creates an object of type SVG.Transformation', function() { | |||
// expect(trans instanceof SVG.Transformation).toBeTruthy() | |||
// }) | |||
// | |||
// it('uses scaleX, scaleY, cx and cy as arguments', function() { | |||
// expect(trans.arguments).toEqual(['scaleX', 'scaleY', 'cx', 'cy']) | |||
// }) | |||
// | |||
// it('s method is scale()', function() { | |||
// expect(trans.method).toEqual('scale') | |||
// }) | |||
// | |||
// it('sets the necessary parameters at creation', function() { | |||
// expect(trans.scaleX).toBe(2) | |||
// expect(trans.scaleY).toBe(2) | |||
// expect(trans.cx).toBe(50) | |||
// expect(trans.cy).toBe(50) | |||
// }) | |||
// | |||
// describe('undo', function() { | |||
// it('sets the undo matrix which can undo the translation', function() { | |||
// var extracted = (new SVG.Matrix(4,0,0,4,0,0)).extract() | |||
// trans.undo(extracted) | |||
// expect(trans._undo.toString()).toEqual('matrix(0.25,0,0,0.25,37.5,37.5)') | |||
// | |||
// var extracted = (new SVG.Matrix(10,0,0,10,20,20)).extract() | |||
// trans.undo(extracted) | |||
// expect(trans._undo.a).toBeCloseTo(1/extracted.scaleX) | |||
// expect(trans._undo.d).toBeCloseTo(1/extracted.scaleY) | |||
// expect(trans._undo.e).toBeCloseTo(45) | |||
// expect(trans._undo.f).toBeCloseTo(45) | |||
// | |||
// var extracted = (new SVG.Matrix(10,50,50,30,20,20)).extract() | |||
// trans.undo(extracted) | |||
// expect(trans._undo.a).toBeCloseTo(1/extracted.scaleX) | |||
// expect(trans._undo.d).toBeCloseTo(1/extracted.scaleY) | |||
// }) | |||
// }) | |||
// | |||
// describe('at', function() { | |||
// it('creates a matrix at a certain position', function() { | |||
// expect(trans.at(0.75).toString()).toEqual('matrix(1.75,0,0,1.75,-37.5,-37.5)') | |||
// }) | |||
// it('returns the inversed matrix from a specific position when created with inverse flag', function() { | |||
// var morphed = (new SVG.Scale(scaled.transform(2,2,50,50), true)).at(0.25) | |||
// | |||
// expect(morphed.a).toBeCloseTo(0.8) | |||
// expect(morphed.d).toBeCloseTo(0.8) | |||
// }) | |||
// it('returns the resulting transformation which has to be made to set an absolute translation', function() { | |||
// | |||
// var morphed = trans.undo((new SVG.Matrix(10,0,0,10,0,0)).extract()).at(0.5) | |||
// | |||
// expect(morphed.a).toBeCloseTo(0.6) | |||
// expect(morphed.b).toEqual(0) | |||
// expect(morphed.c).toEqual(0) | |||
// expect(morphed.d).toBeCloseTo(0.6) | |||
// expect(morphed.e).toBeCloseTo(20) | |||
// expect(morphed.f).toBeCloseTo(20) | |||
// }) | |||
// }) | |||
// }) | |||
// | |||
// describe('SVG.Skew', function() { | |||
// var trans | |||
// | |||
// beforeEach(function(){ | |||
// trans = new SVG.Skew(30,-30,50,50) | |||
// }) | |||
// | |||
// | |||
// it('creates an object of type SVG.Transformation', function() { | |||
// expect(trans instanceof SVG.Transformation).toBeTruthy() | |||
// }) | |||
// | |||
// it('uses scaleX, scaleY, cx and cy as arguments', function() { | |||
// expect(trans.arguments).toEqual(['skewX', 'skewY', 'cx', 'cy']) | |||
// }) | |||
// | |||
// it('s method is skew()', function() { | |||
// expect(trans.method).toEqual('skew') | |||
// }) | |||
// | |||
// it('sets the necessary parameters at creation', function() { | |||
// expect(trans.skewX).toBe(30) | |||
// expect(trans.skewY).toBe(-30) | |||
// expect(trans.cx).toBe(50) | |||
// expect(trans.cy).toBe(50) | |||
// }) | |||
// | |||
// describe('undo', function() { | |||
// it('sets the undo matrix which can undo the translation', function() { | |||
// var extracted = (new SVG.Matrix()).skew(90, 90, 0, 0).extract() | |||
// trans.undo(extracted) | |||
// expect(trans._undo.a).toBeCloseTo(0) | |||
// expect(trans._undo.b).toBeCloseTo(0) | |||
// expect(trans._undo.c).toBeCloseTo(0) | |||
// expect(trans._undo.d).toBeCloseTo(0) | |||
// expect(trans._undo.e).toBeCloseTo(50) | |||
// expect(trans._undo.f).toBeCloseTo(50) | |||
// | |||
// var extracted = (new SVG.Matrix(10,0,0,10,20,20)).extract() | |||
// trans.undo(extracted) | |||
// expect(trans._undo.a).toBeCloseTo(1) | |||
// expect(trans._undo.b).toBeCloseTo(0) | |||
// expect(trans._undo.c).toBeCloseTo(0) | |||
// expect(trans._undo.d).toBeCloseTo(1) | |||
// expect(trans._undo.e).toBeCloseTo(0) | |||
// expect(trans._undo.f).toBeCloseTo(0) | |||
// }) | |||
// }) | |||
// | |||
// describe('at', function() { | |||
// it('creates a matrix at a certain position', function() { | |||
// expect(trans.at(0.75)).toEqual((new SVG.Matrix()).morph((new SVG.Matrix()).skew(30, -30, 50, 50)).at(0.75)) | |||
// }) | |||
// it('returns the inversed matrix from a specific position when created with inverse flag', function() { | |||
// var morphed = (new SVG.Scale(skewed.transform(20,-20,50,50), true)).at(0.25) | |||
// | |||
// expect(morphed.a).toBeCloseTo(0.963) | |||
// expect(morphed.b).toBeCloseTo(0) | |||
// expect(morphed.c).toBeCloseTo(0) | |||
// expect(morphed.d).toBeCloseTo(0.963) | |||
// expect(morphed.e).toBeCloseTo(0) | |||
// expect(morphed.f).toBeCloseTo(0) | |||
// }) | |||
// it('returns the resulting transformation which has to be made to set an absolute translation', function() { | |||
// | |||
// var morphed = trans.undo((new SVG.Matrix(10,0,0,10,0,0)).skew(20, 30, 20, 10).extract()).at(0.5) | |||
// | |||
// expect(morphed.a).toBeCloseTo(1.266) | |||
// expect(morphed.b).toBeCloseTo(-0.7310) | |||
// expect(morphed.c).toBeCloseTo(0.1351) | |||
// expect(morphed.d).toBeCloseTo(0.9220) | |||
// expect(morphed.e).toBeCloseTo(-20.05593) | |||
// expect(morphed.f).toBeCloseTo(40.4468) | |||
// }) | |||
// }) | |||
// }) | |||
// }) |
@@ -18,7 +18,6 @@ SVG.Box = SVG.invent({ | |||
// add center, right, bottom... | |||
fullBox(this) | |||
}, | |||
extend: { | |||
// Merge rect box with another, return a new instance | |||
merge: function (box) { | |||
@@ -53,7 +52,11 @@ SVG.Box = SVG.invent({ | |||
yMax = Math.max(yMax, p.y) | |||
}) | |||
return new SVG.Box(xMin, yMin, xMax - xMin, yMax - yMin) | |||
return new SVG.Box( | |||
xMin, yMin, | |||
xMax - xMin, | |||
yMax - yMin | |||
) | |||
}, | |||
addOffset: function () { | |||
@@ -62,11 +65,9 @@ SVG.Box = SVG.invent({ | |||
this.y += window.pageYOffset | |||
return this | |||
}, | |||
toString: function () { | |||
return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height | |||
}, | |||
morph: function (x, y, width, height) { | |||
this.destination = new SVG.Box(x, y, width, height) | |||
return this | |||
@@ -76,15 +77,15 @@ SVG.Box = SVG.invent({ | |||
if (!this.destination) return this | |||
return new SVG.Box( | |||
this.x + (this.destination.x - this.x) * pos, | |||
this.y + (this.destination.y - this.y) * pos, | |||
this.width + (this.destination.width - this.width) * pos, | |||
this.height + (this.destination.height - this.height) * pos | |||
this.x + (this.destination.x - this.x) * pos | |||
, this.y + (this.destination.y - this.y) * pos | |||
, this.width + (this.destination.width - this.width) * pos | |||
, this.height + (this.destination.height - this.height) * pos | |||
) | |||
} | |||
}, | |||
// Define Parent | |||
// Define Parent | |||
parent: SVG.Element, | |||
// Constructor |
@@ -93,12 +93,12 @@ SVG.Matrix = SVG.invent({ | |||
// Applies a matrix defined by its affine parameters | |||
compose: function (o) { | |||
// Get the parameters | |||
var sx = o.scaleX | |||
var sy = o.scaleY | |||
var lam = o.shear | |||
var theta = o.rotate | |||
var tx = o.translateX | |||
var ty = o.translateY | |||
var sx = o.scaleX || 1 | |||
var sy = o.scaleY || 1 | |||
var lam = o.shear || 0 | |||
var theta = o.rotate || 0 | |||
var tx = o.translateX || 0 | |||
var ty = o.translateY || 0 | |||
// Apply the standard matrix | |||
var result = new SVG.Matrix() | |||
@@ -122,7 +122,7 @@ SVG.Matrix = SVG.invent({ | |||
// Figure out if the winding direction is clockwise or counterclockwise | |||
var determinant = a * d - b * c | |||
var ccw = determinant > 0 ? -1 : 1 | |||
var ccw = determinant > 0 ? 1 : -1 | |||
// Since we only shear in x, we can use the x basis to get the x scale | |||
// and the rotation of the resulting matrix | |||
@@ -145,13 +145,13 @@ SVG.Matrix = SVG.invent({ | |||
translateY: f, | |||
// Return the matrix parameters | |||
matrix: this, | |||
matrix: new SVG.Matrix(this), | |||
a: this.a, | |||
b: this.b, | |||
c: this.c, | |||
d: this.d, | |||
e: this.e, | |||
f: this.f, | |||
f: this.f | |||
} | |||
}, | |||
@@ -34,6 +34,12 @@ var sugar = { | |||
}) | |||
SVG.extend([SVG.Element, SVG.FX], { | |||
// Let the user set the matrix directly | |||
matrix: function (mat, b, c, d, e, f) { | |||
var matrix = new SVG.Matrix(arguments.length > 1 ? [mat, b, c, d, e, f] : mat) | |||
return this.attr('transform', matrix) | |||
}, | |||
// Map rotation to transform | |||
rotate: function (angle, cx, cy) { | |||
return this.transform({rotate: angle, origin: [cx, cy]}, true) | |||
@@ -69,11 +75,15 @@ SVG.extend([SVG.Element, SVG.FX], { | |||
// Map flip to transform | |||
flip: function (direction, around) { | |||
var directionString = typeof direction == 'string' ? direction | |||
: isFinite(direction) ? 'both' | |||
: 'both' | |||
var origin = (direction === 'both' && isFinite(around)) ? [around, around] | |||
: (direction === 'x') ? [around, 0] | |||
: (direction === 'y') ? [0, around] | |||
: isFinite(direction) ? [direction, direction] | |||
: [0, 0] | |||
this.transform({flip: direction || 'both', origin: origin}, true) | |||
this.transform({flip: directionString, origin: origin}, true) | |||
}, | |||
// Opacity |
@@ -44,7 +44,7 @@ SVG.extend(SVG.Element, { | |||
// same as above with parent equals root-svg | |||
toDoc: function () { | |||
return this.toParent(this.doc()) | |||
} | |||
}, | |||
}) | |||
SVG.extend(SVG.Element, { | |||
@@ -55,8 +55,9 @@ SVG.extend(SVG.Element, { | |||
var bbox = this.bbox() | |||
// Act as a getter if no object was passed | |||
if (o == null) { | |||
return new SVG.Matrix(this).decompose() | |||
if (o == null || typeof o === 'string') { | |||
var decomposed = new SVG.Matrix(this).decompose() | |||
return decomposed[o] || decomposed | |||
// Let the user pass in a matrix as well | |||
} else if (o.a != null) { |