diff options
author | Ulrich-Matthias Schäfer <ulima.ums@googlemail.com> | 2020-05-03 12:32:34 +1000 |
---|---|---|
committer | Ulrich-Matthias Schäfer <ulima.ums@googlemail.com> | 2020-05-03 12:32:34 +1000 |
commit | 59f09a1a2317e57d13bbe8f60e1949cc82199ead (patch) | |
tree | 6c76c27325af4440146be65731fbc69ec398ddf0 /src/animation | |
parent | 897bbfa075055097d64d42d7a32952bec9c75665 (diff) | |
download | svg.js-59f09a1a2317e57d13bbe8f60e1949cc82199ead.tar.gz svg.js-59f09a1a2317e57d13bbe8f60e1949cc82199ead.zip |
99% line coverage - BAAAAM
Diffstat (limited to 'src/animation')
-rw-r--r-- | src/animation/Morphable.js | 88 | ||||
-rw-r--r-- | src/animation/Runner.js | 83 |
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 |