From 39cd3a29e2c8dc494a7cffa610c33f5b62995841 Mon Sep 17 00:00:00 2001 From: Saivan Date: Fri, 1 Jun 2018 21:48:09 +1000 Subject: [PATCH] The timelines continue function requests a step animation frame --- dirty.html | 8 ++-- spec/spec/runner.js | 16 ++++++-- src/runner.js | 30 +++++++++------ src/timeline.js | 7 +++- todo.md | 91 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 132 insertions(+), 20 deletions(-) create mode 100644 todo.md diff --git a/dirty.html b/dirty.html index f6ff65d..09438cb 100644 --- a/dirty.html +++ b/dirty.html @@ -97,7 +97,7 @@ function getColor(t) { SVG.defaults.timeline.ease = '-' var r = new SVG.Runner(1000) -var t = new SVG.Timeline().pause() +var t = new SVG.Timeline() r.schedule(t, 200) .animate(500).loop(5, true, 100) .animate(600, 200, 'absolute') @@ -116,8 +116,8 @@ schedule.forEach((s, i) => { s.runner.element(rect) .attr('fill', getColor(i*0.1)) - if (i===0) - s.runner.during(console.log) + // if (i===0) + // s.runner.during(console.log) }) var mover = canvas.line(100, 100, 100, 300).attr('stroke', 'black').clone() @@ -127,7 +127,7 @@ t.on('time', function (e) { mover.x(100 + e.detail/10) }) -t.play() + console.log(schedule) // var bla = SVG('').size(0, 0).move(200, 200).addTo('svg') diff --git a/spec/spec/runner.js b/spec/spec/runner.js index 50644e2..1b7ed41 100644 --- a/spec/spec/runner.js +++ b/spec/spec/runner.js @@ -420,6 +420,7 @@ describe('SVG.Runner', function () { runner.step(800) expect(spy).toHaveBeenCalledWith(0.75) + runner.step(250) expect(spy).toHaveBeenCalledWith(1) }) @@ -651,6 +652,7 @@ describe('SVG.Runner', function () { }) describe('position()', function () { + it('gets the position of a runner', function () { var spy = jasmine.createSpy('stepper') var runner = new SVG.Runner(1000).queue(null, spy) @@ -660,6 +662,7 @@ describe('SVG.Runner', function () { expect(runner.position()).toBe(0.3) }) + it('gets the position of a runner when looping', function () { var spy = jasmine.createSpy('stepper') var runner = new SVG.Runner(1000).loop(5, true, 100).queue(null, spy) @@ -669,6 +672,7 @@ describe('SVG.Runner', function () { expect(runner.position()).toBe(0.9) }) + it('sets the position of a runner', function () { var spy = jasmine.createSpy('stepper') var runner = new SVG.Runner(1000).queue(null, spy) @@ -676,14 +680,20 @@ describe('SVG.Runner', function () { expect(runner.position(0.5).position()).toBe(0.5) expect(spy).toHaveBeenCalledWith(0.5) }) - it('sets the position of a runner', function () { + + it('sets the position of a runner in a loop', function () { var spy = jasmine.createSpy('stepper') var runner = new SVG.Runner(1000).loop(5, true, 100).queue(null, spy) runner.step(1200) - expect(runner.position(0.4).position()).toBe(0.4) - expect(spy).toHaveBeenCalledWith(0.6) + expect(spy).toHaveBeenCalledWith(0.4) + + expect(runner.position(0).position()).toBe(0) + expect(spy).toHaveBeenCalledWith(0) + + expect(runner.position(1).position()).toBe(1) + expect(spy).toHaveBeenCalledWith(1) }) }) diff --git a/src/runner.js b/src/runner.js index 065967d..abf7fea 100644 --- a/src/runner.js +++ b/src/runner.js @@ -13,6 +13,9 @@ SVG.Runner = SVG.invent({ create: function (options) { + // Store a unique id on the runner, so that we can identify it + this.id = SVG.Runner.id++ + // ensure a default value options = options == null ? SVG.defaults.timeline.duration @@ -207,6 +210,15 @@ SVG.Runner = SVG.invent({ }, position: function (p) { + + // Get all of the variables we need + var x = this._time + var d = this._duration + var w = this._wait + var t = this._times + var s = this._swing + var r = this._reverse + if (p == null) { /* @@ -216,14 +228,6 @@ SVG.Runner = SVG.invent({ The logic is slightly simplified here because we can use booleans */ - // Get all of the variables we need - var x = this._time - var d = this._duration - var w = this._wait - var t = this._times - var s = this._swing - var r = this._reverse - // Figure out the value without thinking about the start or end time function f (x) { var swinging = s * Math.floor(x % (2 * (w + d)) / (w + d)) @@ -242,9 +246,10 @@ SVG.Runner = SVG.invent({ } // Work out the loops done and add the position to the loops done - var loopDuration = this._duration + this._wait - var loopsDone = Math.floor(this._time / loopDuration) - var position = loopsDone + p + var loopsDone = Math.floor(this.loops()) + var swingForward = s && (loopsDone % 2 == 0) + var forwards = (swingForward && !r) || (r && swingForward) + var position = loopsDone + (forwards ? p : 1 - p) return this.loops(position) }, @@ -409,6 +414,8 @@ SVG.Runner = SVG.invent({ }, }) +SVG.Runner.id = 0 + SVG.Runner.sanitise = function (duration, delay, when) { // Initialise the default parameters @@ -734,7 +741,6 @@ SVG.extend(SVG.Runner, { if (o.color != null) this.attr('stop-color', o.color) if (o.offset != null) this.attr('offset', o.offset) - return this } }) diff --git a/src/timeline.js b/src/timeline.js index 13aff19..62d5021 100644 --- a/src/timeline.js +++ b/src/timeline.js @@ -211,6 +211,7 @@ SVG.Timeline = SVG.invent({ this._time += dtTime this._lastStepTime = this._time +console.log("hi", this._time); this.fire('time', this._time) // Run all of the runners directly @@ -229,6 +230,9 @@ SVG.Timeline = SVG.invent({ return } + // Remove the runner from the set + // this._runner. + // Runner is finished and might get removed if(this._persist !== true) { // Figure out end time of the runner @@ -253,7 +257,8 @@ SVG.Timeline = SVG.invent({ // Checks if we are running and continues the animation _continue () { if (this._paused) return this - if (!this._nextFrame) this._step() + if (!this._nextFrame) + this._nextFrame = SVG.Animator.frame(this._step.bind(this)) return this } }, diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..b1b5a87 --- /dev/null +++ b/todo.md @@ -0,0 +1,91 @@ + + +# Where We Left Off + +Saivan +====== + + +Ulima +===== +- Use runners[runnerid] = {startTime, runner, persist} +timeline.persist('monkey-in', Infinity) + + +Both +==== +- We discussed that matrices should always be applied from the left for animation, so we have: + - If we have C R x where C is the current Matrix and R is the relative matrix that we want to apply + - It could be animated by instead left multiplying (C R inv(C)) so that we have (C R inv(C)) C R + - This allows us to always left multiply (which greatly simplifies things) + => Conclusion: We dont do this. We apply transformations left or right whatever is necessary + +Latest +====== +- Runners would call an element.mergeMatrix() function that requests a native animation frame. Each runner would cancel the call made by the last runner, so that the function only runs once per frame. +-https://en.wikipedia.org/wiki/Change_of_basis#Change_of_coordinates_of_a_vector + + + +# Timeline Description + +- [T] Timeline constructors + - [T] timeline () - Returns the timeline context to the user + +- [T] Time Management + - [T] play () - Lets the timeline keep playing from here + - [T] pause () - Pauses the timeline where it currently is + - [T] stop () - Pauses the timeline and sets time = 0 + - [T] finish () - Moves the time to the final time for the final animation, forces declaratives to snap to their final positions + - [T] speed (newSpeed) - Sets the playback speed + - [T] seek (dt) - Scrubs the timeline time forward or backward by dt + - [T] time (t) - Sets the absolute time to t + - [T] backwards (back) - Sets the speed to (back ? speed : -speed) + - [T] position (p) - sets the position in range [0, 1] + - [T] loop (times, swing, waits) + +- [T] Runner Management + - [T] remove(tagOrRunner, end) - Removes all runners with tag from the timeline + - [T] reset () - Deletes all of the runners and resets the timeline + - [T] persist (tag, lifetime) - how long to keep a reference to an animation after it is completed + - [T] schedule (tag, time, when) - move the start time of the runner to time otherwise, returns all of the scheduled runners start and end times. + +- [T] Hidden Methods + - [x] `_step (dt)` + - [x] `_continue ()` + + +# Runner + +- [x] Constructors + - [x] animate (duration, delay, when) - Makes a new runner and returns the timeline context to the user with the new runner active. + - [x] loop (duration, times, swing) - Makes a new runner with the looping set as described by the parameters, returns timeline + - [x] delay (by, when) - Makes a new runner to start ms after the last active runner is complete + +- [x] Runner Methods + - [x] element (svgElement) - Given an element, you can bind it directly + - [x] animate (args) - Calls animate if we have an element set + - [x] loop (args) - Calls loop with arguments if we have an element + - [x] delay (args) - calls delay if we have an element + +- [x] Runner Events + - [x] on (eventName, fn) - Binds a function to an event + - [x] off (eventName) - Unbinds all function from that event + - [x] fire () - Fires an event + +- [x] Basic Functionality + - [x] queue (initFn, runFn, alwaysInitialise) - Given two functions, the runner will run initFn once, and run runFn on every step. If alwaysInitialise is true, it will always run the initialisation as well. + - [x] during (runFn) - The function to run on each frame + +- [x] Runner Animation Methods + - [x] time (time) - Sets the time to the given time and runs the runner + - [x] step (dt) - Runs the runner method if + - [x] finish () - runs step with dT = Infinity + - [x] reverse () - Makes non-declarative runners play backwards + - [x] ease (fn) - Sets the easing function, can not be used to convert a non-declarative to a declarative animation. + - [x] active (activated) - Activates or deactivates a runner + - [x] loop (o) - Activates a loop sequence + +- [x] Runner Management + - [x] tag (name) - Name a runner or act as a getter + - [x] untag () -- 2.39.5