diff options
author | Ulrich-Matthias Schäfer <ulima.ums@googlemail.com> | 2018-10-17 23:09:34 +0200 |
---|---|---|
committer | Ulrich-Matthias Schäfer <ulima.ums@googlemail.com> | 2018-10-17 23:09:34 +0200 |
commit | 417d4b253d2daea0ef3c437c5b3d5eda6ccc7525 (patch) | |
tree | 1b5e6528df2cd679af07e4ffc44c177ed35dac68 /src | |
parent | 8db39b099ea85d881f5e4d12b2b2182d41414da4 (diff) | |
download | svg.js-417d4b253d2daea0ef3c437c5b3d5eda6ccc7525.tar.gz svg.js-417d4b253d2daea0ef3c437c5b3d5eda6ccc7525.zip |
add babel, satisfy linter, build dist
Diffstat (limited to 'src')
-rw-r--r-- | src/controller.js | 67 | ||||
-rw-r--r-- | src/helpers.js | 16 | ||||
-rw-r--r-- | src/matrix.js | 11 | ||||
-rw-r--r-- | src/morph.js | 180 | ||||
-rw-r--r-- | src/runner.js | 270 | ||||
-rw-r--r-- | src/svg.js | 2 | ||||
-rw-r--r-- | src/timeline.js | 91 | ||||
-rw-r--r-- | src/transform.js | 2 |
8 files changed, 237 insertions, 402 deletions
diff --git a/src/controller.js b/src/controller.js index 46c1771..842c772 100644 --- a/src/controller.js +++ b/src/controller.js @@ -18,8 +18,8 @@ function makeSetterGetter (k, f) { } } -SVG.Stepper = SVG.invent ({ - create: function () {}, +SVG.Stepper = SVG.invent({ + create: function () {} }) /*** @@ -27,8 +27,7 @@ Easing Functions ================ ***/ -SVG.Ease = SVG.invent ({ - +SVG.Ease = SVG.invent({ inherit: SVG.Stepper, create: function (fn) { @@ -40,7 +39,7 @@ SVG.Ease = SVG.invent ({ extend: { step: function (from, to, pos) { - if(typeof from !== 'number') { + if (typeof from !== 'number') { return pos < 1 ? from : to } return from + (to - from) * this.ease(pos) @@ -48,8 +47,8 @@ SVG.Ease = SVG.invent ({ done: function (dt, c) { return false - }, - }, + } + } }) SVG.easing = { @@ -61,17 +60,15 @@ SVG.easing = { return function (t) { // TODO: FINISH } - }, + } } - /*** Controller Types ================ ***/ -SVG.Controller = SVG.invent ({ - +SVG.Controller = SVG.invent({ inherit: SVG.Stepper, create: function (fn) { @@ -87,12 +84,11 @@ SVG.Controller = SVG.invent ({ done: function (c) { return c.done - }, - }, + } + } }) function recalculate () { - // Apply the default parameters var duration = (this._duration || 500) / 1000 var overshoot = this._overshoot || 0 @@ -101,15 +97,15 @@ function recalculate () { var eps = 1e-10 var pi = Math.PI var os = Math.log(overshoot / 100 + eps) - var zeta = - os / Math.sqrt(pi * pi + os * os) - var wn = 3.9 / ( zeta * duration ) + var zeta = -os / Math.sqrt(pi * pi + os * os) + var wn = 3.9 / (zeta * duration) // Calculate the Spring values this.d = 2 * zeta * wn this.k = wn * wn } -SVG.Spring = SVG.invent ({ +SVG.Spring = SVG.invent({ inherit: SVG.Controller, create: function (duration, overshoot) { @@ -119,11 +115,10 @@ SVG.Spring = SVG.invent ({ extend: { step: function (current, target, dt, c) { - - if (typeof current == 'string') return current - c.done = dt == Infinity - if(dt == Infinity) return target - if(dt == 0) return current + if (typeof current === 'string') return current + c.done = dt === Infinity + if (dt === Infinity) return target + if (dt === 0) return current if (dt > 100) dt = 16 @@ -133,10 +128,10 @@ SVG.Spring = SVG.invent ({ var velocity = c.velocity || 0 // Apply the control to get the new position and store it - var acceleration = - this.d * velocity - this.k * (current - target) - var newPosition = current - + velocity * dt - + acceleration * dt * dt / 2 + var acceleration = -this.d * velocity - this.k * (current - target) + var newPosition = current + + velocity * dt + + acceleration * dt * dt / 2 // Store the velocity c.velocity = velocity + acceleration * dt @@ -147,16 +142,14 @@ SVG.Spring = SVG.invent ({ }, duration: makeSetterGetter('_duration', recalculate), - overshoot: makeSetterGetter('_overshoot', recalculate), + overshoot: makeSetterGetter('_overshoot', recalculate) } }) -SVG.PID = SVG.invent ({ +SVG.PID = SVG.invent({ inherit: SVG.Controller, create: function (p, i, d, windup) { - if(!(this instanceof SVG.PID)) - return new SVG.PID(p, i, d, windup) SVG.Controller.call(this) p = p == null ? 0.1 : p @@ -168,12 +161,11 @@ SVG.PID = SVG.invent ({ extend: { step: function (current, target, dt, c) { + if (typeof current === 'string') return current + c.done = dt === Infinity - if (typeof current == 'string') return current - c.done = dt == Infinity - - if(dt == Infinity) return target - if(dt == 0) return current + if (dt === Infinity) return target + if (dt === 0) return current var p = target - current var i = (c.integral || 0) + p * dt @@ -181,8 +173,9 @@ SVG.PID = SVG.invent ({ var windup = this.windup // antiwindup - if(windup !== false) + if (windup !== false) { i = Math.max(-windup, Math.min(i, windup)) + } c.error = p c.integral = i @@ -195,6 +188,6 @@ SVG.PID = SVG.invent ({ windup: makeSetterGetter('windup'), p: makeSetterGetter('P'), i: makeSetterGetter('I'), - d: makeSetterGetter('D'), + d: makeSetterGetter('D') } }) diff --git a/src/helpers.js b/src/helpers.js index fc22e4c..c2073cf 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -254,12 +254,10 @@ function formatTransforms (o) { // Populate all of the values return { - scaleX, scaleY, skewX, skewY, shear, theta, - rx, ry, tx, ty, ox, oy, px, py + scaleX, scaleY, skewX, skewY, shear, theta, rx, ry, tx, ty, ox, oy, px, py } } - // left matrix, right matrix, target matrix which is overwritten function matrixMultiply (l, r, o) { // Work out the product directly @@ -281,15 +279,13 @@ function matrixMultiply (l, r, o) { return o } - -function getOrigin (o, element, inSpace) { +function getOrigin (o, element) { // Allow origin or around as the names 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 if (typeof origin === 'string' || origin == null) { - // Get the bounding box of the element with no transformations applied const string = (origin || 'center').toLowerCase().trim() const { height, width, x, y } = element.bbox() @@ -305,19 +301,11 @@ function getOrigin (o, element, inSpace) { // Set the bounds eg : "bottom-left", "Top right", "middle" etc... ox = o.ox != null ? o.ox : bx oy = o.oy != null ? o.oy : by - } else { ox = origin[0] oy = origin[1] } - // Transform the origin into the current reference frame - if ( inSpace ) { - let originRelative = new SVG.Point( ox, oy ).transform(inSpace) - ox = originRelative.x - oy = originRelative.y - } - // Return the origin as it is if it wasn't a string return [ ox, oy ] } diff --git a/src/matrix.js b/src/matrix.js index 49015a3..666b898 100644 --- a/src/matrix.js +++ b/src/matrix.js @@ -1,4 +1,4 @@ -/* global abcdef, arrayToMatrix, closeEnough, formatTransforms */ +/* global abcdef arrayToMatrix closeEnough formatTransforms isMatrixLike matrixMultiply */ SVG.Matrix = SVG.invent({ // Initialize @@ -41,7 +41,7 @@ SVG.Matrix = SVG.invent({ // Get the proposed transformations and the current transformations var t = formatTransforms(o) - var current = this//new SVG.Matrix(this) // FIXME: do we need a new matrix here? + var current = this let { x: ox, y: oy } = new SVG.Point(t.ox, t.oy).transform(current) // Construct the resulting matrix @@ -260,7 +260,7 @@ SVG.Matrix = SVG.invent({ scaleO: function (x, y = x, cx = 0, cy = 0) { // Support uniform scaling - if (arguments.length == 3) { + if (arguments.length === 3) { cy = cx cx = y y = x @@ -335,7 +335,7 @@ SVG.Matrix = SVG.invent({ skewO: function (x, y = x, cx = 0, cy = 0) { // support uniformal skew - if (arguments.length == 3) { + if (arguments.length === 3) { cy = cx cx = y y = x @@ -467,9 +467,6 @@ SVG.Matrix = SVG.invent({ // // SVG.extend(SVG.Matrix, extensions) - - - // function matrixMultiplyParams (matrix, a, b, c, d, e, f) { // return matrixMultiply({a, b, c, d, e, f}, matrix, matrix) // } diff --git a/src/morph.js b/src/morph.js index bf94efc..acb9e21 100644 --- a/src/morph.js +++ b/src/morph.js @@ -14,16 +14,18 @@ SVG.Morphable = SVG.invent({ extend: { from: function (val) { - if(val == null) + if (val == null) { return this._from + } this._from = this._set(val) return this }, to: function (val) { - if(val == null) + if (val == null) { return this._to + } this._to = this._set(val) return this @@ -31,8 +33,9 @@ SVG.Morphable = SVG.invent({ type: function (type) { // getter - if (type == null) + if (type == null) { return this._type + } // setter this._type = type @@ -40,40 +43,30 @@ SVG.Morphable = SVG.invent({ }, _set: function (value) { - - if(!this._type) { + if (!this._type) { var type = typeof value if (type === 'number') { this.type(SVG.Number) - } else if (type === 'string') { - if (SVG.Color.isColor(value)) { this.type(SVG.Color) - } else if (SVG.regex.delimiter.test(value)) { this.type(SVG.regex.pathLetters.test(value) ? SVG.PathArray : SVG.Array ) - } else if (SVG.regex.numberAndUnit.test(value)) { this.type(SVG.Number) - } else { this.type(SVG.Morphable.NonMorphable) } - } else if (SVG.MorphableTypes.indexOf(value.constructor) > -1) { this.type(value.constructor) - } else if (Array.isArray(value)) { this.type(SVG.Array) - } else if (type === 'object') { this.type(SVG.Morphable.ObjectBag) - } else { this.type(SVG.Morphable.NonMorphable) } @@ -81,13 +74,13 @@ SVG.Morphable = SVG.invent({ var result = (new this._type(value)).toArray() this._morphObj = this._morphObj || new this._type() - this._context = this._context - || Array.apply(null, Array(result.length)).map(Object) + this._context = this._context || + Array.apply(null, Array(result.length)).map(Object) return result }, stepper: function (stepper) { - if(stepper == null) return this._stepper + if (stepper == null) return this._stepper this._stepper = stepper return this }, @@ -132,7 +125,7 @@ SVG.Morphable.NonMorphable = SVG.invent({ SVG.Morphable.TransformBag = SVG.invent({ create: function (obj) { - if(Array.isArray(obj)) { + if (Array.isArray(obj)) { obj = { scaleX: obj[0], scaleY: obj[1], @@ -149,7 +142,7 @@ SVG.Morphable.TransformBag = SVG.invent({ }, extend: { - toArray: function (){ + toArray: function () { var v = this return [ @@ -160,7 +153,7 @@ SVG.Morphable.TransformBag = SVG.invent({ v.translateX, v.translateY, v.originX, - v.originY, + v.originY ] } } @@ -177,64 +170,11 @@ SVG.Morphable.TransformBag.defaults = { originY: 0 } -// SVG.Morphable.TransformBag = SVG.invent({ -// inherit: SVG.Matrix, -// create: function (obj) { -// if(Array.isArray(obj)) { -// obj = { -// scaleX: obj[0], -// scaleY: obj[1], -// shear: obj[2], -// rotate: obj[3], -// translateX: obj[4], -// translateY: obj[5], -// originX: obj[6], -// originY: obj[7] -// } -// } -// -// var data = {...(obj || {})} -// -// if (typeof data.origin == 'string') { -// delete data.origin -// } -// -// SVG.Matrix.call(this, data) -// -// -// if (data.origin) { -// data.originX = data.origin[0] -// data.originY = data.origin[1] -// } -// -// this.originX = data.originX || 0 -// this.originY = data.originY || 0 -// }, -// -// extend: { -// toArray: function (){ -// var v = this.decompose(this.originX, this.originY) -// -// return [ -// v.scaleX, -// v.scaleY, -// v.shear, -// v.rotate, -// v.translateX, -// v.translateY, -// v.originX, -// v.originY, -// ] -// } -// } -// }) - - SVG.Morphable.ObjectBag = SVG.invent({ create: function (objOrArr) { this.values = [] - if(Array.isArray(objOrArr)) { + if (Array.isArray(objOrArr)) { this.values = objOrArr return } @@ -251,14 +191,14 @@ SVG.Morphable.ObjectBag = SVG.invent({ 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) { + obj[arr[i]] = arr[i + 1] } return obj }, - toArray: function (){ + toArray: function () { return this.values } } @@ -274,7 +214,7 @@ SVG.MorphableTypes = [ SVG.PathArray, SVG.Morphable.NonMorphable, SVG.Morphable.TransformBag, - SVG.Morphable.ObjectBag, + SVG.Morphable.ObjectBag ] SVG.extend(SVG.MorphableTypes, { @@ -285,89 +225,7 @@ SVG.extend(SVG.MorphableTypes, { .to(val, args) }, fromArray: function (arr) { - this.constructor.call(this, arr) + this.constructor(arr) return this } }) - - - - -// - Objects are just variable bags -// - morph rerutrns a morphable. No state on normal objects (like SVG.Color) -// - Objects can be represented as Array (with toArray()) -// - Objects have an unmorph/fromarray function which converts it back to a normal object - -// var b = new Color('#fff') -// b.morph('#000') === new Morph(b).to('#000') - -// sweet = Color('#fff') -// dark = Color('#fef') -// sweet.to(dark, 'hsl') - -// angle = Number(30) -// lastAngle = Number(300) -// angle.to(lastAngle, cyclic) - -// mat1 = Matrix().transform({rotation: 30, scale: 0}) -// mat2 = Matrix(30, 40, 50, 60, 10, 20) -// mat1.to(mat2) - - - - -/** - -el.loop({times: 5, swing: true, wait: [20, 50]}) - -el.opacity(0) - .animate(300).opacity(1) - .animate(300, true).scale(5).reverse() - - -for(var i = 0; i < 7; ++i) - circle.clone() - .scale(3).rotate(0) - .loop({swing: false, wait: 500}) - .scale(1) - .rotate(360) - .delay(1000) - .animate(500, 'swingOut') - .scale(3) -} - -fn () => { - el.animate().stroke('dashoffset', 213).scale(1) - .delay(1) - .animate().scale(2) - .after(fn) -} - -When you start an element has a base matrix B - which starts as the identity - - If you modify the matrix, then we have: - - T U V W X B x - . . . - - runner.step() - - for all runners in stack: - if(runner is done) repalce with matrix - - if(2 matrix next to eachother are done) { - - } - -What if - -/// RunnerA -el.animate() - .transform({rotate: 30, scale: 2}) - .transform({rotate: 500}, true) - -f| -----A----- -s| --------B--------- -t| ---------C------- - -**/ diff --git a/src/runner.js b/src/runner.js index 788563c..41280a0 100644 --- a/src/runner.js +++ b/src/runner.js @@ -1,3 +1,4 @@ +/* global isMatrixLike getOrigin */ SVG.easing = { '-': function (pos) { return pos }, @@ -7,13 +8,10 @@ SVG.easing = { } SVG.Runner = SVG.invent({ - - inherit: SVG.EventTarget, parent: SVG.Element, create: function (options) { - - // Store a unique id on the runner, so that we can identify it + // Store a unique id on the runner, so that we can identify it later this.id = SVG.Runner.id++ // Ensure a default value @@ -27,7 +25,6 @@ SVG.Runner = SVG.invent({ : options // Declare all of the variables - this._dispatcher = document.createElement('div') this._element = null this._timeline = null this.done = false @@ -74,7 +71,7 @@ SVG.Runner = SVG.invent({ delay: function (by, when) { return this.animate(0, by, when) - }, + } }, extend: { @@ -87,7 +84,7 @@ SVG.Runner = SVG.invent({ */ element: function (element) { - if(element == null) return this._element + if (element == null) return this._element this._element = element element._prepareRunner() return this @@ -95,29 +92,29 @@ SVG.Runner = SVG.invent({ timeline: function (timeline) { // check explicitly for undefined so we can set the timeline to null - if(typeof timeline === 'undefined') return this._timeline + if (typeof timeline === 'undefined') return this._timeline this._timeline = timeline return this }, - animate: function(duration, delay, when) { + animate: function (duration, delay, when) { var o = SVG.Runner.sanitise(duration, delay, when) var runner = new SVG.Runner(o.duration) - if(this._timeline) runner.timeline(this._timeline) - if(this._element) runner.element(this._element) + if (this._timeline) runner.timeline(this._timeline) + if (this._element) runner.element(this._element) return runner.loop(o).schedule(delay, when) }, schedule: function (timeline, delay, when) { // The user doesn't need to pass a timeline if we already have one - if(!(timeline instanceof SVG.Timeline)) { + if (!(timeline instanceof SVG.Timeline)) { when = delay delay = timeline timeline = this.timeline() } // If there is no timeline, yell at the user... - if(!timeline) { + if (!timeline) { throw Error('Runner cannot be scheduled without timeline') } @@ -163,7 +160,7 @@ SVG.Runner = SVG.invent({ runner: runFn || SVG.void, isTransform: isTransform, initialised: false, - finished: false, + finished: false }) var timeline = this.timeline() timeline && this.timeline()._continue() @@ -212,7 +209,6 @@ SVG.Runner = SVG.invent({ }, position: function (p) { - // Get all of the variables we need var x = this._time var d = this._duration @@ -220,9 +216,9 @@ SVG.Runner = SVG.invent({ var t = this._times var s = this._swing var r = this._reverse + var position if (p == null) { - /* This function converts a time to a position in the range [0, 1] The full explanation can be found in this desmos demonstration @@ -231,7 +227,7 @@ SVG.Runner = SVG.invent({ */ // Figure out the value without thinking about the start or end time - function f (x) { + const f = function (x) { var swinging = s * Math.floor(x % (2 * (w + d)) / (w + d)) var backwards = (swinging && !r) || (!swinging && r) var uncliped = Math.pow(-1, backwards) * (x % (w + d)) / d + backwards @@ -241,7 +237,7 @@ SVG.Runner = SVG.invent({ // Figure out the value by incorporating the start time var endTime = t * (w + d) - w - var position = x <= 0 ? Math.round(f(1e-5)) + position = x <= 0 ? Math.round(f(1e-5)) : x < endTime ? f(x) : Math.round(f(endTime - 1e-5)) return position @@ -249,9 +245,9 @@ SVG.Runner = SVG.invent({ // Work out the loops done and add the position to the loops done var loopsDone = Math.floor(this.loops()) - var swingForward = s && (loopsDone % 2 == 0) + var swingForward = s && (loopsDone % 2 === 0) var forwards = (swingForward && !r) || (r && swingForward) - var position = loopsDone + (forwards ? p : 1 - p) + position = loopsDone + (forwards ? p : 1 - p) return this.loops(position) }, @@ -263,7 +259,6 @@ SVG.Runner = SVG.invent({ }, step: function (dt) { - // If we are inactive, this stepper just gets skipped if (!this.enabled) return this @@ -292,7 +287,7 @@ SVG.Runner = SVG.invent({ this.done = !declarative && !justFinished && this._time >= duration // Call initialise and the run function - if ( running || declarative ) { + if (running || declarative) { this._initialise(running) // clear the transforms on this runner so they dont get added again and again @@ -324,7 +319,7 @@ SVG.Runner = SVG.invent({ }, active: function (enabled) { - if(enabled == null) return this.enabled + if (enabled == null) return this.enabled this.enabled = enabled return this }, @@ -341,7 +336,7 @@ SVG.Runner = SVG.invent({ // Add all of the tags to the object directly name = Array.isArray(name) ? name : [name] - for(var i = name.length; i--;) { + for (var i = name.length; i--;) { this.tags[name[i]] = true } return this @@ -349,7 +344,7 @@ SVG.Runner = SVG.invent({ untag: function (name) { name = Array.isArray(name) ? name : [name] - for(var i = name.length; i--;) { + for (var i = name.length; i--;) { delete this.tags[name[i]] } return this @@ -369,15 +364,14 @@ SVG.Runner = SVG.invent({ _rememberMorpher: function (method, morpher) { this._history[method] = { morpher: morpher, - caller: this._queue[this._queue.length - 1], + caller: this._queue[this._queue.length - 1] } }, // Try to set the target for a morpher if the morpher exists, otherwise // do nothing and return false _tryRetarget: function (method, target) { - if(this._history[method]) { - + if (this._history[method]) { // if the last method wasnt even initialised, throw it away if (!this._history[method].caller.initialised) { let index = this._queue.indexOf(this._history[method].caller) @@ -389,7 +383,6 @@ SVG.Runner = SVG.invent({ // which has access to the outer scope if (this._history[method].caller.isTransform) { this._history[method].caller.isTransform(target) - // for everything else a simple morpher change is sufficient } else { this._history[method].morpher.to(target) @@ -405,18 +398,17 @@ SVG.Runner = SVG.invent({ // Run each initialise function in the runner if required _initialise: function (running) { - // If we aren't running, we shouldn't initialise when not declarative if (!running && !this._isDeclarative) return // Loop through all of the initialisers - for (var i = 0, len = this._queue.length; i < len ; ++i) { + for (var i = 0, len = this._queue.length; i < len; ++i) { // Get the current initialiser var current = this._queue[i] // Determine whether we need to initialise var needsIt = this._isDeclarative || (!current.initialised && running) - var running = !current.finished + running = !current.finished // Call the initialiser if we need to if (needsIt && running) { @@ -428,11 +420,9 @@ SVG.Runner = SVG.invent({ // Run each run function for the position or dt given _run: function (positionOrDt) { - // Run all of the _queue directly var allfinished = true - for (var i = 0, len = this._queue.length; i < len ; ++i) { - + for (var i = 0, len = this._queue.length; i < len; ++i) { // Get the current function to run var current = this._queue[i] @@ -456,23 +446,22 @@ SVG.Runner = SVG.invent({ this.transforms = new SVG.Matrix() return this } - }, + } }) SVG.Runner.id = 0 SVG.Runner.sanitise = function (duration, delay, when) { - // Initialise the default parameters var times = 1 var swing = false var wait = 0 - var duration = duration || SVG.defaults.timeline.duration - var delay = delay || SVG.defaults.timeline.delay - var when = when || 'last' + duration = duration || SVG.defaults.timeline.duration + delay = delay || SVG.defaults.timeline.delay + when = when || 'last' // If we have an object, unpack the values - if (typeof duration == 'object' && !(duration instanceof SVG.Stepper)) { + if (typeof duration === 'object' && !(duration instanceof SVG.Stepper)) { delay = duration.delay || delay when = duration.when || when swing = duration.swing || swing @@ -491,7 +480,6 @@ SVG.Runner.sanitise = function (duration, delay, when) { } } - SVG.FakeRunner = class { constructor (transforms = new SVG.Matrix(), id = -1, done = true) { this.transforms = transforms @@ -509,79 +497,106 @@ SVG.extend([SVG.Runner, SVG.FakeRunner], { } }) +// SVG.FakeRunner.emptyRunner = new SVG.FakeRunner() const lmultiply = (last, curr) => last.lmultiplyO(curr) const getRunnerTransform = (runner) => runner.transforms function mergeTransforms () { - // Find the matrix to apply to the element and apply it - let runners = this._transformationRunners + let runners = this._transformationRunners.runners let netTransform = runners .map(getRunnerTransform) .reduce(lmultiply, new SVG.Matrix()) this.transform(netTransform) - // Merge any two transformations in a row that are done - let lastRunner = null - runners.forEach((runner, i) => { - if (lastRunner && runner.done && lastRunner.done) { - delete runners[runner.id+1] - runners[lastRunner.id+1] = runner.mergeWith(lastRunner) - } - - lastRunner = runner - }) + this._transformationRunners.merge() - // 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]) { + if (this._transformationRunners.length() === 1) { this._frameId = null } - - this._currentTransformCache = runners[0].transforms } +class RunnerArray { + constructor () { + this.runners = [] + this.ids = [] + } -SVG.extend(SVG.Element, { + add (runner) { + if (this.runners.includes(runner)) return - // 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) { + let id = runner.id + 1 - this._transformationRunners.forEach((runner, i, arr) => { + let leftSibling = this.ids.reduce((last, curr) => { + if (curr > last && curr < id) return curr + return last + }, 0) - // only delete runners which run before the current - if (runner.id < currentRunner.id) { + let index = this.ids.indexOf(leftSibling) + 1 - // 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 - }) - } + this.ids.splice(index, 0, id) + this.runners.splice(index, 0, runner) - delete arr[i] + return this + } + + getByID (id) { + return this.runners[this.ids.indexOf(id + 1)] + } + + remove (id) { + let index = this.ids.indexOf(id + 1) + this.ids.splice(index, 1) + this.runners.splice(index, 1) + return this + } + + merge () { + let lastRunner = null + this.runners.forEach((runner, i) => { + if (lastRunner && runner.done && lastRunner.done) { + this.remove(runner.id) + this.edit(lastRunner.id, runner.mergeWith(lastRunner)) } + + lastRunner = runner }) - this._transformationRunners[0] = new SVG.FakeRunner() - }, + return this + } + + edit (id, newRunner) { + let index = this.ids.indexOf(id + 1) + this.ids.splice(index, 1, id) + this.runners.splice(index, 1, newRunner) + return this + } + + length () { + return this.ids.length + } - addToCurrentTransform (transform) { - this._currentTransformCache = this._currentTransformCache.lmultiply(transform) + clearBefore (id) { + let deleteCnt = this.ids.indexOf(id + 1) || 1 + this.ids.splice(0, deleteCnt, 0) + this.runners.splice(0, deleteCnt, new SVG.FakeRunner()) return this + } +} + +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.clearBefore(currentRunner.id) }, _currentTransform (current) { - // return this._currentTransformCache - return this._transformationRunners + return this._transformationRunners.runners // 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 @@ -591,7 +606,7 @@ SVG.extend(SVG.Element, { }, addRunner: function (runner) { - this._transformationRunners[runner.id+1] = runner + this._transformationRunners.add(runner) SVG.Animator.transform_frame( mergeTransforms.bind(this), this._frameId @@ -600,20 +615,17 @@ SVG.extend(SVG.Element, { _prepareRunner: function () { if (this._frameId == null) { - this._transformationRunners = [ - new SVG.FakeRunner(new SVG.Matrix(this)) - ] + this._transformationRunners = new RunnerArray() + .add(new SVG.FakeRunner(new SVG.Matrix(this))) - // this._currentTransformCache = new SVG.Matrix(this) this._frameId = SVG.Element.frameId++ } - }, + } }) SVG.Element.frameId = 0 SVG.extend(SVG.Runner, { - attr: function (a, v) { return this.styleAttr('attr', a, v) }, @@ -644,17 +656,17 @@ SVG.extend(SVG.Runner, { }, zoom: function (level, point) { - var morpher = new SVG.Morphable(this._stepper).to(new SVG.Number(level)) + var morpher = new SVG.Morphable(this._stepper).to(new SVG.Number(level)) - this.queue(function() { - morpher = morpher.from(this.zoom()) - }, function (pos) { - this.element().zoom(morpher.at(pos), point) - return morpher.done() - }) + this.queue(function () { + morpher = morpher.from(this.zoom()) + }, function (pos) { + this.element().zoom(morpher.at(pos), point) + return morpher.done() + }) - return this - }, + return this + }, /** ** absolute transformations @@ -688,7 +700,7 @@ SVG.extend(SVG.Runner, { // Create a morepher and set its type const morpher = new SVG.Morphable() - .type( affine ? SVG.Morphable.TransformBag : SVG.Matrix ) + .type(affine ? SVG.Morphable.TransformBag : SVG.Matrix) .stepper(this._stepper) let origin @@ -698,7 +710,6 @@ SVG.extend(SVG.Runner, { let startTransform function setup () { - // make sure element and origin is defined element = element || this.element() origin = origin || getOrigin(transforms, element) @@ -709,13 +720,12 @@ SVG.extend(SVG.Runner, { element.addRunner(this) // Deactivate all transforms that have run so far if we are absolute - if ( !relative ) { + 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() @@ -737,7 +747,7 @@ SVG.extend(SVG.Runner, { // Figure out the shortest path to rotate directly const possibilities = [rTarget - 360, rTarget, rTarget + 360] - const distances = possibilities.map( a => Math.abs(a - rCurrent) ) + const distances = possibilities.map(a => Math.abs(a - rCurrent)) const shortest = Math.min(...distances) const index = distances.indexOf(shortest) target.rotate = possibilities[index] @@ -766,13 +776,12 @@ SVG.extend(SVG.Runner, { } function retarget (newTransforms) { - // only get a new origin if it changed since the last call if ( - (newTransforms.origin || 'center').toString() - != (transforms.origin || 'center').toString() + (newTransforms.origin || 'center').toString() !== + (transforms.origin || 'center').toString() ) { - origin = getOrigin (transforms, element) + origin = getOrigin(transforms, element) } // overwrite the old transformations with the new ones @@ -803,29 +812,28 @@ SVG.extend(SVG.Runner, { }, _queueNumberDelta: function (method, to) { - to = new SVG.Number(to) - - // Try to change the target if we have this method already registerd - if (this._tryRetargetDelta(method, to)) return this - - // Make a morpher and queue the animation - var morpher = new SVG.Morphable(this._stepper).to(to) - this.queue(function () { - var from = this.element()[method]() - morpher.from(from) - morpher.to(from + x) - }, function (pos) { - this.element()[method](morpher.at(pos)) - return morpher.done() - }) + to = new SVG.Number(to) - // Register the morpher so that if it is changed again, we can retarget it - this._rememberMorpher(method, morpher) - return this + // Try to change the target if we have this method already registerd + if (this._tryRetargetDelta(method, to)) return this + + // Make a morpher and queue the animation + var morpher = new SVG.Morphable(this._stepper).to(to) + this.queue(function () { + var from = this.element()[method]() + morpher.from(from) + morpher.to(from + to) + }, function (pos) { + this.element()[method](morpher.at(pos)) + return morpher.done() + }) + + // Register the morpher so that if it is changed again, we can retarget it + this._rememberMorpher(method, morpher) + return this }, _queueObject: function (method, to) { - // Try to change the target if we have this method already registerd if (this._tryRetarget(method, to)) return this @@ -910,7 +918,8 @@ SVG.extend(SVG.Runner, { // in the init function return this._queueObject('plot', new this._element.MorphArray(a)) - /*var morpher = this._element.morphArray().to(a) + /* + var morpher = this._element.morphArray().to(a) this.queue(function () { morpher.from(this._element.array()) @@ -918,7 +927,8 @@ SVG.extend(SVG.Runner, { this._element.plot(morpher.at(pos)) }) - return this*/ + return this + */ }, // Add leading method @@ -2,7 +2,7 @@ /* eslint-disable new-cap */ // The main wrapping element -var SVG = this.SVG = function (element) { +var SVG = window.SVG = function (element) { if (SVG.supported) { element = createElement(element) return element diff --git a/src/timeline.js b/src/timeline.js index 02de178..0bf8ac5 100644 --- a/src/timeline.js +++ b/src/timeline.js @@ -7,7 +7,7 @@ SVG.easing = { '<': function (pos) { return -Math.cos(pos * Math.PI / 2) + 1 } } -var time = performance || Date +var time = window.performance || Date var makeSchedule = function (runnerInfo) { var start = runnerInfo.start @@ -57,10 +57,9 @@ SVG.Timeline = SVG.invent({ // schedules a runner on the timeline schedule (runner, delay, when) { - - if(runner == null) { + if (runner == null) { return this._runners.map(makeSchedule).sort(function (a, b) { - return (a.start - b.start) || (a.duration - b.duration) + return (a.start - b.start) || (a.duration - b.duration) }) } @@ -80,50 +79,47 @@ SVG.Timeline = SVG.invent({ // Work out when to start the animation if (when == null || when === 'last' || when === 'after') { // Take the last time and increment - absoluteStartTime = this._startTime //+ delay - - } else if (when === 'absolute' || when === 'start' ) { + absoluteStartTime = this._startTime + } else if (when === 'absolute' || when === 'start') { absoluteStartTime = delay delay = 0 - } else if (when === 'now') { - absoluteStartTime = this._time //+ delay - + absoluteStartTime = this._time } else if (when === 'relative') { let runnerInfo = this._runners[runner.id] if (runnerInfo) { absoluteStartTime = runnerInfo.start + delay delay = 0 } - } else { throw new Error('Invalid value for the "when" parameter') } - // manage runner + // Manage runner runner.unschedule() runner.timeline(this) runner.time(-delay) - // save startTime for next runner + // Save startTime for next runner this._startTime = absoluteStartTime + runner.duration() + delay - // save runnerInfo + // Save runnerInfo this._runners[runner.id] = { persist: this.persist(), runner: runner, start: absoluteStartTime } - // save order and continue + + // Save order and continue this._order.push(runner.id) this._continue() return this }, - // remove the runner from this timeline + // Remove the runner from this timeline unschedule (runner) { var index = this._order.indexOf(runner.id) - if(index < 0) return this + if (index < 0) return this delete this._runners[runner.id] this._order.splice(index, 1) @@ -132,7 +128,6 @@ SVG.Timeline = SVG.invent({ }, play () { - // Now make sure we are not paused and continue the animation this._paused = false return this._continue() @@ -157,14 +152,14 @@ SVG.Timeline = SVG.invent({ }, speed (speed) { - if(speed == null) return this._speed + if (speed == null) return this._speed this._speed = speed return this }, reverse (yes) { var currentSpeed = this.speed() - if(yes == null) return this.speed(-currentSpeed) + if (yes == null) return this.speed(-currentSpeed) var positive = Math.abs(currentSpeed) return this.speed(yes ? positive : -positive) @@ -176,7 +171,7 @@ SVG.Timeline = SVG.invent({ }, time (time) { - if(time == null) return this._time + if (time == null) return this._time this._time = time return this }, @@ -194,7 +189,6 @@ SVG.Timeline = SVG.invent({ }, _step () { - // If the timeline is paused, just do nothing if (this._paused) return @@ -218,15 +212,16 @@ SVG.Timeline = SVG.invent({ var runner = runnerInfo.runner let dt = dtTime - // Make sure that we give the actual dt to the start if needed + // Make sure that we give the actual difference + // between runner start time and now let dtToStart = this._time - runnerInfo.start - // dont run runner if not started yet + // Dont run runner if not started yet if (dtToStart < 0) { runnersLeft = true continue - } else if (dtToStart < dt){ - // adjust dt to make sure that animation is on point + } else if (dtToStart < dt) { + // Adjust dt to make sure that animation is on point dt = dtToStart } @@ -238,42 +233,36 @@ SVG.Timeline = SVG.invent({ if (!finished) { runnersLeft = true // continue + } else if (runnerInfo.persist !== true) { + // runner is finished. And runner might get removed + + // TODO: Figure out end time of runner + var endTime = runner.duration() - runner.time() + this._time + + if (endTime + this._persist < this._time) { + // Delete runner and correct index + delete this._runners[this._order[i]] + this._order.splice(i--, 1) && --len + runner.timeline(null) + } } - - - // } else if(runnerInfo.persist !== true){ - // - // // runner is finished. And runner might get removed - // - // // TODO: Figure out end time of runner - // var endTime = runner.duration() - runner.time() + this._time - // - // if(endTime + this._persist < this._time) { - // // FIXME: which one is better? - // // runner.unschedule() - // // --i - // // --len - // - // // delete runner and correct index - // this._runners.splice(i--, 1) && --len - // runner.timeline(null) - // } - // - // } } // Get the next animation frame to keep the simulation going - if (runnersLeft) + if (runnersLeft) { this._nextFrame = SVG.Animator.frame(this._step.bind(this)) - else this._nextFrame = null + } else { + this._nextFrame = null + } return this }, // Checks if we are running and continues the animation _continue () { if (this._paused) return this - if (!this._nextFrame) + if (!this._nextFrame) { this._nextFrame = SVG.Animator.frame(this._step.bind(this)) + } return this }, @@ -288,6 +277,6 @@ SVG.Timeline = SVG.invent({ timeline: function () { this._timeline = (this._timeline || new SVG.Timeline()) return this._timeline - }, + } } }) diff --git a/src/transform.js b/src/transform.js index 6ea5269..96c0aec 100644 --- a/src/transform.js +++ b/src/transform.js @@ -1,4 +1,4 @@ -/* global arrayToMatrix getOrigin */ +/* global arrayToMatrix getOrigin isMatrixLike */ SVG.extend(SVG.Element, { // Reset all transformations |