diff options
author | Ulrich-Matthias Schäfer <ulima.ums@googlemail.com> | 2018-05-29 00:18:41 +0200 |
---|---|---|
committer | Ulrich-Matthias Schäfer <ulima.ums@googlemail.com> | 2018-05-29 00:18:41 +0200 |
commit | 8c4e55ee559fdc1597319f18aa1ccb9ac15474cc (patch) | |
tree | a8f37c00547231d3f904fdb44caa70bcebb637e3 | |
parent | be8320d4bfada1f5fc1c7eaef8402c52f9d9be86 (diff) | |
download | svg.js-8c4e55ee559fdc1597319f18aa1ccb9ac15474cc.tar.gz svg.js-8c4e55ee559fdc1597319f18aa1ccb9ac15474cc.zip |
implement methods, reorganize runner, list questions
-rw-r--r-- | dirty.html | 31 | ||||
-rw-r--r-- | src/animator.js | 4 | ||||
-rw-r--r-- | src/runner.js | 216 | ||||
-rw-r--r-- | src/timeline.js | 230 |
4 files changed, 239 insertions, 242 deletions
@@ -74,8 +74,8 @@ function getColor(t) { // } // } -// var bla = SVG('<rect>').size(50, 50).center(100, 100).addTo('svg') -// bla.animate().move(220, 200) +var bla = SVG('<rect>').size(0, 0).move(200, 200).addTo('svg') +bla.animate().size(220, 200).queue(null, console.log) // var randPoint = (x = 50, y = 50) => [ // Math.random() * 100 - 50 + x, @@ -101,14 +101,27 @@ function getColor(t) { // ]) // }) -var mover = SVG('<ellipse>').size(50, 50).center(100, 100).addTo('svg') -var anim = mover.animate(new SVG.Spring(500, 10)).move(500, 500) +// var mover = SVG('<ellipse>').size(50, 50).center(100, 100).addTo('svg') +// var anim = mover.animate(new SVG.Spring(500, 10)).move(500, 500) +// +// SVG.on(document, 'mousemove', function (e) { +// //mover.animate(SVG.PID()).move(e.pageX, e.pageY) +// var p = mover.point(e.pageX, e.pageY) +// anim.center(p.x, p.y) +// }) + +// var timeline = new SVG.Timeline().pause() +// var runner = new SVG.Runner(100000) +// runner.queue(null, function (pos) { +// console.log(pos) +// }) +// timeline.schedule(runner) +// +// runner.after(() => console.log('finished with after')) +// runner.on('finish', () => console.log('finished with on')) -SVG.on(document, 'mousemove', function (e) { - //mover.animate(SVG.PID()).move(e.pageX, e.pageY) - var p = mover.point(e.pageX, e.pageY) - anim.center(p.x, p.y) -}) +//timeline.play() +//timeline.finish() </script> diff --git a/src/animator.js b/src/animator.js index 4505eec..cfc5e7e 100644 --- a/src/animator.js +++ b/src/animator.js @@ -10,7 +10,7 @@ SVG.Animator = { frame: function (fn) { SVG.Animator.frames.push({ - id: SVG.Animator.frameCount, + id: SVG.Animator.frameCount++, run: fn }) @@ -18,7 +18,7 @@ SVG.Animator = { SVG.Animator.nextDraw = requestAnimationFrame(SVG.Animator._draw) } - return ++SVG.Animator.frameCount + return SVG.Animator.frameCount }, timeout: function (fn, delay) { diff --git a/src/runner.js b/src/runner.js index 68dd7e8..3b658c2 100644 --- a/src/runner.js +++ b/src/runner.js @@ -25,6 +25,7 @@ SVG.Runner = SVG.invent({ // Declare all of the variables this._dispacher = document.createElement('div') this._element = null + this._timeline = null this.done = false this._queue = [] @@ -41,52 +42,65 @@ SVG.Runner = SVG.invent({ this._time = 0 this._last = 0 this.tags = {} + + // save the transformation we are starting with + this._baseTransform = null }, construct: { animate: function (duration, delay, when) { - // Initialise the default parameters - var times = 0 - var swing = false - var waits = [] - - // If we have an object, unpack the values - if (typeof duration == 'object' && !(duration instanceof SVG.Stepper)) { - delay = duration.delay || 0 - when = duration.when || 'now' - duration = duration.duration || 1000 - swing = duration.swing || false - times = duration.times || 0 - waits = duration.waits || [] - } - - // FIXME: take care of looping here because loop is a constructor - // alternatively disallow loop as constructor - // Construct a new runner and setup its looping behaviour - var runner = new SVG.Runner(duration) - //.loop(times, swing, waits) + return new SVG.Runner(duration && duration.duration || duration) .element(this) - - // Attach this animation to a timeline - this.timeline().schedule(runner, delay, when) - return runner + .timeline(this.timeline()) + .init(duration, delay, when) + + // // Initialise the default parameters + // var times = 0 + // var swing = false + // var waits = [] + // + // // If we have an object, unpack the values + // if (typeof duration == 'object' && !(duration instanceof SVG.Stepper)) { + // delay = duration.delay || 0 + // when = duration.when || 'now' + // duration = duration.duration || 1000 + // swing = duration.swing || false + // times = duration.times || 0 + // waits = duration.waits || [] + // } + // + // // FIXME: take care of looping here because loop is a constructor + // // alternatively disallow loop as constructor + // // Construct a new runner and setup its looping behaviour + // var runner = new SVG.Runner(duration) + // //.loop(times, swing, waits) + // .element(this) + // + // // Attach this animation to a timeline + // this.timeline().schedule(runner, delay, when) + // return runner }, loop: function (duration, times, swing) { - // If we have an object, unpack the values - if (typeof duration == 'object') { - duration.times = duration.times || Infinity - } else { - duration = { - duration: duration, - times: times || Infinity, - swing: swing - } - } - return this.animate(duration) + return new SVG.Runner(duration.duration || duration) + .element(this) + .timeline(this.timeline()) + .initLoop(duration, times, swing) + + // // If we have an object, unpack the values + // if (typeof duration == 'object') { + // duration.times = duration.times || Infinity + // } else { + // duration = { + // duration: duration, + // times: times || Infinity, + // swing: swing + // } + // } + // return this.animate(duration) }, delay: function (by, when) { @@ -109,24 +123,83 @@ SVG.Runner = SVG.invent({ return this }, - timeline: function () { - return this._element.timeline() + timeline: function (timeline) { + if(timeline == null) return this._timeline + this._timeline = timeline + return this }, - // FIXME: It makes totally sense to call this, when the runner is attached to a timeline. - // So maybe we should attach runners to timelines and timelines to elements instead of the other way round - animate: function () { - if(this._element) { - return this._element.animate.apply(this._element, arguments) + animate: function(duration, delay, when) { + var runner = new SVG.Runner(duration.duration || duration) + if(this._timeline) runner.element(this._timeline) + if(this._element) runner.element(this._element) + return runner.init(duration, delay, when) + }, + + unschedule: function () { + var timeline = this.timeline() + timeline && timeline.unschedule(this) + return this + }, + + schedule: function (timeline, delay, when) { + if(!timeline) { + throw Error('Runner cannot be scheduled without timeline') } - // TODO: throw an error if there is no element + + // FIXME: timeline is already set when used in normal ways + // but for manual runners we need that here anyway + // so just have doubled code? + timeline.schedule(this, delay, when) + this.timeline(timeline) + return this }, - loop: function () { - if(this._element) { - return this._element.loop.apply(this._element, arguments) + // schedule a runner + init: function (duration, delay, when) { + // Initialise the default parameters + var times = 0 + var swing = false + var waits = [] + + // If we have an object, unpack the values + if (typeof duration == 'object' && !(duration instanceof SVG.Stepper)) { + delay = duration.delay || 0 + when = duration.when || 'now' + duration = duration.duration || 1000 + swing = duration.swing || false + times = duration.times || 0 + waits = duration.waits || [] } - // TODO: throw an error + + // TODO: take care of looping here because there is no loop function we can use + // e.g. this._times = times + + // Attach this animation to a timeline + //this.timeline().schedule(this, delay, when) + return this.schedule(this.timeline(), delay, when) + }, + + initLoop: function (duration, times, swing) { + // If we have an object, unpack the values + if (typeof duration == 'object') { + duration.times = duration.times || Infinity + } else { + duration = { + duration: duration, + times: times || Infinity, + swing: swing + } + } + + return this.init(duration) + }, + + loop: function (duration, times, swing) { + var runner = new SVG.Runner(duration.duration || duration) + if(this._timeline) runner.element(this._timeline) + if(this._element) runner.element(this._element) + return runner.initLoop(duration, times, swing) }, delay: function () { @@ -150,27 +223,29 @@ SVG.Runner = SVG.invent({ initialised: false, finished: false, }) - this.timeline()._continue() + var timeline = this.timeline() + timeline && this.timeline()._continue() return this }, - during: function (runFn) { - return this.queue(null, runFn, false) + during: function () { + return this.on('during', fn, this) }, - on (eventName, fn) { - SVG.on(this._dispacher, eventName, fn, this) + on (eventName, fn, binding) { + SVG.on(this._dispacher, eventName, fn, binding) return this }, // Queue a function to run after this runner - after (time, fn) { - return this.on('finish', fn) + after (fn) { + return this.on('finish', fn, this) }, - fire: function (name) { - - } + fire: function (name, detail) { + SVG.Element.prototype.dispatch.call({node: this._dispacher}, name, detail) + return this + }, /* Runner animation methods @@ -223,14 +298,9 @@ SVG.Runner = SVG.invent({ // Set whether this runner is complete or not this.done = finished - if (this.done) { - this._afterEvents.forEach(function (event) { event(this) }) - if (this._element) this._element.fire(`runner.${id}.finish`, {runner: this}) - - el.animate().after() - el.on() - } + // Fire finished event if finished + this.done && this.fire('finish', {runner: this}) return this }, @@ -320,7 +390,7 @@ SVG.Runner = SVG.invent({ var running = !current.finished if (needsInit && running) { - current.initialiser.call(this._element) + current.initialiser.call(this) current.initialised = true } } @@ -339,7 +409,7 @@ SVG.Runner = SVG.invent({ // Run the function if its not finished, we keep track of the finished // flag for the sake of declarative _queue current.finished = current.finished - || (current.runner.call(this._element, position) === true) + || (current.runner.call(this, position) === true) allfinished = allfinished && current.finished } @@ -373,9 +443,9 @@ SVG.extend(SVG.Runner, { var morpher = new Morphable(this._stepper).to(val) this.queue(function () { - morpher = morpher.from(this[type](name)) + morpher = morpher.from(this.element()[type](name)) }, function () { - this[type](name, morpher.at(pos)) + this.element()[type](name, morpher.at(pos)) return morpher.done() }, this._isDeclarative) @@ -388,7 +458,7 @@ SVG.extend(SVG.Runner, { this.queue(function() { morpher = morpher.from(this.zoom()) }, function (pos) { - this.zoom(morpher.at(pos), point) + this.element().zoom(morpher.at(pos), point) return morpher.done() }, this._isDeclarative) @@ -515,11 +585,11 @@ SVG.extend(SVG.Runner, { // Make a morpher and queue the animation var morpher = new SVG.Morphable(this._stepper).to(to) this.queue(function () { - var from = this[method]() + var from = this.element()[method]() morpher.from(from) morpher.to(from + x) }, function (pos) { - this[method](morpher.at(pos)) + this.element()[method](morpher.at(pos)) return morpher.done() }, this._isDeclarative) @@ -536,9 +606,9 @@ SVG.extend(SVG.Runner, { // Make a morpher and queue the animation var morpher = new SVG.Morphable(this._stepper).to(to) this.queue(function () { - morpher.from(this[method]()) + morpher.from(this.element()[method]()) }, function (pos) { - this[method](morpher.at(pos)) + this.element()[method](morpher.at(pos)) return morpher.done() }, this._isDeclarative) diff --git a/src/timeline.js b/src/timeline.js index 154dabe..35bc71c 100644 --- a/src/timeline.js +++ b/src/timeline.js @@ -13,20 +13,15 @@ SVG.Timeline = SVG.invent({ create: function (element) { // Store a reference to the element to call its parent methods - this._element = element + this._element = element || null // Store the timing variables this._startTime = 0 - this._duration = 0 - this._ease = SVG.defaults.timeline.ease this._speed = 1.0 // Play control variables control how the animation proceeds - this._controller = null this._reverse = false - this._loops = null - this._waits = null - this._swing = null + this._persist = 0 // Keep track of the running animations and their starting parameters this._baseTransform = null @@ -34,98 +29,33 @@ SVG.Timeline = SVG.invent({ this._paused = false this._runners = [] this._time = 0 + this._lastTime = 0 }, extend: { - // /** - // * Runner Constructors - // */ - // - // animate (duration, delay, nowOrAbsolute) { - // - // // Clear the controller and the looping parameters - // this._controller = duration instanceof Function ? duration : null - // this._backwards = false - // this._swing = false - // this._loops = 0 - // - // // If we have an object we are declaring imperative animations - // if (typeof duration === 'object') { - // duration = duration.duration - // delay = duration.delay - // nowOrAbsolute = duration.absolute || duration.now - // } - // - // // The start time for the next animation can either be given explicitly, - // // derived from the current timeline time or it can be relative to the - // // last start time to chain animations direclty - // var absoluteStartTime = typeof nowOrAbsolute === 'number' ? nowOrAbsolute - // : nowOrAbsolute ? this._time - // : this._startTime + this._duration - // - // // We start the next animation after the delay required - // this._startTime = absoluteStartTime + (delay || 0) - // this._duration = duration instanceof Function ? null - // : (duration || SVG.defaults.timeline.duration) - // - // // Make a new runner to queue all of the animations onto - // this._runner = new Runner(this._time - this._startTime, this.duration) - // this._runners.push(this._runner) - // - // // Step the animation - // this._continue() - // - // // Allow for chaining - // return this - // }, - // - // delay (by, now) { - // return this.animate(0, by, now) - // }, - // - // /** - // * Runner Behaviours - // */ - // - // loop (swing, times, wait) { - // - // }, - // - // ease (fn) { - // var ease = SVG.easing[fn || SVG.defaults.timeline.ease] || fn - // this._controller = function (from, to, pos) { - // // FIXME: This is needed for at lest ObjectBag but could slow down stuff - // if(typeof from !== 'number') { - // return pos < 1 ? from : to - // } - // return from + (to - from) * ease(pos) - // } - // return this - // }, - - reverse () { - + element (element) { + if(element == null) return this._element + this._element = element }, /** * */ - // tag (name) { - // this._runner.tag(name) - // }, - // - // runner (tag) { - // if (tag) { - // return this._runners.find(function (runTag) {return runTag === tag}) - // } else { - // return this._runner - // } - // }, + // remove the runner from this timeline + unschedule (runner) { + var index = this._runners.indexOf(runner) + if(index > -1) { + this._runners.splice(index, 1) + } + return this + }, schedule (runner, delay, when) { + runner.unschedule() + // The start time for the next animation can either be given explicitly, // derived from the current timeline time or it can be relative to the // last start time to chain animations direclty @@ -167,89 +97,91 @@ SVG.Timeline = SVG.invent({ return this }, - pause () { - - // + // FIXME: this does not work. Setting the nextFrame to null alone is not working + // We need to remove our frames from the animator somehow + cancel () { + // SVG.Animator.cancel(this._nextFrame) this._nextFrame = null - this._paused = true return this }, + pause () { + // Cancel the next animation frame and pause + this._paused = true + return this.cancel() + }, + stop () { - // Cancel the next animation frame for this object - this._nextFrame = null - return this + // Cancel the next animation frame and go to start + this.seek(-this._time) + return this.cancel() }, finish () { + this.seek(Infinity) + return this.cancel() + }, + + speed (speed) { + if(speed == null) return this._speed + this._speed = speed return this }, - speed (newSpeed) { - this._speed = newSpeed + // FIXME: rewrite this to use the speed method + reverse (yes) { + this._speed = Math.abs(this._speed) * yes ? -1 : 1 return this }, seek (dt) { - this._time += dt + // what to do here? + // we cannot just set a new time + // also calling step does not result in anything + // because step is getting called with the current real time which + // will reset it to the old flow + + // only way is to change lastTime to the current time + what we want + this._lastTime -= dt return this }, time (t) { + if(t == null) return this._time this._time = t return this }, persist (dtOrForever) { - // 0 by default - }, + if(tdOrForever == null) return this._persist - // queue (initFn, runFn) { - // - // // Make sure there is a function available - // initFn = (initFn || SVG.void).bind(this) - // runFn = (runFn || SVG.void).bind(this) - // - // // Add the functions to the active runner - // this._runner.add(initFn, runFn) - // return this - // }, - - // Queue a function to run after some time - after (time, fn) { - - // If the user passes no time, just queue it - if (fn == null) { - return this.queue(time) - } - - // Otherwise make a runner to run this one time later - var runner = new Runner(-time, 0).add(fn) - this._runners.push(runner) + this._persist = dtOrForever return this }, - during (fn) { - return this.queue(null, fn) - }, - _step (time) { - + // FIXME: User should be able to step manually + // move this check to the very bottom + // or mixup the continue, step logic // If we are paused, just exit if (this._paused) return // Get the time delta from the last time and update the time // TODO: Deal with window.blur window.focus to pause animations // HACK: We keep the time below 50ms to avoid driving animations crazy + // FIXME: We cannot seek to -time because speed fucks this up var dt = this._speed * ((time - this._lastTime) || 16) + + // we cannot do that. Doesnt work when user wants to manually step (or seek) dt = dt < 50 ? dt : 16 // If we missed alot of time, ignore this._lastTime = time + + // FIXME: this is not used this._time += dt // Run all of the runners directly var runnersLeft = false - for (var i = 0; i < this._runners.length ; i++) { - + for (var i = 0, len = this._runners.length; i < len; i++) { // Get and run the current runner and ignore it if its inactive var runner = this._runners[i] if(!runner.active()) continue @@ -259,6 +191,17 @@ SVG.Timeline = SVG.invent({ var finished = runner.step(dt).done if (!finished) { runnersLeft = true + } else if(this._persist !== true){ + // runner is finished. And runner might get removed + + // TODO: Figure out end time of runner + var endTime = Infinity + + if(endTime + this._persist < this._time) { + // delete runner and correct index + this._runners.splice(i--, 1) && --len + } + } // TODO: Check if a runner is still healthy, and if it is, run it. @@ -283,9 +226,9 @@ SVG.Timeline = SVG.invent({ // Checks if we are running and continues the animation _continue () { - if (this._paused) return + if (this._paused) return this if (!this._nextFrame) - this._step() + this._step(this._lastTime) // FIXME: we have to past an absolute time here return this }, }, @@ -293,38 +236,9 @@ SVG.Timeline = SVG.invent({ // These methods will be added to all SVG.Element objects parent: SVG.Element, construct: { - timeline: function () { this._timeline = (this._timeline || new SVG.Timeline(this)) return this._timeline }, - - // animate: function(o, delay, now) { - // - // // Get the current timeline or construct a new one - // this.timeline = (this.timeline || new SVG.Timeline(this)) - // .animate(o, delay, now) - // this.timeline._loops = null - // return this.timeline - // }, - // - // loop: function(o) { - // - // /* - // { - // swing: wether or not the animation should repeat when its done - // times: the number of times to loop the animation - // wait: [array] a buffer of times to wait between successive animations - // delay: defaults.timeline to wait - // } - // */ - // this.timeline = (this.timeline || new SVG.Timeline(this)) - // - // // REFACTOR this into an init function - // this.timeline._waits = [].concat(o.wait || o.delay || 0) - // this.timeline._loops = o.times || Infinity - // this.timeline._swing = o.swing || false - // return this.timeline - // } } }) |