aboutsummaryrefslogtreecommitdiffstats
path: root/src/animation
diff options
context:
space:
mode:
authorUlrich-Matthias Schäfer <ulima.ums@googlemail.com>2020-05-03 12:32:34 +1000
committerUlrich-Matthias Schäfer <ulima.ums@googlemail.com>2020-05-03 12:32:34 +1000
commit59f09a1a2317e57d13bbe8f60e1949cc82199ead (patch)
tree6c76c27325af4440146be65731fbc69ec398ddf0 /src/animation
parent897bbfa075055097d64d42d7a32952bec9c75665 (diff)
downloadsvg.js-59f09a1a2317e57d13bbe8f60e1949cc82199ead.tar.gz
svg.js-59f09a1a2317e57d13bbe8f60e1949cc82199ead.zip
99% line coverage - BAAAAM
Diffstat (limited to 'src/animation')
-rw-r--r--src/animation/Morphable.js88
-rw-r--r--src/animation/Runner.js83
2 files changed, 122 insertions, 49 deletions
diff --git a/src/animation/Morphable.js b/src/animation/Morphable.js
index 0a28e8e..2d48e10 100644
--- a/src/animation/Morphable.js
+++ b/src/animation/Morphable.js
@@ -10,6 +10,34 @@ import PathArray from '../types/PathArray.js'
import SVGArray from '../types/SVGArray.js'
import SVGNumber from '../types/SVGNumber.js'
+const getClassForType = (value) => {
+ const type = typeof value
+
+ if (type === 'number') {
+ return SVGNumber
+ } else if (type === 'string') {
+ if (Color.isColor(value)) {
+ return Color
+ } else if (delimiter.test(value)) {
+ return pathLetters.test(value)
+ ? PathArray
+ : SVGArray
+ } else if (numberAndUnit.test(value)) {
+ return SVGNumber
+ } else {
+ return NonMorphable
+ }
+ } else if (morphableTypes.indexOf(value.constructor) > -1) {
+ return value.constructor
+ } else if (Array.isArray(value)) {
+ return SVGArray
+ } else if (type === 'object') {
+ return ObjectBag
+ } else {
+ return NonMorphable
+ }
+}
+
export default class Morphable {
constructor (stepper) {
this._stepper = stepper || new Ease('-')
@@ -52,32 +80,7 @@ export default class Morphable {
_set (value) {
if (!this._type) {
- var type = typeof value
-
- if (type === 'number') {
- this.type(SVGNumber)
- } else if (type === 'string') {
- if (Color.isColor(value)) {
- this.type(Color)
- } else if (delimiter.test(value)) {
- this.type(pathLetters.test(value)
- ? PathArray
- : SVGArray
- )
- } else if (numberAndUnit.test(value)) {
- this.type(SVGNumber)
- } else {
- this.type(NonMorphable)
- }
- } else if (morphableTypes.indexOf(value.constructor) > -1) {
- this.type(value.constructor)
- } else if (Array.isArray(value)) {
- this.type(SVGArray)
- } else if (type === 'object') {
- this.type(ObjectBag)
- } else {
- this.type(NonMorphable)
- }
+ this.type(getClassForType(value))
}
var result = (new this._type(value))
@@ -86,6 +89,13 @@ export default class Morphable {
: this._from ? result[this._from[4]]()
: result
}
+
+ if (this._type === ObjectBag) {
+ result = this._to ? result.align(this._to)
+ : this._from ? result.align(this._from)
+ : result
+ }
+
result = result.toArray()
this._morphObj = this._morphObj || new this._type()
@@ -208,7 +218,7 @@ export class ObjectBag {
this.values = []
if (Array.isArray(objOrArr)) {
- this.values = objOrArr
+ this.values = objOrArr.slice()
return
}
@@ -216,7 +226,9 @@ export class ObjectBag {
var entries = []
for (const i in objOrArr) {
- entries.push([ i, objOrArr[i] ])
+ const Type = getClassForType(objOrArr[i])
+ const val = new Type(objOrArr[i]).toArray()
+ entries.push([ i, Type, val.length, ...val ])
}
entries.sort(sortByKey)
@@ -229,8 +241,13 @@ export class ObjectBag {
var obj = {}
var arr = this.values
- for (var i = 0, len = arr.length; i < len; i += 2) {
- obj[arr[i]] = arr[i + 1]
+ // for (var i = 0, len = arr.length; i < len; i += 2) {
+ while (arr.length) {
+ const key = arr.shift()
+ const Type = arr.shift()
+ const num = arr.shift()
+ const values = arr.splice(0, num)
+ obj[key] = new Type(values).valueOf()
}
return obj
@@ -239,6 +256,17 @@ export class ObjectBag {
toArray () {
return this.values
}
+
+ align (other) {
+ for (let i = 0, il = this.values.length; i < il; ++i) {
+ if (this.values[i] === Color) {
+ const space = other[i + 6]
+ const color = new Color(this.values.splice(i + 2, 5))[space]().toArray()
+ this.values.splice(i + 2, 0, ...color)
+ }
+ }
+ return this
+ }
}
const morphableTypes = [
diff --git a/src/animation/Runner.js b/src/animation/Runner.js
index 8c56423..e2ba380 100644
--- a/src/animation/Runner.js
+++ b/src/animation/Runner.js
@@ -13,6 +13,7 @@ import Morphable, { TransformBag } from './Morphable.js'
import Point from '../types/Point.js'
import SVGNumber from '../types/SVGNumber.js'
import Timeline from './Timeline.js'
+import { ObjectBag } from '../main.js'
export default class Runner extends EventTarget {
constructor (options) {
@@ -381,7 +382,7 @@ export default class Runner extends EventTarget {
// for the case of transformations, we use the special retarget function
// which has access to the outer scope
if (this._history[method].caller.retarget) {
- this._history[method].caller.retarget(target, extra)
+ this._history[method].caller.retarget.call(this, target, extra)
// for everything else a simple morpher change is sufficient
} else {
this._history[method].morpher.to(target)
@@ -487,7 +488,7 @@ export default class Runner extends EventTarget {
Runner.id = 0
-class FakeRunner {
+export class FakeRunner {
constructor (transforms = new Matrix(), id = -1, done = true) {
this.transforms = transforms
this.id = id
@@ -527,7 +528,7 @@ function mergeTransforms () {
}
}
-class RunnerArray {
+export class RunnerArray {
constructor () {
this.runners = []
this.ids = []
@@ -556,7 +557,8 @@ class RunnerArray {
merge () {
let lastRunner = null
- this.runners.forEach((runner, i) => {
+ for (let i = 0; i < this.runners.length; ++i) {
+ const runner = this.runners[i]
const condition = lastRunner
&& runner.done && lastRunner.done
@@ -567,11 +569,14 @@ class RunnerArray {
if (condition) {
// the +1 happens in the function
this.remove(runner.id)
- this.edit(lastRunner.id, runner.mergeWith(lastRunner))
+ const newRunner = runner.mergeWith(lastRunner)
+ this.edit(lastRunner.id, newRunner)
+ lastRunner = newRunner
+ --i
+ } else {
+ lastRunner = runner
}
-
- lastRunner = runner
- })
+ }
return this
}
@@ -649,6 +654,14 @@ registerMethods({
}
})
+const intersect = (a, b) => {
+ var setB = new Set(b)
+ return [ ...new Set(a) ].filter(x => setB.has(x))
+}
+
+// Will output the elements from array A that are not in the array B
+const difference = (a, b) => a.filter(x => !b.includes(x))
+
extend(Runner, {
attr (a, v) {
return this.styleAttr('attr', a, v)
@@ -659,24 +672,56 @@ extend(Runner, {
return this.styleAttr('css', s, v)
},
- styleAttr (type, name, val) {
- // apply attributes individually
- if (typeof name === 'object') {
- for (var key in name) {
- this.styleAttr(type, key, name[key])
- }
- return this
+ styleAttr (type, nameOrAttrs, val) {
+ if (typeof nameOrAttrs === 'string') {
+ return this.styleAttr(type, { [nameOrAttrs]: val })
}
- var morpher = new Morphable(this._stepper).to(val)
+ let attrs = nameOrAttrs
+ if (this._tryRetarget(type, attrs)) return this
+
+ var morpher = new Morphable(this._stepper).to(attrs)
+ let keys = Object.keys(attrs)
this.queue(function () {
- morpher = morpher.from(this.element()[type](name))
+ morpher = morpher.from(this.element()[type](keys))
}, function (pos) {
- this.element()[type](name, morpher.at(pos))
+ this.element()[type](morpher.at(pos).valueOf())
return morpher.done()
+ }, function (newToAttrs) {
+
+ // Check if any new keys were added
+ const newKeys = Object.keys(newToAttrs)
+ const differences = difference(newKeys, keys)
+
+ // If their are new keys, initialize them and add them to morpher
+ if (differences.length) {
+ // Get the values
+ const addedFromAttrs = this.element()[type](differences)
+
+ // Get the already initialized values
+ const oldFromAttrs = new ObjectBag(morpher.from()).valueOf()
+
+ // Merge old and new
+ Object.assign(oldFromAttrs, addedFromAttrs)
+ morpher.from(oldFromAttrs)
+ }
+
+ // Get the object from the morpher
+ const oldToAttrs = new ObjectBag(morpher.to()).valueOf()
+
+ // Merge in new attributes
+ Object.assign(oldToAttrs, newToAttrs)
+
+ // Change morpher target
+ morpher.to(oldToAttrs)
+
+ // Make sure that we save the work we did so we don't need it to do again
+ keys = newKeys
+ attrs = newToAttrs
})
+ this._rememberMorpher(type, morpher)
return this
},
@@ -812,7 +857,7 @@ extend(Runner, {
(newTransforms.origin || 'center').toString()
!== (transforms.origin || 'center').toString()
) {
- origin = getOrigin(transforms, element)
+ origin = getOrigin(newTransforms, element)
}
// overwrite the old transformations with the new ones