This commit adds playgrounds and a build:dev mode. Now you can call npm run build:dev to make the linter warn you about errors without breaking. Also, we now have playgrounds, where you can use a built version of svg.js to run your own tests.tags/3.0.0
@@ -1,56 +1,55 @@ | |||
;( function() { | |||
/* global Snap */ | |||
;(function () { | |||
SVG.bench = { | |||
// Initalize test store | |||
_chain: [] | |||
, _before: function() {} | |||
, _after: function() {} | |||
, draw: SVG().addTo('#draw') | |||
, snap: Snap(100, 100) | |||
, raw: document.getElementById('native') | |||
_chain: [], | |||
_before: function () {}, | |||
_after: function () {}, | |||
draw: SVG().addTo('#draw'), | |||
snap: Snap(100, 100), | |||
raw: document.getElementById('native'), | |||
// Add descriptor | |||
, describe: function(name, closure) { | |||
describe: function (name, closure) { | |||
this._chain.push({ | |||
name: name | |||
, run: closure | |||
name: name, | |||
run: closure | |||
}) | |||
return this | |||
} | |||
}, | |||
// Add test | |||
, test: function(name, run) { | |||
test: function (name, run) { | |||
// run test | |||
var start = ( new Date ).getTime() | |||
var start = (new Date()).getTime() | |||
run() | |||
this.write( name, ( new Date ).getTime() - start ) | |||
this.write(name, (new Date()).getTime() - start) | |||
// clear everything | |||
this.clear() | |||
} | |||
}, | |||
// Skip test | |||
, skip: function(name, run) { | |||
this.write( name, false ) | |||
} | |||
skip: function (name, run) { | |||
this.write(name, false) | |||
}, | |||
// Run tests | |||
, run: function() { | |||
run: function () { | |||
this.pad() | |||
for (var h, i = 0, il = this._chain.length; i < il; i++) { | |||
var h = document.createElement('h1') | |||
h = document.createElement('h1') | |||
h.innerHTML = this._chain[i].name | |||
this.pad().appendChild(h) | |||
this._chain[i].run(this) | |||
} | |||
} | |||
}, | |||
// Write result | |||
, write: function(name, ms) { | |||
write: function (name, ms) { | |||
var test = document.createElement('div') | |||
if (typeof ms === 'number') { | |||
@@ -60,14 +59,14 @@ | |||
test.className = 'test skipped' | |||
test.innerHTML = name + ' (skipped)' | |||
} | |||
this.pad().appendChild(test) | |||
return this | |||
} | |||
}, | |||
// Reference writable element | |||
, pad: function() { | |||
pad: function () { | |||
var pad = document.getElementById('pad') | |||
if (!pad) { | |||
@@ -76,15 +75,15 @@ | |||
} | |||
return pad | |||
} | |||
}, | |||
// Clear canvasses | |||
, clear: function() { | |||
while(this.raw.hasChildNodes()) | |||
clear: function () { | |||
while (this.raw.hasChildNodes()) { | |||
this.raw.removeChild(this.raw.lastChild) | |||
} | |||
this.draw.clear() | |||
this.snap.clear() | |||
} | |||
} | |||
})(); | |||
})() |
@@ -98,8 +98,8 @@ gulp.task('unify', ['clean'], function () { | |||
.pipe(standard()) | |||
.pipe(standard.reporter('default', { | |||
showRuleNames: true, | |||
breakOnError: true, | |||
quiet: true | |||
breakOnError: process.argv[2] !== "--dont-break", | |||
quiet: true, | |||
})) | |||
.pipe(concat('svg.js', { newLine: '\n' })) | |||
// wrap the whole thing in an immediate function call | |||
@@ -109,6 +109,7 @@ gulp.task('unify', ['clean'], function () { | |||
.pipe(chmod(0o644)) | |||
.pipe(gulp.dest('dist')) | |||
.pipe(size({ showFiles: true, title: 'Full' })) | |||
return collection | |||
}) | |||
/** |
@@ -56,6 +56,7 @@ | |||
"scripts": { | |||
"build": "gulp", | |||
"build:test": "gulp unify", | |||
"build:dev": "gulp --dont-break", | |||
"test": "karma start .config/karma.conf.js --single-run", | |||
"test:quick": "karma start .config/karma.quick.js", | |||
"lint": "standard --verbose | snazzy" | |||
@@ -88,6 +89,7 @@ | |||
"standard": { | |||
"ignore": [ | |||
"/dist", | |||
"/spec", | |||
"/src/umd.js" | |||
], | |||
"globals": [ |
@@ -0,0 +1,42 @@ | |||
html { | |||
background-color : #f5f6f7; | |||
text-align: center; | |||
} | |||
h1 { | |||
color: #f06; | |||
font-size: 6vh; | |||
margin: 4vh; | |||
font-family: Helvetica; | |||
} | |||
svg { | |||
width: 70vw; | |||
height: 80vh; | |||
background-color: white; | |||
position: fixed; | |||
border-radius: 20px; | |||
border: #f065 1px solid; | |||
left: 15vw; | |||
} | |||
.pink { | |||
fill: #FF0066; | |||
} | |||
.green { | |||
fill: #00ff99; | |||
} | |||
.dark-pink { | |||
fill: #660029; | |||
} | |||
.light-pink { | |||
fill: #FF99C2; | |||
} | |||
.off-white { | |||
fill: #FFCCE0; | |||
} |
@@ -0,0 +1,27 @@ | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
<meta charset="utf-8"> | |||
<title>SVG Playground</title> | |||
<link rel="stylesheet" href="../playground.css"> | |||
</head> | |||
<body> | |||
<h1>SVG JS Playground</h1> | |||
<svg viewBox="0 0 1000 1000"> | |||
<rect id="old" x=300 y=400 width=200 height=400 class="green"/> | |||
<rect id="new" x=300 y=400 width=200 height=400 class="pink"/> | |||
</svg> | |||
</body> | |||
<script src="../../dist/svg.js" charset="utf-8"></script> | |||
<script src="transforms.js" charset="utf-8"></script> | |||
</html> |
@@ -0,0 +1,7 @@ | |||
let mover = SVG.select("#new")[0] | |||
console.log(mover.transform()); | |||
mover.transform({ | |||
position: [30, 50] | |||
}) |
@@ -19,11 +19,11 @@ describe('Transformations:', function() { | |||
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() | |||
@@ -51,7 +51,7 @@ describe('Transformations:', function() { | |||
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) | |||
@@ -78,14 +78,14 @@ describe('Transformations:', function() { | |||
}) | |||
}) | |||
}) | |||
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() | |||
@@ -129,15 +129,15 @@ describe('Transformations:', function() { | |||
}) | |||
}) | |||
}) | |||
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() | |||
@@ -170,7 +170,7 @@ describe('Transformations:', function() { | |||
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) | |||
@@ -184,12 +184,12 @@ describe('Transformations:', function() { | |||
}) | |||
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) | |||
@@ -200,15 +200,15 @@ describe('Transformations:', function() { | |||
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() | |||
@@ -257,7 +257,7 @@ describe('Transformations:', function() { | |||
}) | |||
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) | |||
@@ -266,7 +266,7 @@ describe('Transformations:', function() { | |||
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) | |||
@@ -278,5 +278,4 @@ describe('Transformations:', function() { | |||
}) | |||
}) | |||
}) | |||
}) |
@@ -1,4 +1,4 @@ | |||
/* global abcdef, arrayToMatrix, deltaTransformPoint, parseMatrix */ | |||
/* global abcdef, arrayToMatrix, parseMatrix, unitCircle, mag */ | |||
SVG.Matrix = SVG.invent({ | |||
// Initialize | |||
@@ -23,159 +23,130 @@ SVG.Matrix = SVG.invent({ | |||
}, | |||
// Add methods | |||
, extend: { | |||
extend: { | |||
// Convert an object of affine parameters into a matrix | |||
compose: function (o, cx, cy) { | |||
// Set the defaults | |||
var tx = o.translateX || 0 | |||
, ty = o.translateY || 0 | |||
, theta = o.theta || 0 | |||
, sx = o.scaleX || 1 | |||
, sy = o.scaleY || 1 | |||
, lam = o.shear || 0 | |||
, cx = cx || 0 | |||
, cy = cy || 0 | |||
var ty = o.translateY || 0 | |||
var theta = o.theta || 0 | |||
var sx = o.scaleX || 1 | |||
var sy = o.scaleY || 1 | |||
var lam = o.shear || 0 | |||
cx = cx || 0 | |||
cy = cy || 0 | |||
// Calculate the trigonometric values | |||
var ct = Math.cos(theta * Math.PI / 180) | |||
, st Math.sin(theta * Math.PI / 180) | |||
var st = Math.sin(theta * Math.PI / 180) | |||
// Calculate the matrix components directly | |||
var a = sx * ct | |||
, b = sx * st | |||
, c = lam * sx * ct - sy * st | |||
, d = lam * sx * st + sy * ct | |||
, e = - sx * ct * (cx + cy * lam) + sy * st * cy + tx + cx | |||
, f = - sx * st * (cx + cy * lam) - sy * ct * cy + ty + cy | |||
var b = sx * st | |||
var c = lam * sx * ct - sy * st | |||
var d = lam * sx * st + sy * ct | |||
var e = -sx * ct * (cx + cy * lam) + sy * st * cy + tx + cx | |||
var f = -sx * st * (cx + cy * lam) - sy * ct * cy + ty + cy | |||
// Construct a new matrix and return it | |||
var matrix = new SVG.Matrix([a, b, c, d, e, f]) | |||
return matrix | |||
} | |||
}, | |||
// Decompose a matrix into the affine parameters needed to form it | |||
, decompose: function (matrix, cx, cy) { | |||
decompose: function (matrix, cx, cy) { | |||
// Get the paramaters of the current matrix | |||
var a = matrix.a | |||
, b = matrix.b | |||
, c = matrix.c | |||
, d = matrix.d | |||
, e = matrix.e | |||
, f = matrix.f | |||
var b = matrix.b | |||
var c = matrix.c | |||
var d = matrix.d | |||
var e = matrix.e | |||
var f = matrix.f | |||
// Project the first basis vector onto the unit circle | |||
var circle = unitCircle (a, b) | |||
, theta = circle.theta | |||
, ct = circle.cos | |||
, st = circle.sin | |||
var circle = unitCircle(a, b) | |||
var theta = circle.theta | |||
var ct = circle.cos | |||
var st = circle.sin | |||
// Work out the transformation parameters | |||
var signX = Math.sign(a * ct + b * st) | |||
, sx = signX * mag (a, b) | |||
, lam = (st * d + ct * c) / (ct * a + st * b) | |||
, signY = Math.sign(- c * st + d * ct) | |||
, sy = mag (lam * a - c, d - lam * b) | |||
, tx = e - cx + cx * ct * sx + cy * (lam * ct * sx - st * sy) | |||
, ty = f - cy + cx * st * sx + cy * (lam * st * sx + ct * sy) | |||
var sx = signX * mag(a, b) | |||
var lam = (st * d + ct * c) / (ct * a + st * b) | |||
var sy = mag(lam * a - c, d - lam * b) | |||
var tx = e - cx + cx * ct * sx + cy * (lam * ct * sx - st * sy) | |||
var ty = f - cy + cx * st * sx + cy * (lam * st * sx + ct * sy) | |||
// Package and return the parameters | |||
return { | |||
// Bundle the affine parameters | |||
translateX: tx | |||
, translateY: ty | |||
, theta: theta | |||
, scaleX: sx | |||
, scaleY: sy | |||
, shear: lam | |||
translateX: tx, | |||
translateY: ty, | |||
theta: theta, | |||
scaleX: sx, | |||
scaleY: sy, | |||
shear: lam, | |||
// Bundle the matrix parameters | |||
, a: this.a | |||
, b: this.b | |||
, c: this.c | |||
, d: this.d | |||
, e: this.e | |||
, f: this.f | |||
// Return the new origin point | |||
, x: this.e | |||
, y: this.f | |||
// Store the matrix | |||
, matrix: new SVG.Matrix(this) | |||
// 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, | |||
// Return the new origin point | |||
x: this.e, | |||
y: this.f, | |||
matrix: new SVG.Matrix(this) | |||
>>>>>>> 3.0.0 | |||
} | |||
}, | |||
// Clone matrix | |||
, form: function (o) { | |||
// Get all of the parameters required to form the matrix | |||
var flipX = o.flip && (o.flip == "x" || o.flip == "both") ? -1 : 1 | |||
, flipY = o.flip && (o.flip == "y" || o.flip == "both") ? -1 : 1 | |||
, kX = o.skew.length ? o.skew[0] | |||
form: function (o) { | |||
// Get all of the parameters required to form the matrix | |||
var flipX = o.flip && (o.flip === 'x' || o.flip === 'both') ? -1 : 1 | |||
var flipY = o.flip && (o.flip === 'y' || o.flip === 'both') ? -1 : 1 | |||
var skewX = o.skew.length ? o.skew[0] | |||
: isFinite(o.skew) ? o.skew | |||
: isFinite(o.skewX) ? o.skewX | |||
: 0 | |||
, kY = o.skew.length ? o.skew[1] | |||
var skewY = o.skew.length ? o.skew[1] | |||
: isFinite(o.skew) ? o.skew | |||
: isFinite(o.skewY) ? o.skewY | |||
: 0 | |||
, skewX = o.scale.length ? o.scale[0] * flipX | |||
var sx = o.scale.length ? o.scale[0] * flipX | |||
: isFinite(o.scale) ? o.scale * flipX | |||
: isFinite(o.scaleX) ? o.scaleX * flipX | |||
: flipX | |||
, skewY = o.scale.length ? o.scale[1] * flipY | |||
var sy = o.scale.length ? o.scale[1] * flipY | |||
: isFinite(o.scale) ? o.scale * flipY | |||
: isFinite(o.scaleY) ? o.scaleY * flipY | |||
: flipY | |||
, kx = Math.tan(SVG.utils.radians(skewX)) | |||
, ky = Math.tan(SVG.utils.radians(skewY)) | |||
, lam = o.shear || 0 | |||
, theta = SVG.utils.radians(o.rotate || 0) | |||
, st = Math.sin(theta) | |||
, ct = Math.cos(theta) | |||
, ox = o.origin.length ? o.origin[0] : o.ox || 0 | |||
, oy = o.origin.length ? o.origin[1] : o.oy || 0 | |||
, px = o.position.length ? o.position[0] : o.px || ox | |||
, py = o.position.length ? o.position[1] : o.py || oy | |||
, tx = o.translate.length ? o.translate[0] : o.tx || 0 | |||
, ty = o.translate.length ? o.translate[1] : o.ty || 0 | |||
var kx = Math.tan(SVG.utils.radians(skewX)) | |||
var ky = Math.tan(SVG.utils.radians(skewY)) | |||
var lam = o.shear || 0 | |||
var theta = SVG.utils.radians(o.rotate || 0) | |||
var st = Math.sin(theta) | |||
var ct = Math.cos(theta) | |||
var ox = o.origin.length ? o.origin[0] : o.ox || 0 | |||
var oy = o.origin.length ? o.origin[1] : o.oy || 0 | |||
var px = o.position.length ? o.position[0] : o.px || ox | |||
var py = o.position.length ? o.position[1] : o.py || oy | |||
var tx = o.translate.length ? o.translate[0] : o.tx || 0 | |||
var ty = o.translate.length ? o.translate[1] : o.ty || 0 | |||
// Form the matrix parameters... aka. welcome to wonderland! (used wolfram) | |||
var a = ct*sx + ky*st*sy | |||
, b = ct*ky*sy - st*sx | |||
, c = ct*kx*sx + st*sy + lam*(ct*sx+ky*st*sy) | |||
, d = -kx*st*sx + ct*sy + lam*(-st*sx + ct*ky*sy) | |||
, e = px + tx + cx*(ct*sx+ky*st*sy) + cy*(ct*kx*sx+st*sy+lam*(ct*sx+ky*st*sy)) | |||
, f = py + ty + cx*(-st*sx + ct*ky*sy) + cy*(-kx*st*sx + ct*sy + lam*(-st*sx + ct*ky*sy)) | |||
, result = new Matrix(a, b, c, d, e, f) | |||
return result | |||
} | |||
, clone: function() { | |||
var a = ct * sx + ky * st * sy | |||
var b = ct * ky * sy - st * sx | |||
var c = ct * kx * sx + st * sy + lam * (ct * sx + ky * st * sy) | |||
var d = -kx * st * sx + ct * sy + lam * (-st * sx + ct * ky * sy) | |||
var e = px + tx + ox * (ct * sx + ky * st * sy) + oy * (ct * kx * sx + st * sy + lam * (ct * sx + ky * st * sy)) | |||
var f = py + ty + ox * (-st * sx + ct * ky * sy) + oy * (-kx * st * sx + ct * sy + lam * (-st * sx + ct * ky * sy)) | |||
var result = new SVG.Matrix(a, b, c, d, e, f) | |||
return result | |||
}, | |||
clone: function () { | |||
>>>>>>> 3.0.0 | |||
return new SVG.Matrix(this) | |||
}, | |||
// Morph one matrix into another | |||
@@ -211,15 +182,15 @@ SVG.Matrix = SVG.invent({ | |||
return new SVG.Matrix(this.native().inverse()) | |||
}, | |||
// Translate matrix | |||
, translate: function(x, y) { | |||
var translation = new SVG.Matrix(this.native().translate(x || 0, y || 0)) | |||
, matrix = this.multiply(translation) | |||
translate: function (x, y) { | |||
var translation = new SVG.Matrix(this.native().translate(x || 0, y || 0)) | |||
var matrix = this.multiply(translation) | |||
return matrix | |||
} | |||
}, | |||
// Scale matrix | |||
, scale: function(x, y, cx, cy) { | |||
scale: function (x, y, cx, cy) { | |||
// Support uniform scaling | |||
if (arguments.length == 1) { | |||
if (arguments.length === 1) { | |||
y = x | |||
} else if (arguments.length === 3) { | |||
cy = cx | |||
@@ -229,22 +200,21 @@ SVG.Matrix = SVG.invent({ | |||
// Rotate the current matrix | |||
var scale = new SVG.Matrix(x, 0, 0, y, 0, 0) | |||
, centered = this.around(cx, cy, rotation) | |||
, matrix = this.multiply(centered) | |||
return scale | |||
} | |||
var centered = this.around(cx, cy, scale) | |||
var matrix = this.multiply(centered) | |||
return matrix | |||
}, | |||
// Rotate matrix | |||
, rotate: function(r, cx, cy) { | |||
rotate: function (r, cx, cy) { | |||
// Convert degrees to radians | |||
r = SVG.utils.radians(r) | |||
// Construct the rotation matrix | |||
var rotation = new SVG.Matrix(Math.cos(r), Math.sin(r), -Math.sin(r), Math.cos(r), 0, 0) | |||
, centered = this.around(cx, cy, rotation) | |||
, matrix = this.multiply(centered) | |||
var centered = this.around(cx, cy, rotation) | |||
var matrix = this.multiply(centered) | |||
return matrix | |||
} | |||
}, | |||
// Flip matrix on x or y, at a given offset | |||
flip: function (a, o) { | |||
return a === 'x' ? this.scale(-1, 1, o, 0) | |||
@@ -252,13 +222,13 @@ SVG.Matrix = SVG.invent({ | |||
: this.scale(-1, -1, a, o != null ? o : a) | |||
}, | |||
// Skew | |||
, shear: function(a, cx, cy) { | |||
var shear = new SVG.Matrix(1, a, 0, 1, 0, 0) | |||
, centered = this.around(cx, cy, shear) | |||
, matrix = this.multiply(centered) | |||
return matrix | |||
} | |||
, skew: function(x, y, cx, cy) { | |||
shear: function (a, cx, cy) { | |||
var shear = new SVG.Matrix(1, a, 0, 1, 0, 0) | |||
var centered = this.around(cx, cy, shear) | |||
var matrix = this.multiply(centered) | |||
return matrix | |||
}, | |||
skew: function (x, y, cx, cy) { | |||
// support uniformal skew | |||
if (arguments.length === 1) { | |||
y = x | |||
@@ -274,10 +244,10 @@ SVG.Matrix = SVG.invent({ | |||
// Construct the matrix | |||
var skew = new SVG.Matrix(1, Math.tan(y), Math.tan(x), 1, 0, 0) | |||
, centered = this.around(cx, cy, skew) | |||
, matrix = this.multiply(centered) | |||
var centered = this.around(cx, cy, skew) | |||
var matrix = this.multiply(centered) | |||
return matrix | |||
} | |||
}, | |||
// SkewX | |||
skewX: function (x, cx, cy) { | |||
return this.skew(x, 0, cx, cy) |
@@ -35,17 +35,17 @@ var sugar = { | |||
SVG.extend([SVG.Element, SVG.FX], { | |||
// Map rotation to transform | |||
, rotate: function(angle, cx, cy) { | |||
rotate: function (angle, cx, cy) { | |||
var matrix = new SVG.Matrix().rotate(angle, cx, cy) | |||
return this.transform({ rotation: d, cx: cx, cy: cy }) | |||
return this.matrix(matrix, true) | |||
}, | |||
// Map skew to transform | |||
, skew: function(x, y, cx, cy) { | |||
return arguments.length == 1 || arguments.length == 3 ? | |||
this.transform({ skew: x, cx: y, cy: cx }) : | |||
this.transform({ skewX: x, skewY: y, cx: cx, cy: cy }) | |||
} | |||
skew: function (x, y, cx, cy) { | |||
var matrix = arguments.length === 1 || arguments.length === 3 | |||
? new SVG.Matrix().skew(x, x, cx, cy) | |||
: new SVG.Matrix().skew(x, y, cx, cy) | |||
return this.matrix(matrix, true) | |||
}, | |||
// Map scale to transform | |||
scale: function (x, y, cx, cy) { | |||
return arguments.length === 1 || arguments.length === 3 | |||
@@ -60,7 +60,7 @@ SVG.extend([SVG.Element, SVG.FX], { | |||
flip: function (a, o) { | |||
o = typeof a === 'number' ? a : o | |||
return this.transform({ flip: a || 'both', offset: o }) | |||
} | |||
}, | |||
// Opacity | |||
opacity: function (value) { | |||
return this.attr('opacity', value) |
@@ -1,37 +1,72 @@ | |||
/* global ensureCentre, capitalize, arrayToMatrix */ | |||
/* global arrayToMatrix */ | |||
SVG.extend(SVG.Element, { | |||
// Reset all transformations | |||
untransform: function () { | |||
return this.attr('transform', null) | |||
}, | |||
// Add transformations | |||
transform: function (o) { | |||
// merge the whole transformation chain into one matrix and returns it | |||
matrixify: function () { | |||
var matrix = (this.attr('transform') || '') | |||
// split transformations | |||
.split(SVG.regex.transforms).slice(0, -1).map(function (str) { | |||
// generate key => value pairs | |||
var kv = str.trim().split('(') | |||
return [kv[0], kv[1].split(SVG.regex.delimiter).map(function (str) { return parseFloat(str) })] | |||
}) | |||
// merge every transformation into one matrix | |||
.reduce(function (matrix, transform) { | |||
if (transform[0] === 'matrix') return matrix.multiply(arrayToMatrix(transform[1])) | |||
return matrix[transform[0]].apply(matrix, transform[1]) | |||
}, new SVG.Matrix()) | |||
/** | |||
* EXTRACTING PARAMETERS | |||
*/ | |||
return matrix | |||
}, | |||
// add an element to another parent without changing the visual representation on the screen | |||
toParent: function (parent) { | |||
if (this === parent) return this | |||
var ctm = this.screenCTM() | |||
var pCtm = parent.screenCTM().inverse() | |||
this.addTo(parent).untransform().transform(pCtm.multiply(ctm)) | |||
return this | |||
}, | |||
// same as above with parent equals root-svg | |||
toDoc: function () { | |||
return this.toParent(this.doc()) | |||
} | |||
}) | |||
SVG.extend(SVG.Element, { | |||
// Add transformations | |||
transform: function (o) { | |||
// Act as a getter if no object was passed | |||
if (typeof o !== 'object') { | |||
matrix = new SVG.Matrix(this).extract() | |||
var matrix = new SVG.Matrix(this).decompose() | |||
return typeof o === 'string' ? matrix[o] : matrix | |||
} | |||
// Allow the user to define the origin with a string | |||
if (typeof o.origin === "string") { | |||
if (typeof o.origin === 'string') { | |||
// Get the bounding box and string to use in our calculations | |||
var string = o.origin.toLowerCase().trim() | |||
, bbox = this.bbox() | |||
, x = bbox.x | |||
, y = bbox.y | |||
, width = bbox.width | |||
, height = bbox.height | |||
var bbox = this.bbox() | |||
var x = bbox.x | |||
var y = bbox.y | |||
var width = bbox.width | |||
var height = bbox.height | |||
// Set the bounds eg : "bottom-left", "Top right", "middle" etc... | |||
o.ox = string.includes("left") ? x | |||
: string.includes("right") ? x + width | |||
o.ox = string.includes('left') ? x | |||
: string.includes('right') ? x + width | |||
: x + width / 2 | |||
o.oy = string.includes("top") ? y | |||
: string.includes("bottom") ? y + height | |||
o.oy = string.includes('top') ? y | |||
: string.includes('bottom') ? y + height | |||
: y + height / 2 | |||
// Make sure we only pass ox and oy | |||
@@ -40,71 +75,14 @@ SVG.extend(SVG.Element, { | |||
// Get the resulting matrix and apply it to the element | |||
var result = new SVG.Matrix().form(o) | |||
, matrixString = result.toString() | |||
// get current matrix | |||
matrix = new SVG.Matrix(target) | |||
// ensure relative flag | |||
relative = !!relative || !!o.relative | |||
// act on matrix | |||
if (o.a != null) { | |||
matrix = relative | |||
? matrix.multiply(new SVG.Matrix(o)) | |||
: new SVG.Matrix(o) | |||
// act on rotation | |||
} else if (o.rotation != null) { | |||
// ensure centre point | |||
ensureCentre(o, target) | |||
// apply transformation | |||
matrix = relative | |||
? matrix.rotate(o.rotation, o.cx, o.cy) | |||
: matrix.rotate(o.rotation - matrix.extract().rotation, o.cx, o.cy) | |||
// act on scale | |||
} else if (o.scale != null || o.scaleX != null || o.scaleY != null) { | |||
// ensure centre point | |||
ensureCentre(o, target) | |||
// ensure scale values on both axes | |||
o.scaleX = o.scale != null ? o.scale : o.scaleX != null ? o.scaleX : 1 | |||
o.scaleY = o.scale != null ? o.scale : o.scaleY != null ? o.scaleY : 1 | |||
if (!relative) { | |||
// absolute; multiply inversed values | |||
var e = matrix.extract() | |||
o.scaleX = o.scaleX * 1 / e.scaleX | |||
o.scaleY = o.scaleY * 1 / e.scaleY | |||
} | |||
matrix = matrix.scale(o.scaleX, o.scaleY, o.cx, o.cy) | |||
// act on skew | |||
} else if (o.skew != null || o.skewX != null || o.skewY != null) { | |||
// ensure centre point | |||
ensureCentre(o, target) | |||
// ensure skew values on both axes | |||
o.skewX = o.skew != null ? o.skew : o.skewX != null ? o.skewX : 0 | |||
o.skewY = o.skew != null ? o.skew : o.skewY != null ? o.skewY : 0 | |||
if (!relative) { | |||
// absolute; reset skew values | |||
var el = matrix.extract() | |||
matrix = matrix.multiply(new SVG.Matrix().skew(el.skewX, el.skewY, el.cx, el.cy).inverse()) | |||
} | |||
>>>>>>> 3.0.0 | |||
var matrixString = result.toString() | |||
// Apply the result | |||
return this.attr('transform', matrix) | |||
} | |||
} | |||
return this.attr('transform', matrixString) | |||
}, | |||
// Map matrix to transform | |||
, matrix: function(m, relative) { | |||
matrix: function (m, relative) { | |||
// Construct a matrix from the first parameter | |||
var matrix = new SVG.Matrix(m) | |||
@@ -120,10 +98,7 @@ SVG.extend(SVG.Element, { | |||
}) | |||
SVG.extend(SVG.FX, { | |||
transform: function(o, relative) { | |||
transform: function (o, relative) { | |||
// // get target in case of the fx module, otherwise reference this | |||
// var target = this.target() | |||
@@ -203,90 +178,51 @@ SVG.extend(SVG.FX, { | |||
// | |||
// return this._callStart() | |||
// } | |||
// ensure scale values on both axes | |||
o.scaleX = o.scale != null ? o.scale : o.scaleX != null ? o.scaleX : 1 | |||
o.scaleY = o.scale != null ? o.scale : o.scaleY != null ? o.scaleY : 1 | |||
matrix = new SVG.Scale(o.scaleX, o.scaleY, o.cx, o.cy) | |||
// act on skew | |||
} else if (o.skewX != null || o.skewY != null) { | |||
// ensure centre point | |||
ensureCentre(o, target) | |||
// ensure skew values on both axes | |||
o.skewX = o.skewX != null ? o.skewX : 0 | |||
o.skewY = o.skewY != null ? o.skewY : 0 | |||
matrix = new SVG.Skew(o.skewX, o.skewY, o.cx, o.cy) | |||
// act on flip | |||
} else if (o.flip) { | |||
if (o.flip === 'x' || o.flip === 'y') { | |||
o.offset = o.offset == null ? target.bbox()['c' + o.flip] : o.offset | |||
} else { | |||
if (o.offset == null) { | |||
bbox = target.bbox() | |||
o.flip = bbox.cx | |||
o.offset = bbox.cy | |||
} else { | |||
o.flip = o.offset | |||
} | |||
} | |||
matrix = new SVG.Matrix().flip(o.flip, o.offset) | |||
// act on translate | |||
} else if (o.x != null || o.y != null) { | |||
matrix = new SVG.Translate(o.x, o.y) | |||
} | |||
if (!matrix) return this | |||
matrix.relative = relative | |||
this.last().transforms.push(matrix) | |||
return this._callStart() | |||
} | |||
>>>>>>> 3.0.0 | |||
}) | |||
SVG.extend(SVG.Element, { | |||
// Reset all transformations | |||
untransform: function () { | |||
return this.attr('transform', null) | |||
}, | |||
// merge the whole transformation chain into one matrix and returns it | |||
matrixify: function () { | |||
var matrix = (this.attr('transform') || '') | |||
// split transformations | |||
.split(SVG.regex.transforms).slice(0, -1).map(function (str) { | |||
// generate key => value pairs | |||
var kv = str.trim().split('(') | |||
return [kv[0], kv[1].split(SVG.regex.delimiter).map(function (str) { return parseFloat(str) })] | |||
}) | |||
// merge every transformation into one matrix | |||
.reduce(function (matrix, transform) { | |||
if (transform[0] === 'matrix') return matrix.multiply(arrayToMatrix(transform[1])) | |||
return matrix[transform[0]].apply(matrix, transform[1]) | |||
}, new SVG.Matrix()) | |||
return matrix | |||
}, | |||
// add an element to another parent without changing the visual representation on the screen | |||
toParent: function (parent) { | |||
if (this === parent) return this | |||
var ctm = this.screenCTM() | |||
var pCtm = parent.screenCTM().inverse() | |||
this.addTo(parent).untransform().transform(pCtm.multiply(ctm)) | |||
return this | |||
}, | |||
// same as above with parent equals root-svg | |||
toDoc: function () { | |||
return this.toParent(this.doc()) | |||
// // ensure scale values on both axes | |||
// o.scaleX = o.scale != null ? o.scale : o.scaleX != null ? o.scaleX : 1 | |||
// o.scaleY = o.scale != null ? o.scale : o.scaleY != null ? o.scaleY : 1 | |||
// | |||
// matrix = new SVG.Scale(o.scaleX, o.scaleY, o.cx, o.cy) | |||
// | |||
// // act on skew | |||
// } else if (o.skewX != null || o.skewY != null) { | |||
// // ensure centre point | |||
// ensureCentre(o, target) | |||
// | |||
// // ensure skew values on both axes | |||
// o.skewX = o.skewX != null ? o.skewX : 0 | |||
// o.skewY = o.skewY != null ? o.skewY : 0 | |||
// | |||
// matrix = new SVG.Skew(o.skewX, o.skewY, o.cx, o.cy) | |||
// | |||
// // act on flip | |||
// } else if (o.flip) { | |||
// if (o.flip === 'x' || o.flip === 'y') { | |||
// o.offset = o.offset == null ? target.bbox()['c' + o.flip] : o.offset | |||
// } else { | |||
// if (o.offset == null) { | |||
// bbox = target.bbox() | |||
// o.flip = bbox.cx | |||
// o.offset = bbox.cy | |||
// } else { | |||
// o.flip = o.offset | |||
// } | |||
// } | |||
// | |||
// matrix = new SVG.Matrix().flip(o.flip, o.offset) | |||
// | |||
// // act on translate | |||
// } else if (o.x != null || o.y != null) { | |||
// matrix = new SVG.Translate(o.x, o.y) | |||
// } | |||
// | |||
// if (!matrix) return this | |||
// | |||
// matrix.relative = relative | |||
// | |||
// this.last().transforms.push(matrix) | |||
// | |||
// return this._callStart() | |||
} | |||
}) | |||
@@ -432,137 +368,3 @@ SVG.extend(SVG.Element, { | |||
// } | |||
// | |||
// }) | |||
SVG.Transformation = SVG.invent({ | |||
create: function (source, inversed) { | |||
if (arguments.length > 1 && typeof inversed !== 'boolean') { | |||
return this.constructor.bind(this)([].slice.call(arguments)) | |||
} | |||
var i, len | |||
if (Array.isArray(source)) { | |||
for (i = 0, len = this.arguments.length; i < len; ++i) { | |||
this[this.arguments[i]] = source[i] | |||
} | |||
} else if (typeof source === 'object') { | |||
for (i = 0, len = this.arguments.length; i < len; ++i) { | |||
this[this.arguments[i]] = source[this.arguments[i]] | |||
} | |||
} | |||
this.inversed = false | |||
if (inversed === true) { | |||
this.inversed = true | |||
} | |||
}, | |||
extend: { | |||
arguments: [], | |||
method: '', | |||
at: function (pos) { | |||
var params = [] | |||
for (var i = 0, len = this.arguments.length; i < len; ++i) { | |||
params.push(this[this.arguments[i]]) | |||
} | |||
var m = this._undo || new SVG.Matrix() | |||
m = new SVG.Matrix().morph(SVG.Matrix.prototype[this.method].apply(m, params)).at(pos) | |||
return this.inversed ? m.inverse() : m | |||
}, | |||
undo: function (o) { | |||
for (var i = 0, len = this.arguments.length; i < len; ++i) { | |||
o[this.arguments[i]] = typeof this[this.arguments[i]] === 'undefined' ? 0 : o[this.arguments[i]] | |||
} | |||
// The method SVG.Matrix.extract which was used before calling this | |||
// method to obtain a value for the parameter o doesn't return a cx and | |||
// a cy so we use the ones that were provided to this object at its creation | |||
o.cx = this.cx | |||
o.cy = this.cy | |||
this._undo = new SVG[capitalize(this.method)](o, true).at(1) | |||
return this | |||
} | |||
} | |||
}) | |||
SVG.Translate = SVG.invent({ | |||
parent: SVG.Matrix, | |||
inherit: SVG.Transformation, | |||
create: function (source, inversed) { | |||
this.constructor.apply(this, [].slice.call(arguments)) | |||
}, | |||
extend: { | |||
arguments: ['transformedX', 'transformedY'], | |||
method: 'translate' | |||
} | |||
}) | |||
SVG.Rotate = SVG.invent({ | |||
parent: SVG.Matrix, | |||
inherit: SVG.Transformation, | |||
create: function (source, inversed) { | |||
this.constructor.apply(this, [].slice.call(arguments)) | |||
}, | |||
extend: { | |||
arguments: ['rotation', 'cx', 'cy'], | |||
method: 'rotate', | |||
at: function (pos) { | |||
var m = new SVG.Matrix().rotate(new SVG.Number().morph(this.rotation - (this._undo ? this._undo.rotation : 0)).at(pos), this.cx, this.cy) | |||
return this.inversed ? m.inverse() : m | |||
}, | |||
undo: function (o) { | |||
this._undo = o | |||
return this | |||
} | |||
} | |||
}) | |||
SVG.Scale = SVG.invent({ | |||
parent: SVG.Matrix, | |||
inherit: SVG.Transformation, | |||
create: function (source, inversed) { | |||
this.constructor.apply(this, [].slice.call(arguments)) | |||
}, | |||
extend: { | |||
arguments: ['scaleX', 'scaleY', 'cx', 'cy'], | |||
method: 'scale' | |||
} | |||
}) | |||
SVG.Skew = SVG.invent({ | |||
parent: SVG.Matrix, | |||
inherit: SVG.Transformation, | |||
create: function (source, inversed) { | |||
this.constructor.apply(this, [].slice.call(arguments)) | |||
}, | |||
extend: { | |||
arguments: ['skewX', 'skewY', 'cx', 'cy'], | |||
method: 'skew' | |||
} | |||
}) | |||
>>>>>>> 3.0.0 |
@@ -1,3 +1,4 @@ | |||
SVG.utils = { | |||
// Map function | |||
map: function (array, block) { |