summaryrefslogtreecommitdiffstats
path: root/src/transform.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/transform.js')
-rw-r--r--src/transform.js341
1 files changed, 26 insertions, 315 deletions
diff --git a/src/transform.js b/src/transform.js
index 54e9900..96c0aec 100644
--- a/src/transform.js
+++ b/src/transform.js
@@ -1,195 +1,11 @@
-/* global ensureCentre, capitalize, arrayToMatrix */
-
-SVG.extend(SVG.Element, {
- // Add transformations
- transform: function (o, relative) {
- // get target in case of the fx module, otherwise reference this
- var target = this
- var matrix, bbox
-
- // act as a getter
- if (typeof o !== 'object') {
- // get current matrix
- matrix = new SVG.Matrix(target).extract()
-
- return typeof o === 'string' ? matrix[o] : matrix
- }
-
- // 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())
- }
-
- matrix = matrix.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) {
- if (relative) {
- // relative
- matrix = matrix.translate(o.x, o.y)
- } else {
- // absolute
- if (o.x != null) matrix.e = o.x
- if (o.y != null) matrix.f = o.y
- }
- }
-
- return this.attr('transform', matrix)
- }
-})
-
-SVG.extend(SVG.FX, {
- transform: function (o, relative) {
- // get target in case of the fx module, otherwise reference this
- var target = this.target()
- var matrix, bbox
-
- // act as a getter
- if (typeof o !== 'object') {
- // get current matrix
- matrix = new SVG.Matrix(target).extract()
- return typeof o === 'string' ? matrix[o] : matrix
- }
-
- // ensure relative flag
- relative = !!relative || !!o.relative
-
- // act on matrix
- if (o.a != null) {
- matrix = new SVG.Matrix(o)
-
- // act on rotation
- } else if (o.rotation != null) {
- // ensure centre point
- ensureCentre(o, target)
-
- // apply transformation
- matrix = new SVG.Rotate(o.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
-
- 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()
- }
-})
+/* global arrayToMatrix getOrigin isMatrixLike */
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') || '')
@@ -197,16 +13,23 @@ SVG.extend(SVG.Element, {
.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) })]
+ return [kv[0],
+ kv[1].split(SVG.regex.delimiter)
+ .map(function (str) { return parseFloat(str) })
+ ]
})
+ .reverse()
// merge every transformation into one matrix
.reduce(function (matrix, transform) {
- if (transform[0] === 'matrix') return matrix.multiply(arrayToMatrix(transform[1]))
+ if (transform[0] === 'matrix') {
+ return matrix.lmultiply(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
@@ -217,143 +40,31 @@ SVG.extend(SVG.Element, {
return this
},
+
// same as above with parent equals root-svg
toDoc: function () {
return this.toParent(this.doc())
}
-
})
-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
+SVG.extend(SVG.Element, {
- this._undo = new SVG[capitalize(this.method)](o, true).at(1)
- return this
+ // Add transformations
+ transform: function (o, relative) {
+ // Act as a getter if no object was passed
+ if (o == null || typeof o === 'string') {
+ var decomposed = new SVG.Matrix(this).decompose()
+ return decomposed[o] || decomposed
}
- }
-
-})
-
-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
+ if (!isMatrixLike(o)) {
+ // Set the origin according to the defined transform
+ o = {...o, origin: getOrigin(o, 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'
+ // The user can pass a boolean, an SVG.Element or an SVG.Matrix or nothing
+ var cleanRelative = relative === true ? this : (relative || false)
+ var result = new SVG.Matrix(cleanRelative).transform(o)
+ return this.attr('transform', result)
}
})