summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlrich-Matthias Schäfer <ulima.ums@googlemail.com>2018-05-29 00:18:41 +0200
committerUlrich-Matthias Schäfer <ulima.ums@googlemail.com>2018-05-29 00:18:41 +0200
commit8c4e55ee559fdc1597319f18aa1ccb9ac15474cc (patch)
treea8f37c00547231d3f904fdb44caa70bcebb637e3
parentbe8320d4bfada1f5fc1c7eaef8402c52f9d9be86 (diff)
downloadsvg.js-8c4e55ee559fdc1597319f18aa1ccb9ac15474cc.tar.gz
svg.js-8c4e55ee559fdc1597319f18aa1ccb9ac15474cc.zip
implement methods, reorganize runner, list questions
-rw-r--r--dirty.html31
-rw-r--r--src/animator.js4
-rw-r--r--src/runner.js216
-rw-r--r--src/timeline.js230
4 files changed, 239 insertions, 242 deletions
diff --git a/dirty.html b/dirty.html
index 41c1583..21cf58e 100644
--- a/dirty.html
+++ b/dirty.html
@@ -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
- // }
}
})