diff options
Diffstat (limited to 'src/animation/Runner.js')
-rw-r--r-- | src/animation/Runner.js | 838 |
1 files changed, 293 insertions, 545 deletions
diff --git a/src/animation/Runner.js b/src/animation/Runner.js index d2c7bdf..7e04c21 100644 --- a/src/animation/Runner.js +++ b/src/animation/Runner.js @@ -15,9 +15,7 @@ import SVGNumber from '../types/SVGNumber.js' import Timeline from './Timeline.js' export default class Runner extends EventTarget { - - constructor ( options ) { - + constructor (options) { super() // Store a unique id on the runner, so that we can identify it later @@ -30,7 +28,7 @@ export default class Runner extends EventTarget { // Ensure that we get a controller options = typeof options === 'function' - ? new Controller( options ) + ? new Controller(options) : options // Declare all of the variables @@ -63,7 +61,6 @@ export default class Runner extends EventTarget { this._swing = false this._wait = 0 this._times = 1 - } /* @@ -73,75 +70,58 @@ export default class Runner extends EventTarget { help us make new runners from the current runner */ - element ( element ) { - - if ( element == null ) return this._element + element (element) { + if (element == null) return this._element this._element = element element._prepareRunner() return this - } - timeline ( timeline ) { - + timeline (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 ( duration, delay, when ) { - - var o = Runner.sanitise( duration, delay, when ) - var runner = new Runner( o.duration ) - if ( this._timeline ) runner.timeline( this._timeline ) - if ( this._element ) runner.element( this._element ) - return runner.loop( o ).schedule( delay, when ) - + animate (duration, delay, when) { + var o = Runner.sanitise(duration, delay, when) + var runner = new Runner(o.duration) + if (this._timeline) runner.timeline(this._timeline) + if (this._element) runner.element(this._element) + return runner.loop(o).schedule(delay, when) } - schedule ( timeline, delay, when ) { - + schedule (timeline, delay, when) { // The user doesn't need to pass a timeline if we already have one - if ( !( timeline instanceof Timeline ) ) { - + if (!(timeline instanceof Timeline)) { when = delay delay = timeline timeline = this.timeline() - } // If there is no timeline, yell at the user... - if ( !timeline ) { - - throw Error( 'Runner cannot be scheduled without timeline' ) - + if (!timeline) { + throw Error('Runner cannot be scheduled without timeline') } // Schedule the runner on the timeline provided - timeline.schedule( this, delay, when ) + timeline.schedule(this, delay, when) return this - } unschedule () { - var timeline = this.timeline() - timeline && timeline.unschedule( this ) + timeline && timeline.unschedule(this) return this - } - loop ( times, swing, wait ) { - + loop (times, swing, wait) { // Deal with the user passing in an object - if ( typeof times === 'object' ) { - + if (typeof times === 'object') { swing = times.swing wait = times.wait times = times.times - } // Sanitise the values and store them @@ -149,13 +129,10 @@ export default class Runner extends EventTarget { this._swing = swing || false this._wait = wait || 0 return this - } - delay ( delay ) { - - return this.animate( 0, delay ) - + delay (delay) { + return this.animate(0, delay) } /* @@ -164,32 +141,26 @@ export default class Runner extends EventTarget { These methods allow us to attach basic functions to the runner directly */ - queue ( initFn, runFn, retargetFn, isTransform ) { - - this._queue.push( { + queue (initFn, runFn, retargetFn, isTransform) { + this._queue.push({ initialiser: initFn || noop, runner: runFn || noop, retarget: retargetFn, isTransform: isTransform, initialised: false, finished: false - } ) + }) var timeline = this.timeline() timeline && this.timeline()._continue() return this - } - during ( fn ) { - - return this.queue( null, fn ) - + during (fn) { + return this.queue(null, fn) } - after ( fn ) { - - return this.on( 'finish', fn ) - + after (fn) { + return this.on('finish', fn) } /* @@ -198,45 +169,34 @@ export default class Runner extends EventTarget { Control how the animation plays */ - time ( time ) { - - if ( time == null ) { - + time (time) { + if (time == null) { return this._time - } let dt = time - this._time - this.step( dt ) + this.step(dt) return this - } duration () { - - return this._times * ( this._wait + this._duration ) - this._wait - + return this._times * (this._wait + this._duration) - this._wait } - loops ( p ) { - + loops (p) { var loopDuration = this._duration + this._wait - if ( p == null ) { - - var loopsDone = Math.floor( this._time / loopDuration ) - var relativeTime = ( this._time - loopsDone * loopDuration ) + if (p == null) { + var loopsDone = Math.floor(this._time / loopDuration) + var relativeTime = (this._time - loopsDone * loopDuration) var position = relativeTime / this._duration - return Math.min( loopsDone + position, this._times ) - + return Math.min(loopsDone + position, this._times) } - var whole = Math.floor( p ) + var whole = Math.floor(p) var partial = p % 1 var time = loopDuration * whole + this._duration * partial - return this.time( time ) - + return this.time(time) } - position ( p ) { - + position (p) { // Get all of the variables we need var x = this._time var d = this._duration @@ -246,8 +206,7 @@ export default class Runner extends EventTarget { var r = this._reverse var position - if ( p == null ) { - + 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 @@ -256,49 +215,40 @@ export default class Runner extends EventTarget { */ // Figure out the value without thinking about the start or end time - 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 - var clipped = Math.max( Math.min( uncliped, 1 ), 0 ) + 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 + var clipped = Math.max(Math.min(uncliped, 1), 0) return clipped - } // Figure out the value by incorporating the start time - var endTime = t * ( w + d ) - w - position = x <= 0 ? Math.round( f( 1e-5 ) ) - : x < endTime ? f( x ) - : Math.round( f( endTime - 1e-5 ) ) + var endTime = t * (w + d) - w + position = x <= 0 ? Math.round(f(1e-5)) + : x < endTime ? f(x) + : Math.round(f(endTime - 1e-5)) return position - } // 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 forwards = ( swingForward && !r ) || ( r && swingForward ) - position = loopsDone + ( forwards ? p : 1 - p ) - return this.loops( position ) - + var loopsDone = Math.floor(this.loops()) + var swingForward = s && (loopsDone % 2 === 0) + var forwards = (swingForward && !r) || (r && swingForward) + position = loopsDone + (forwards ? p : 1 - p) + return this.loops(position) } - progress ( p ) { - - if ( p == null ) { - - return Math.min( 1, this._time / this.duration() ) - + progress (p) { + if (p == null) { + return Math.min(1, this._time / this.duration()) } - return this.time( p * this.duration() ) - + return this.time(p * this.duration()) } - step ( dt ) { - + step (dt) { // If we are inactive, this stepper just gets skipped - if ( !this.enabled ) return this + if (!this.enabled) return this // Update the time and get the new position dt = dt == null ? 16 : dt @@ -314,10 +264,8 @@ export default class Runner extends EventTarget { var justStarted = this._lastTime < 0 && this._time > 0 var justFinished = this._lastTime < this._time && this.time > duration this._lastTime = this._time - if ( justStarted ) { - - this.fire( 'start', this ) - + if (justStarted) { + this.fire('start', this) } // Work out if the runner is finished set the done flag here so animations @@ -327,54 +275,41 @@ export default class Runner extends EventTarget { this.done = !declarative && !justFinished && this._time >= duration // Call initialise and the run function - if ( running || declarative ) { - - this._initialise( running ) + if (running || declarative) { + this._initialise(running) // clear the transforms on this runner so they dont get added again and again this.transforms = new Matrix() - var converged = this._run( declarative ? dt : position ) - this.fire( 'step', this ) - + var converged = this._run(declarative ? dt : position) + this.fire('step', this) } // correct the done flag here // declaritive animations itself know when they converged - this.done = this.done || ( converged && declarative ) - if ( this.done ) { - - this.fire( 'finish', this ) - + this.done = this.done || (converged && declarative) + if (this.done) { + this.fire('finish', this) } return this - } finish () { - - return this.step( Infinity ) - + return this.step(Infinity) } - reverse ( reverse ) { - + reverse (reverse) { this._reverse = reverse == null ? !this._reverse : reverse return this - } - ease ( fn ) { - - this._stepper = new Ease( fn ) + ease (fn) { + this._stepper = new Ease(fn) return this - } - active ( enabled ) { - - if ( enabled == null ) return this.enabled + active (enabled) { + if (enabled == null) return this.enabled this.enabled = enabled return this - } /* @@ -384,135 +319,102 @@ export default class Runner extends EventTarget { */ // Save a morpher to the morpher list so that we can retarget it later - _rememberMorpher ( method, morpher ) { - + _rememberMorpher (method, morpher) { this._history[method] = { morpher: morpher, 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 ( method, target ) { - - if ( this._history[method] ) { - + _tryRetarget (method, target) { + 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 ) - this._queue.splice( index, 1 ) + if (!this._history[method].caller.initialised) { + let index = this._queue.indexOf(this._history[method].caller) + this._queue.splice(index, 1) return false - } // 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 ) + if (this._history[method].caller.retarget) { + this._history[method].caller.retarget(target) // for everything else a simple morpher change is sufficient - } else { - - this._history[method].morpher.to( target ) - + this._history[method].morpher.to(target) } this._history[method].caller.finished = false var timeline = this.timeline() timeline && timeline._continue() return true - } return false - } // Run each initialise function in the runner if required - _initialise ( running ) { - + _initialise (running) { // If we aren't running, we shouldn't initialise when not declarative - if ( !running && !this._isDeclarative ) return + 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 needsIt = this._isDeclarative || (!current.initialised && running) running = !current.finished // Call the initialiser if we need to - if ( needsIt && running ) { - - current.initialiser.call( this ) + if (needsIt && running) { + current.initialiser.call(this) current.initialised = true - } - } - } // Run each run function for the position or dt given - _run ( positionOrDt ) { - + _run (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] // Run the function if its not finished, we keep track of the finished // flag for the sake of declarative _queue - var converged = current.runner.call( this, positionOrDt ) - current.finished = current.finished || ( converged === true ) + var converged = current.runner.call(this, positionOrDt) + current.finished = current.finished || (converged === true) allfinished = allfinished && current.finished - } // We report when all of the constructors are finished return allfinished - } - addTransform ( transform, index ) { - - this.transforms.lmultiplyO( transform ) + addTransform (transform, index) { + this.transforms.lmultiplyO(transform) return this - } clearTransform () { - this.transforms = new Matrix() return this - } // TODO: Keep track of all transformations so that deletion is faster clearTransformsFromQueue () { - - if ( !this.done ) { - - this._queue = this._queue.filter( ( item ) => { - + if (!this.done) { + this._queue = this._queue.filter((item) => { return !item.isTransform - - } ) - + }) } - } - static sanitise ( duration, delay, when ) { - + static sanitise (duration, delay, when) { // Initialise the default parameters var times = 1 var swing = false @@ -522,15 +424,13 @@ export default class Runner extends EventTarget { when = when || 'last' // If we have an object, unpack the values - if ( typeof duration === 'object' && !( duration instanceof Stepper ) ) { - + if (typeof duration === 'object' && !(duration instanceof Stepper)) { delay = duration.delay || delay when = duration.when || when swing = duration.swing || swing times = duration.times || times wait = duration.wait || wait duration = duration.duration || timeline.duration - } return { @@ -541,285 +441,215 @@ export default class Runner extends EventTarget { wait: wait, when: when } - } - } Runner.id = 0 class FakeRunner { - - constructor ( transforms = new Matrix(), id = -1, done = true ) { - + constructor (transforms = new Matrix(), id = -1, done = true) { this.transforms = transforms this.id = id this.done = done - } clearTransformsFromQueue () { } - } -extend( [ Runner, FakeRunner ], { - mergeWith ( runner ) { - +extend([ Runner, FakeRunner ], { + mergeWith (runner) { return new FakeRunner( - runner.transforms.lmultiply( this.transforms ), + runner.transforms.lmultiply(this.transforms), runner.id ) - } -} ) +}) // FakeRunner.emptyRunner = new FakeRunner() -const lmultiply = ( last, curr ) => last.lmultiplyO( curr ) -const getRunnerTransform = ( runner ) => runner.transforms +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.runners let netTransform = runners - .map( getRunnerTransform ) - .reduce( lmultiply, new Matrix() ) + .map(getRunnerTransform) + .reduce(lmultiply, new Matrix()) - this.transform( netTransform ) + this.transform(netTransform) this._transformationRunners.merge() - if ( this._transformationRunners.length() === 1 ) { - + if (this._transformationRunners.length() === 1) { this._frameId = null - } - } class RunnerArray { - constructor () { - this.runners = [] this.ids = [] - } - add ( runner ) { - - if ( this.runners.includes( runner ) ) return + add (runner) { + if (this.runners.includes(runner)) return let id = runner.id + 1 - let leftSibling = this.ids.reduce( ( last, curr ) => { - - if ( curr > last && curr < id ) return curr + let leftSibling = this.ids.reduce((last, curr) => { + if (curr > last && curr < id) return curr return last + }, 0) - }, 0 ) + let index = this.ids.indexOf(leftSibling) + 1 - let index = this.ids.indexOf( leftSibling ) + 1 - - this.ids.splice( index, 0, id ) - this.runners.splice( index, 0, runner ) + this.ids.splice(index, 0, id) + this.runners.splice(index, 0, runner) return this - } - getByID ( id ) { - - return this.runners[this.ids.indexOf( id + 1 )] - + 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 ) + 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 ) ) - + this.runners.forEach((runner, i) => { + if (lastRunner && runner.done && lastRunner.done) { + this.remove(runner.id) + this.edit(lastRunner.id, runner.mergeWith(lastRunner)) } lastRunner = runner - - } ) + }) return this - } - edit ( id, newRunner ) { - - let index = this.ids.indexOf( id + 1 ) - this.ids.splice( index, 1, id ) - this.runners.splice( index, 1, newRunner ) + 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 - } - clearBefore ( id ) { - - let deleteCnt = this.ids.indexOf( id + 1 ) || 1 - this.ids.splice( 0, deleteCnt, 0 ) - this.runners.splice( 0, deleteCnt, new FakeRunner() ) - .forEach( ( r ) => r.clearTransformsFromQueue() ) + clearBefore (id) { + let deleteCnt = this.ids.indexOf(id + 1) || 1 + this.ids.splice(0, deleteCnt, 0) + this.runners.splice(0, deleteCnt, new FakeRunner()) + .forEach((r) => r.clearTransformsFromQueue()) return this - } - } let frameId = 0 -registerMethods( { +registerMethods({ Element: { - animate ( duration, delay, when ) { - - var o = Runner.sanitise( duration, delay, when ) + animate (duration, delay, when) { + var o = Runner.sanitise(duration, delay, when) var timeline = this.timeline() - return new Runner( o.duration ) - .loop( o ) - .element( this ) - .timeline( timeline ) - .schedule( delay, when ) - + return new Runner(o.duration) + .loop(o) + .element(this) + .timeline(timeline) + .schedule(delay, when) }, - delay ( by, when ) { - - return this.animate( 0, by, when ) - + delay (by, when) { + return this.animate(0, by, when) }, // 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 ( currentRunner ) { - - this._transformationRunners.clearBefore( currentRunner.id ) - + _clearTransformRunnersBefore (currentRunner) { + this._transformationRunners.clearBefore(currentRunner.id) }, - _currentTransform ( current ) { - + _currentTransform (current) { 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 - .filter( ( runner ) => runner.id <= current.id ) - .map( getRunnerTransform ) - .reduce( lmultiply, new Matrix() ) - + .filter((runner) => runner.id <= current.id) + .map(getRunnerTransform) + .reduce(lmultiply, new Matrix()) }, - addRunner ( runner ) { - - this._transformationRunners.add( runner ) + addRunner (runner) { + this._transformationRunners.add(runner) Animator.transform_frame( - mergeTransforms.bind( this ), this._frameId + mergeTransforms.bind(this), this._frameId ) - }, _prepareRunner () { - - if ( this._frameId == null ) { - + if (this._frameId == null) { this._transformationRunners = new RunnerArray() - .add( new FakeRunner( new Matrix( this ) ) ) + .add(new FakeRunner(new Matrix(this))) this._frameId = frameId++ - } - } } -} ) - -extend( Runner, { - attr ( a, v ) { - - return this.styleAttr( 'attr', a, v ) +}) +extend(Runner, { + attr (a, v) { + return this.styleAttr('attr', a, v) }, // Add animatable styles - css ( s, v ) { - - return this.styleAttr( 'css', s, v ) - + css (s, v) { + return this.styleAttr('css', s, v) }, - styleAttr ( type, name, val ) { - + styleAttr (type, name, val) { // apply attributes individually - if ( typeof name === 'object' ) { - - for ( var key in val ) { - - this.styleAttr( type, key, val[key] ) - + if (typeof name === 'object') { + for (var key in val) { + this.styleAttr(type, key, val[key]) } - } - var morpher = new Morphable( this._stepper ).to( val ) - - this.queue( function () { - - morpher = morpher.from( this.element()[type]( name ) ) - - }, function ( pos ) { + var morpher = new Morphable(this._stepper).to(val) - this.element()[type]( name, morpher.at( pos ) ) + this.queue(function () { + morpher = morpher.from(this.element()[type](name)) + }, function (pos) { + this.element()[type](name, morpher.at(pos)) return morpher.done() - - } ) + }) return this - }, - zoom ( level, point ) { - - var morpher = new Morphable( this._stepper ).to( new SVGNumber( level ) ) - - this.queue( function () { + zoom (level, point) { + var morpher = new Morphable(this._stepper).to(new SVGNumber(level)) - morpher = morpher.from( this.zoom() ) - - }, function ( pos ) { - - this.element().zoom( morpher.at( pos ), point ) + this.queue(function () { + morpher = morpher.from(this.zoom()) + }, function (pos) { + this.element().zoom(morpher.at(pos), point) return morpher.done() - - } ) + }) return this - }, /** @@ -839,25 +669,22 @@ extend( Runner, { // - Note F(1) = T // 4. Now you get the delta matrix as a result: D = F * inv(M) - transform ( transforms, relative, affine ) { - + transform (transforms, relative, affine) { // If we have a declarative function, we should retarget it if possible relative = transforms.relative || relative - if ( this._isDeclarative && !relative && this._tryRetarget( 'transform', transforms ) ) { - + if (this._isDeclarative && !relative && this._tryRetarget('transform', transforms)) { return this - } // Parse the parameters - var isMatrix = Matrix.isMatrixLike( transforms ) + var isMatrix = Matrix.isMatrixLike(transforms) affine = transforms.affine != null ? transforms.affine - : ( affine != null ? affine : !isMatrix ) + : (affine != null ? affine : !isMatrix) // Create a morepher and set its type - const morpher = new Morphable( this._stepper ) - .type( affine ? TransformBag : Matrix ) + const morpher = new Morphable(this._stepper) + .type(affine ? TransformBag : Matrix) let origin let element @@ -866,42 +693,36 @@ extend( Runner, { let startTransform function setup () { - // make sure element and origin is defined element = element || this.element() - origin = origin || getOrigin( transforms, element ) + origin = origin || getOrigin(transforms, element) - startTransform = new Matrix( relative ? undefined : element ) + startTransform = new Matrix(relative ? undefined : element) // add the runner to the element so it can merge transformations - element.addRunner( this ) + element.addRunner(this) // Deactivate all transforms that have run so far if we are absolute - if ( !relative ) { - - element._clearTransformRunnersBefore( this ) - + if (!relative) { + element._clearTransformRunnersBefore(this) } - } - function run ( pos ) { - + 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() + if (!relative) this.clearTransform() - let { x, y } = new Point( origin ).transform( element._currentTransform( this ) ) + let { x, y } = new Point(origin).transform(element._currentTransform(this)) - let target = new Matrix( { ...transforms, origin: [ x, y ] } ) + let target = new Matrix({ ...transforms, origin: [ x, y ] }) let start = this._isDeclarative && current ? current : startTransform - if ( affine ) { - - target = target.decompose( x, y ) - start = start.decompose( x, y ) + if (affine) { + target = target.decompose(x, y) + start = start.decompose(x, y) // Get the current and target angle as it was set const rTarget = target.rotate @@ -909,285 +730,212 @@ extend( 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 shortest = Math.min( ...distances ) - const index = distances.indexOf( shortest ) + const distances = possibilities.map(a => Math.abs(a - rCurrent)) + const shortest = Math.min(...distances) + const index = distances.indexOf(shortest) target.rotate = possibilities[index] - } - if ( relative ) { - + if (relative) { // we have to be careful here not to overwrite the rotation // with the rotate method of Matrix - if ( !isMatrix ) { - + if (!isMatrix) { target.rotate = transforms.rotate || 0 - } - if ( this._isDeclarative && currentAngle ) { - + if (this._isDeclarative && currentAngle) { start.rotate = currentAngle - } - } - morpher.from( start ) - morpher.to( target ) + morpher.from(start) + morpher.to(target) - let affineParameters = morpher.at( pos ) + let affineParameters = morpher.at(pos) currentAngle = affineParameters.rotate - current = new Matrix( affineParameters ) + current = new Matrix(affineParameters) - this.addTransform( current ) + this.addTransform(current) return morpher.done() - } - function retarget ( newTransforms ) { - + 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 transforms = { ...newTransforms, origin } - } - this.queue( setup, run, retarget, true ) - this._isDeclarative && this._rememberMorpher( 'transform', morpher ) + this.queue(setup, run, retarget, true) + this._isDeclarative && this._rememberMorpher('transform', morpher) return this - }, // Animatable x-axis - x ( x, relative ) { - - return this._queueNumber( 'x', x ) - + x (x, relative) { + return this._queueNumber('x', x) }, // Animatable y-axis - y ( y ) { - - return this._queueNumber( 'y', y ) - + y (y) { + return this._queueNumber('y', y) }, - dx ( x ) { - - return this._queueNumberDelta( 'x', x ) - + dx (x) { + return this._queueNumberDelta('x', x) }, - dy ( y ) { - - return this._queueNumberDelta( 'y', y ) - + dy (y) { + return this._queueNumberDelta('y', y) }, - _queueNumberDelta ( method, to ) { - - to = new SVGNumber( to ) + _queueNumberDelta (method, to) { + to = new SVGNumber(to) // Try to change the target if we have this method already registerd - if ( this._tryRetarget( method, to ) ) return this + if (this._tryRetarget(method, to)) return this // Make a morpher and queue the animation - var morpher = new Morphable( this._stepper ).to( to ) + var morpher = new Morphable(this._stepper).to(to) var from = null - this.queue( function () { - + this.queue(function () { from = this.element()[method]() - morpher.from( from ) - morpher.to( from + to ) - - }, function ( pos ) { - - this.element()[method]( morpher.at( pos ) ) + morpher.from(from) + morpher.to(from + to) + }, function (pos) { + this.element()[method](morpher.at(pos)) return morpher.done() - - }, function ( newTo ) { - - morpher.to( from + new SVGNumber( newTo ) ) - - } ) + }, function (newTo) { + morpher.to(from + new SVGNumber(newTo)) + }) // Register the morpher so that if it is changed again, we can retarget it - this._rememberMorpher( method, morpher ) + this._rememberMorpher(method, morpher) return this - }, - _queueObject ( method, to ) { - + _queueObject (method, to) { // Try to change the target if we have this method already registerd - if ( this._tryRetarget( method, to ) ) return this + if (this._tryRetarget(method, to)) return this // Make a morpher and queue the animation - var morpher = new Morphable( this._stepper ).to( to ) - this.queue( function () { - - morpher.from( this.element()[method]() ) - - }, function ( pos ) { - - this.element()[method]( morpher.at( pos ) ) + var morpher = new Morphable(this._stepper).to(to) + this.queue(function () { + morpher.from(this.element()[method]()) + }, 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 ) + this._rememberMorpher(method, morpher) return this - }, - _queueNumber ( method, value ) { - - return this._queueObject( method, new SVGNumber( value ) ) - + _queueNumber (method, value) { + return this._queueObject(method, new SVGNumber(value)) }, // Animatable center x-axis - cx ( x ) { - - return this._queueNumber( 'cx', x ) - + cx (x) { + return this._queueNumber('cx', x) }, // Animatable center y-axis - cy ( y ) { - - return this._queueNumber( 'cy', y ) - + cy (y) { + return this._queueNumber('cy', y) }, // Add animatable move - move ( x, y ) { - - return this.x( x ).y( y ) - + move (x, y) { + return this.x(x).y(y) }, // Add animatable center - center ( x, y ) { - - return this.cx( x ).cy( y ) - + center (x, y) { + return this.cx(x).cy(y) }, // Add animatable size - size ( width, height ) { - + size (width, height) { // animate bbox based size for all other elements var box - if ( !width || !height ) { - + if (!width || !height) { box = this._element.bbox() - } - if ( !width ) { - + if (!width) { width = box.width / box.height * height - } - if ( !height ) { - + if (!height) { height = box.height / box.width * width - } return this - .width( width ) - .height( height ) - + .width(width) + .height(height) }, // Add animatable width - width ( width ) { - - return this._queueNumber( 'width', width ) - + width (width) { + return this._queueNumber('width', width) }, // Add animatable height - height ( height ) { - - return this._queueNumber( 'height', height ) - + height (height) { + return this._queueNumber('height', height) }, // Add animatable plot - plot ( a, b, c, d ) { - + plot (a, b, c, d) { // Lines can be plotted with 4 arguments - if ( arguments.length === 4 ) { - - return this.plot( [ a, b, c, d ] ) - + if (arguments.length === 4) { + return this.plot([ a, b, c, d ]) } - var morpher = this._element.MorphArray().to( a ) - - this.queue( function () { - - morpher.from( this._element.array() ) + var morpher = this._element.MorphArray().to(a) - }, function ( pos ) { - - this._element.plot( morpher.at( pos ) ) - - } ) + this.queue(function () { + morpher.from(this._element.array()) + }, function (pos) { + this._element.plot(morpher.at(pos)) + }) return this - }, // Add leading method - leading ( value ) { - - return this._queueNumber( 'leading', value ) - + leading (value) { + return this._queueNumber('leading', value) }, // Add animatable viewbox - viewbox ( x, y, width, height ) { - - return this._queueObject( 'viewbox', new Box( x, y, width, height ) ) - + viewbox (x, y, width, height) { + return this._queueObject('viewbox', new Box(x, y, width, height)) }, - update ( o ) { - - if ( typeof o !== 'object' ) { - - return this.update( { + update (o) { + if (typeof o !== 'object') { + return this.update({ offset: arguments[0], color: arguments[1], opacity: arguments[2] - } ) - + }) } - if ( o.opacity != null ) this.attr( 'stop-opacity', o.opacity ) - if ( o.color != null ) this.attr( 'stop-color', o.color ) - if ( o.offset != null ) this.attr( 'offset', o.offset ) + if (o.opacity != null) this.attr('stop-opacity', o.opacity) + if (o.color != null) this.attr('stop-color', o.color) + if (o.offset != null) this.attr('offset', o.offset) return this - } -} ) +}) -extend( Runner, { rx, ry, from, to } ) +extend(Runner, { rx, ry, from, to }) |