cytoscape
Version:
Graph theory (a.k.a. network) library for analysis and visualisation
261 lines (194 loc) • 4.73 kB
JavaScript
import * as util from './util';
import * as is from './is';
import Promise from './promise';
let Animation = function( target, opts, opts2 ){
let isCore = is.core(target);
let isEle = !isCore;
let _p = this._private = util.extend( {
duration: 1000
}, opts, opts2 );
_p.target = target;
_p.style = _p.style || _p.css;
_p.started = false;
_p.playing = false;
_p.hooked = false;
_p.applying = false;
_p.progress = 0;
_p.completes = [];
_p.frames = [];
if( _p.complete && is.fn( _p.complete ) ){
_p.completes.push( _p.complete );
}
if( isEle ){
let pos = target.position();
_p.startPosition = _p.startPosition || {
x: pos.x,
y: pos.y
};
_p.startStyle = _p.startStyle || target.cy().style().getAnimationStartStyle( target, _p.style );
}
if( isCore ){
let pan = target.pan();
_p.startPan = {
x: pan.x,
y: pan.y
};
_p.startZoom = target.zoom();
}
// for future timeline/animations impl
this.length = 1;
this[0] = this;
};
let anifn = Animation.prototype;
util.extend( anifn, {
instanceString: function(){ return 'animation'; },
hook: function(){
let _p = this._private;
if( !_p.hooked ){
// add to target's animation queue
let q;
let tAni = _p.target._private.animation;
if( _p.queue ){
q = tAni.queue;
} else {
q = tAni.current;
}
q.push( this );
// add to the animation loop pool
if( is.elementOrCollection( _p.target ) ){
_p.target.cy().addToAnimationPool( _p.target );
}
_p.hooked = true;
}
return this;
},
play: function(){
let _p = this._private;
// autorewind
if( _p.progress === 1 ){
_p.progress = 0;
}
_p.playing = true;
_p.started = false; // needs to be started by animation loop
_p.stopped = false;
this.hook();
// the animation loop will start the animation...
return this;
},
playing: function(){
return this._private.playing;
},
apply: function(){
let _p = this._private;
_p.applying = true;
_p.started = false; // needs to be started by animation loop
_p.stopped = false;
this.hook();
// the animation loop will apply the animation at this progress
return this;
},
applying: function(){
return this._private.applying;
},
pause: function(){
let _p = this._private;
_p.playing = false;
_p.started = false;
return this;
},
stop: function(){
let _p = this._private;
_p.playing = false;
_p.started = false;
_p.stopped = true; // to be removed from animation queues
return this;
},
rewind: function(){
return this.progress( 0 );
},
fastforward: function(){
return this.progress( 1 );
},
time: function( t ){
let _p = this._private;
if( t === undefined ){
return _p.progress * _p.duration;
} else {
return this.progress( t / _p.duration );
}
},
progress: function( p ){
let _p = this._private;
let wasPlaying = _p.playing;
if( p === undefined ){
return _p.progress;
} else {
if( wasPlaying ){
this.pause();
}
_p.progress = p;
_p.started = false;
if( wasPlaying ){
this.play();
}
}
return this;
},
completed: function(){
return this._private.progress === 1;
},
reverse: function(){
let _p = this._private;
let wasPlaying = _p.playing;
if( wasPlaying ){
this.pause();
}
_p.progress = 1 - _p.progress;
_p.started = false;
let swap = function( a, b ){
let _pa = _p[ a ];
if( _pa == null ){ return; }
_p[ a ] = _p[ b ];
_p[ b ] = _pa;
};
swap( 'zoom', 'startZoom' );
swap( 'pan', 'startPan' );
swap( 'position', 'startPosition' );
// swap styles
if( _p.style ){
for( let i = 0; i < _p.style.length; i++ ){
let prop = _p.style[ i ];
let name = prop.name;
let startStyleProp = _p.startStyle[ name ];
_p.startStyle[ name ] = prop;
_p.style[ i ] = startStyleProp;
}
}
if( wasPlaying ){
this.play();
}
return this;
},
promise: function( type ){
let _p = this._private;
let arr;
switch( type ){
case 'frame':
arr = _p.frames;
break;
default:
case 'complete':
case 'completed':
arr = _p.completes;
}
return new Promise( function( resolve, reject ){
arr.push( function(){
resolve();
} );
} );
}
} );
anifn.complete = anifn.completed;
anifn.run = anifn.play;
anifn.running = anifn.playing;
export default Animation;