summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlrich-Matthias Schäfer <ulima.ums@googlemail.com>2018-09-20 13:25:24 +0200
committerUlrich-Matthias Schäfer <ulima.ums@googlemail.com>2018-09-20 13:25:24 +0200
commit6270500e28c419bf01626af72d8d65a8eab9fe1b (patch)
treebd309501e22adaf778d6cf4b0a4dd436f1f3405a /src
parent545d3213740d3fabcc2f78471acfdb372e8fbd0b (diff)
downloadsvg.js-6270500e28c419bf01626af72d8d65a8eab9fe1b.tar.gz
svg.js-6270500e28c419bf01626af72d8d65a8eab9fe1b.zip
finally solve transformations one and for all time!
This is great - we should party hard. I mean - it took like 4 month to get this done. That's way to much! I don't want anymore. Pease send help :D
Diffstat (limited to 'src')
-rw-r--r--src/helpers.js2
-rw-r--r--src/runner.js167
2 files changed, 89 insertions, 80 deletions
diff --git a/src/helpers.js b/src/helpers.js
index 7860048..9982b36 100644
--- a/src/helpers.js
+++ b/src/helpers.js
@@ -251,7 +251,7 @@ function formatTransforms (o) {
function getOrigin (o, element, inSpace) {
// Allow origin or around as the names
- let origin = o.around == null ? o.origin : o.around
+ let origin = o.origin // o.around == null ? o.origin : o.around
let ox, oy
// Allow the user to pass a string to rotate around a given point
diff --git a/src/runner.js b/src/runner.js
index d892637..09d9703 100644
--- a/src/runner.js
+++ b/src/runner.js
@@ -48,8 +48,9 @@ SVG.Runner = SVG.invent({
this.tags = {}
// Save transforms applied to this runner
+ // this.transforms = [new SVG.Matrix()]
this.transforms = new SVG.Matrix()
- this.targets = new SVG.Matrix()
+ this.transformId = 1
// Looping variables
this._haveReversed = false
@@ -294,6 +295,9 @@ SVG.Runner = SVG.invent({
// Call initialise and the run function
if ( running || declarative ) {
this._initialise(running)
+
+ // clear the transforms on this runner so they dont get added again and again
+ // this.transforms = [new SVG.Matrix()]
this.transforms = new SVG.Matrix()
var converged = this._run(declarative ? dt : position)
// this.fire('step', this)
@@ -302,7 +306,7 @@ SVG.Runner = SVG.invent({
// declaritive animations itself know when they converged
this.done = this.done || (converged && declarative)
if (this.done) {
- // this.fire('finish', this)
+ this.fire('finish', this)
}
return this
},
@@ -445,19 +449,15 @@ SVG.Runner = SVG.invent({
return allfinished
},
- addTransform: function (transform) {
+ addTransform: function (transform, index) {
+ // this.transforms[index] = transform
this.transforms = this.transforms.lmultiply(transform)
return this
},
- addTarget: function (target) {
- this.targets = this.targets.lmultiply(target)
- return this
- },
-
clearTransform: function () {
+ // this.transforms = [new SVG.Matrix()]
this.transforms = new SVG.Matrix()
- this.targets = new SVG.Matrix()
return this
}
},
@@ -495,13 +495,37 @@ SVG.Runner.sanitise = function (duration, delay, when) {
}
}
+
+SVG.FakeRunner = class {
+ constructor (transforms, id = -1, done = true) {
+ // Object.assign(this, {transforms, id, done})
+
+ this.transforms = transforms
+ this.id = id
+ this.done = done
+ }
+}
+
+SVG.extend([SVG.Runner, SVG.FakeRunner], {
+ mergeWith (runner) {
+ return new SVG.FakeRunner(
+ runner.transforms.lmultiply(this.transforms),
+ runner.id
+ )
+ }
+})
+
+
+const lmultiply = (last, curr) => last.lmultiply(curr)
+const getRunnerTransform = (runner) => runner.transforms
+
function mergeTransforms () {
// Find the matrix to apply to the element and apply it
let runners = this._transformationRunners
let netTransform = runners
- .map(runner => runner.transforms)
- .reduce((last, curr) => last.lmultiply(curr))
+ .map(getRunnerTransform)
+ .reduce(lmultiply)
this.transform(netTransform)
@@ -510,27 +534,37 @@ function mergeTransforms () {
runners.forEach((runner, i) => {
if (lastRunner && runner.done && lastRunner.done) {
delete runners[runner.id+1]
- runners[lastRunner.id+1] = {
- transforms: runner.transforms.multiply(lastRunner.transforms),
- done: true,
- id: lastRunner.id,
- }
+ runners[lastRunner.id+1] = runner.mergeWith(lastRunner)
}
lastRunner = runner
})
+ // when the last runner is at index 0 it means all animations are done
+ // that is because the first index always holds a FakeRunner and never an
+ // actual Runner
if (lastRunner == runners[0]) {
this._frameId = null
}
}
+
SVG.extend(SVG.Element, {
+
+ // this function searches for all runners on the element and deletes the ones
+ // which run before the current one. This is because absolute transformations
+ // overwfrite anything anyway so there is no need to waste time computing
+ // other runners
_clearTransformRunnersBefore: function (currentRunner) {
this._transformationRunners.forEach((runner, i, arr) => {
+
+ // only delete runners which run before the current
if (runner.id < currentRunner.id) {
+ // if the runner is still running, it will add itself back on every
+ // frame. So make sure to delete the transformations from this runner
+ // so it doesnt interfer anymore
if (!runner.done) {
runner._queue = runner._queue.filter((item) => {
return !item.isTransform
@@ -544,16 +578,12 @@ SVG.extend(SVG.Element, {
_currentTransform (current) {
return this._transformationRunners
+ // we need the equal sign here to make sure, that also transformations
+ // on the same runner which execute before the current transformation are
+ // taken into account
.filter((runner) => runner.id <= current.id)
- .map(runner => runner.transforms)
- .reduce((last, curr) => last.lmultiply(curr))
- },
-
- _targetTransform (current) {
- return this._transformationRunners
- .filter((runner) => runner.id <= current.id)
- .map(runner => runner.targets)
- .reduce((last, curr) => last.lmultiply(curr))
+ .map(getRunnerTransform)
+ .reduce(lmultiply)
},
addRunner: function (runner) {
@@ -566,12 +596,10 @@ SVG.extend(SVG.Element, {
_prepareRunner: function () {
if (this._frameId == null) {
- this._transformationRunners = [{
- transforms: new SVG.Matrix(this),
- targets: new SVG.Matrix(this),
- done: true,
- id: -1
- }]
+ this._transformationRunners = [
+ new SVG.FakeRunner(new SVG.Matrix(this))
+ ]
+
this._frameId = SVG.Element.frameId++
}
},
@@ -662,42 +690,41 @@ SVG.extend(SVG.Runner, {
let element
let current
let currentAngle
- var u = 0
- let firstRun = true
+ let u = this.transformId++
function setup () {
// make sure element and origin is defined
element = element || this.element()
-
- // TODO: Give me all matricies concatenated, up until this matrix,
- // for example, if I have M = E D C B A
- // If I'm about to run D, I want transform space to be
- // C * B * A
- // Where C B and A are the current morpher targets
- // The solution I've added here won't work if we interrupt an animation
- // mid-animation (try turning on the second animation in dirty)
-
- let transformSpace = relative
- ? element._targetTransform(this)
- : undefined
- origin = origin || getOrigin(transforms, element, transformSpace)
+ origin = origin || getOrigin(transforms, element)
// add the runner to the element so it can merge transformations
element.addRunner(this)
// Deactivate all transforms that have run so far if we are absolute
- let absolute = !relative
- if ( absolute ) {
+ if ( !relative ) {
element._clearTransformRunnersBefore(this)
}
+ }
+
+ function run (pos) {
+
+ // clear all other transforms before this in case something is saved
+ // on this runner. We are absolute. We dont need these!
+ if (!relative) this.clearTransform()
+
+ let {x, y} = new SVG.Point(origin).transform(element._currentTransform(this))
- let target = new SVG.Matrix({...transforms, origin})
- let start = current || new SVG.Matrix(relative ? undefined : element)
+ let target = new SVG.Matrix({...transforms, origin: [x, y]})
+ let start = new SVG.Matrix(relative ? undefined : element)
+
+ if (this._isDeclarative && current) {
+ start = current
+ }
if (affine) {
- target = target.decompose(origin[0], origin[1])
- start = start.decompose(origin[0], origin[1])
+ target = target.decompose(x, y)
+ start = start.decompose(x, y)
// Get the current and target angle as it was set
const rTarget = target.rotate
@@ -712,43 +739,25 @@ SVG.extend(SVG.Runner, {
}
if (relative) {
- target.rotate = transforms.rotate || 0
- start.rotate = currentAngle || start.rotate
- }
-
- if (firstRun) {
- this.addTarget(target)
- firstRun = false
+ // we have to be careful here not to overwrite the rotation
+ // with the rotate method of SVG.Matrix
+ if (!isMatrix) {
+ target.rotate = transforms.rotate || 0
+ }
+ if (this._isDeclarative && currentAngle) {
+ start.rotate = currentAngle
+ }
}
morpher.from(start)
morpher.to(target)
- }
-
- function run (pos) {
-
- // clear all other transforms before this in case something is saved
- // on this runner. We are absolute. We dont need these!
- if (!relative) this.clearTransform()
-
- // let {x, y} = new SVG.Point(origin).transform(element._currentTransform(this))
- // morpher._from.splice(-2, 2, x, y)
- // morpher._to.splice(-2, 2, x, y)
-
- // fix the origin so is in the right space
- // if (affine) {
- // let currentMatrix = element._currentTransform(this)
- // let {x, y} = new SVG.Point(origin).transform(currentMatrix)
- // morpher._from.splice(-2, 2, x, y)
- // morpher._to.splice(-2, 2, x, y)
- // }
let affineParameters = morpher.at(pos)
currentAngle = affineParameters.rotate
current = new SVG.Matrix(affineParameters)
- this.addTransform(current)
+ this.addTransform(current, u)
return morpher.done()
}