Implement possibility to set and remove a steps range
This commit is contained in:
parent
6f35d6399a
commit
b6169fb31a
4
Makefile
4
Makefile
@ -7,7 +7,7 @@ JS_CLIENT_FILES= lib/torque/*.js \
|
|||||||
lib/torque/gmaps/*.js \
|
lib/torque/gmaps/*.js \
|
||||||
lib/torque/leaflet/leaflet_tileloader_mixin.js \
|
lib/torque/leaflet/leaflet_tileloader_mixin.js \
|
||||||
lib/torque/leaflet/canvas_layer.js \
|
lib/torque/leaflet/canvas_layer.js \
|
||||||
lib/torque/leaflet/torque.js
|
lib/torque/leaflet/torque.js
|
||||||
|
|
||||||
all: dist/torque.js dist/torque.full.js add-header
|
all: dist/torque.js dist/torque.full.js add-header
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ test-acceptance: clean-results
|
|||||||
|
|
||||||
test-all: test test-acceptance
|
test-all: test test-acceptance
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf dist
|
rm -rf dist
|
||||||
|
|
||||||
.PHONY: clean dist_folder
|
.PHONY: clean dist_folder
|
||||||
|
24
lib/torque/animator-steps-range.js
Normal file
24
lib/torque/animator-steps-range.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Abstract handler for animator steps
|
||||||
|
*/
|
||||||
|
var AnimatorStepsRange = function(start, end) {
|
||||||
|
if (start < 0) throw new Error('start must be a positive number');
|
||||||
|
if (start >= end) throw new Error('start must be smaller than end');
|
||||||
|
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
};
|
||||||
|
|
||||||
|
AnimatorStepsRange.prototype = {
|
||||||
|
|
||||||
|
diff: function() {
|
||||||
|
return this.end - this.start;
|
||||||
|
},
|
||||||
|
|
||||||
|
isLast: function(step) {
|
||||||
|
// round step into an integer, to be able to compare number as expected (also converts bad input to 0)
|
||||||
|
return (step | 0) === this.end;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = AnimatorStepsRange;
|
@ -1,4 +1,5 @@
|
|||||||
var torque = require('./');
|
var torque = require('./');
|
||||||
|
var StepsRange = require('./animator-steps-range');
|
||||||
|
|
||||||
var requestAnimationFrame = global.requestAnimationFrame
|
var requestAnimationFrame = global.requestAnimationFrame
|
||||||
|| global.mozRequestAnimationFrame
|
|| global.mozRequestAnimationFrame
|
||||||
@ -35,18 +36,16 @@ var cancelAnimationFrame = global.cancelAnimationFrame
|
|||||||
loop: options.loop === undefined ? true : options.loop
|
loop: options.loop === undefined ? true : options.loop
|
||||||
}, this.options);
|
}, this.options);
|
||||||
|
|
||||||
this.rescale();
|
this.steps(options.steps);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Animator.prototype = {
|
Animator.prototype = {
|
||||||
|
|
||||||
start: function() {
|
start: function() {
|
||||||
this.running = true;
|
this.running = true;
|
||||||
requestAnimationFrame(this._tick);
|
requestAnimationFrame(this._tick);
|
||||||
this.options.onStart && this.options.onStart();
|
this.options.onStart && this.options.onStart();
|
||||||
if(this.options.steps === 1){
|
if (this.stepsRange().diff() === 1) {
|
||||||
this.running = false;
|
this.running = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -57,7 +56,7 @@ var cancelAnimationFrame = global.cancelAnimationFrame
|
|||||||
|
|
||||||
stop: function() {
|
stop: function() {
|
||||||
this.pause();
|
this.pause();
|
||||||
this.time(0);
|
this.time(this.stepsRange().start);
|
||||||
this.options.onStop && this.options.onStop();
|
this.options.onStop && this.options.onStop();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -80,7 +79,7 @@ var cancelAnimationFrame = global.cancelAnimationFrame
|
|||||||
rescale: function() {
|
rescale: function() {
|
||||||
this.domainInv = torque.math.linear(this.options.animationDelay, this.options.animationDelay + this.options.animationDuration);
|
this.domainInv = torque.math.linear(this.options.animationDelay, this.options.animationDelay + this.options.animationDuration);
|
||||||
this.domain = this.domainInv.invert();
|
this.domain = this.domainInv.invert();
|
||||||
this.range = torque.math.linear(0, this.options.steps);
|
this.range = torque.math.linear(0, this._defaultStepsRange.end);
|
||||||
this.rangeInv = this.range.invert();
|
this.rangeInv = this.range.invert();
|
||||||
this.time(this._time);
|
this.time(this._time);
|
||||||
this.running? this.start(): this.pause();
|
this.running? this.start(): this.pause();
|
||||||
@ -99,9 +98,34 @@ var cancelAnimationFrame = global.cancelAnimationFrame
|
|||||||
|
|
||||||
steps: function(_) {
|
steps: function(_) {
|
||||||
this.options.steps = _;
|
this.options.steps = _;
|
||||||
|
this._defaultStepsRange = new StepsRange(0, _);
|
||||||
return this.rescale();
|
return this.rescale();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Returns or sets a (custom) steps range
|
||||||
|
// Setting a steps range must be within the full range
|
||||||
|
stepsRange: function(start, end) {
|
||||||
|
if (arguments.length === 2) {
|
||||||
|
if (start < this._defaultStepsRange.start) throw new Error('start must be within default steps range');
|
||||||
|
if (end > this._defaultStepsRange.end) throw new Error('end must be within default steps range');
|
||||||
|
|
||||||
|
this._customStepsRange = new StepsRange(start, end);
|
||||||
|
this.options.onStepsRange && this.options.onStepsRange();
|
||||||
|
|
||||||
|
// Change current step if it's outside the new custom range
|
||||||
|
var step = this.step() | 0; // round to an integer
|
||||||
|
if (step < start || step > end) {
|
||||||
|
this.step(start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this._customStepsRange || this._defaultStepsRange;
|
||||||
|
},
|
||||||
|
|
||||||
|
removeCustomStepsRange: function() {
|
||||||
|
this._customStepsRange = undefined;
|
||||||
|
this.options.onStepsRange && this.options.onStepsRange();
|
||||||
|
},
|
||||||
|
|
||||||
step: function(s) {
|
step: function(s) {
|
||||||
if(arguments.length === 0) return this.range(this.domain(this._time));
|
if(arguments.length === 0) return this.range(this.domain(this._time));
|
||||||
this._time = this.domainInv(this.rangeInv(s));
|
this._time = this.domainInv(this.rangeInv(s));
|
||||||
@ -121,13 +145,15 @@ var cancelAnimationFrame = global.cancelAnimationFrame
|
|||||||
delta = Math.min(this.options.maxDelta, delta);
|
delta = Math.min(this.options.maxDelta, delta);
|
||||||
this._t0 = t1;
|
this._t0 = t1;
|
||||||
this._time += delta;
|
this._time += delta;
|
||||||
if(this.step() >= this.options.steps) {
|
|
||||||
|
var stepsRange = this.stepsRange();
|
||||||
|
if (stepsRange.isLast(this.step())) {
|
||||||
if(!this.options.loop){
|
if(!this.options.loop){
|
||||||
// set time to max time
|
// set time to max time
|
||||||
this.time(this.options.animationDuration);
|
this.time(this.options.animationDuration);
|
||||||
this.pause();
|
this.pause();
|
||||||
} else {
|
} else {
|
||||||
this._time = 0;
|
this.step(stepsRange.start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(this.running) {
|
if(this.running) {
|
||||||
|
@ -43,6 +43,9 @@ function GMapsTorqueLayer(options) {
|
|||||||
},
|
},
|
||||||
onStart: function() {
|
onStart: function() {
|
||||||
self.fire('play');
|
self.fire('play');
|
||||||
|
},
|
||||||
|
onStepsRange: function() {
|
||||||
|
self.fire('change:stepsRange', self.animator.stepsRange());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -237,7 +240,7 @@ GMapsTorqueLayer.prototype = torque.extend({},
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* helper function, does the same than ``setKey`` but only
|
* helper function, does the same than ``setKey`` but only
|
||||||
* accepts scalars.
|
* accepts scalars.
|
||||||
*/
|
*/
|
||||||
setStep: function(time) {
|
setStep: function(time) {
|
||||||
@ -248,10 +251,10 @@ GMapsTorqueLayer.prototype = torque.extend({},
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* transform from animation step to Date object
|
* transform from animation step to Date object
|
||||||
* that contains the animation time
|
* that contains the animation time
|
||||||
*
|
*
|
||||||
* ``step`` should be between 0 and ``steps - 1``
|
* ``step`` should be between 0 and ``steps - 1``
|
||||||
*/
|
*/
|
||||||
stepToTime: function(step) {
|
stepToTime: function(step) {
|
||||||
if (!this.provider) return 0;
|
if (!this.provider) return 0;
|
||||||
@ -369,7 +372,7 @@ GMapsTorqueLayer.prototype = torque.extend({},
|
|||||||
}
|
}
|
||||||
return sum;
|
return sum;
|
||||||
},
|
},
|
||||||
|
|
||||||
error: function (callback) {
|
error: function (callback) {
|
||||||
this.options.errorCallback = callback;
|
this.options.errorCallback = callback;
|
||||||
return this;
|
return this;
|
||||||
@ -450,6 +453,18 @@ GMapsTiledTorqueLayer.prototype = torque.extend({}, CanvasTileLayer.prototype, {
|
|||||||
setCartoCSS: function(cartocss) {
|
setCartoCSS: function(cartocss) {
|
||||||
if (!this.renderer) throw new Error('renderer is not valid');
|
if (!this.renderer) throw new Error('renderer is not valid');
|
||||||
return this.renderer.setCartoCSS(cartocss);
|
return this.renderer.setCartoCSS(cartocss);
|
||||||
|
},
|
||||||
|
|
||||||
|
setStepsRange: function(start, end) {
|
||||||
|
this.animator.stepsRange(start, end);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeStepsRange: function() {
|
||||||
|
this.animator.removeCustomStepsRange();
|
||||||
|
},
|
||||||
|
|
||||||
|
getStepsRange: function() {
|
||||||
|
return this.animator.stepsRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -51,6 +51,9 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
|||||||
},
|
},
|
||||||
onStart: function() {
|
onStart: function() {
|
||||||
self.fire('play');
|
self.fire('play');
|
||||||
|
},
|
||||||
|
onStepsRange: function() {
|
||||||
|
self.fire('change:stepsRange', self.animator.stepsRange());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -428,5 +431,17 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
|||||||
|
|
||||||
invalidate: function() {
|
invalidate: function() {
|
||||||
this.provider.reload();
|
this.provider.reload();
|
||||||
|
},
|
||||||
|
|
||||||
|
setStepsRange: function(start, end) {
|
||||||
|
this.animator.stepsRange(start, end);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeStepsRange: function() {
|
||||||
|
this.animator.removeCustomStepsRange();
|
||||||
|
},
|
||||||
|
|
||||||
|
getStepsRange: function() {
|
||||||
|
return this.animator.stepsRange();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
34
test/animator-steps-range.js
Normal file
34
test/animator-steps-range.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
var AnimatorStepsRange = require('../lib/torque/animator-steps-range');
|
||||||
|
|
||||||
|
QUnit.module('animator-steps-range');
|
||||||
|
|
||||||
|
test('start and end props are available', function(assert) {
|
||||||
|
var stepsRange = validStepsRange();
|
||||||
|
assert.equal(stepsRange.start, 0);
|
||||||
|
assert.equal(stepsRange.end, 4);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('.lastStep returns true if given last step', function(assert) {
|
||||||
|
var stepsRange = validStepsRange();
|
||||||
|
assert.ok(stepsRange.isLast(stepsRange.end));
|
||||||
|
|
||||||
|
assert.notOk(stepsRange.isLast(3));
|
||||||
|
assert.notOk(stepsRange.isLast(42));
|
||||||
|
assert.notOk(stepsRange.isLast(true));
|
||||||
|
assert.notOk(stepsRange.isLast());
|
||||||
|
assert.notOk(stepsRange.isLast('whatever'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('.diff returns the steps between start and end', function(assert) {
|
||||||
|
var stepsRange = validStepsRange();
|
||||||
|
assert.equal(stepsRange.diff(), 4);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('throws error in inconsistent range', function(assert) {
|
||||||
|
assert.throws(function() { new AnimatorStepsRange(4, 3) });
|
||||||
|
assert.throws(function() { new AnimatorStepsRange(4, 4) });
|
||||||
|
});
|
||||||
|
|
||||||
|
function validStepsRange() {
|
||||||
|
return new AnimatorStepsRange(0, 4);
|
||||||
|
}
|
@ -39,12 +39,66 @@ test("onStart runs properly", function(assert){
|
|||||||
animator.stop();
|
animator.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("stop should take the pointer to position zero", function(assert){
|
test(".stepsRange sets a custom range with valid input", function(assert){
|
||||||
|
var animator = new torque.Animator(function(){}, {steps: 500, animationDuration: 2});
|
||||||
|
var customStepsRange = animator.stepsRange(101, 202);
|
||||||
|
assert.ok(customStepsRange);
|
||||||
|
assert.equal(customStepsRange.start, 101);
|
||||||
|
assert.equal(customStepsRange.end, 202);
|
||||||
|
|
||||||
|
var didCallOnStepsRange = false;
|
||||||
|
var animator = new torque.Animator(function(){}, {steps: 500, animationDuration: 2,
|
||||||
|
onStepsRange: function() {
|
||||||
|
didCallOnStepsRange = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
animator.stepsRange(101, 202);
|
||||||
|
assert.ok(didCallOnStepsRange);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(".stepsRange throws error if given range is outside default range", function(assert){
|
||||||
|
var animator = new torque.Animator(function(){}, {steps: 500, animationDuration: 2});
|
||||||
|
assert.throws(function() { animator.stepsRange(1, 501) });
|
||||||
|
assert.throws(function() { animator.stepsRange(-1, 500) });
|
||||||
|
assert.throws(function() { animator.stepsRange(-1, 9000) });
|
||||||
|
});
|
||||||
|
|
||||||
|
test(".removeCustomStepsRange should remove any custom steps range", function(assert){
|
||||||
|
var animator = new torque.Animator(function(){}, {steps: 500, animationDuration: 2});
|
||||||
|
animator.removeCustomStepsRange();
|
||||||
|
animator.stepsRange(101, 202);
|
||||||
|
var customStepsRange = animator.stepsRange();
|
||||||
|
animator.removeCustomStepsRange();
|
||||||
|
var defaultStepsRange = animator.stepsRange();
|
||||||
|
assert.ok(defaultStepsRange);
|
||||||
|
assert.notEqual(defaultStepsRange, customStepsRange);
|
||||||
|
assert.equal(defaultStepsRange.start, 0);
|
||||||
|
assert.equal(defaultStepsRange.end, 500);
|
||||||
|
|
||||||
|
var didCallOnStepsRange = false;
|
||||||
|
var animator = new torque.Animator(function(){}, {steps: 500, animationDuration: 2,
|
||||||
|
onStepsRange: function() {
|
||||||
|
didCallOnStepsRange = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
animator.stepsRange(101, 202);
|
||||||
|
animator.removeCustomStepsRange();
|
||||||
|
assert.ok(didCallOnStepsRange);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("stop should take the pointer to position zero by default", function(assert){
|
||||||
var animator = new torque.Animator(function(){}, {steps: 500, animationDuration: 2});
|
var animator = new torque.Animator(function(){}, {steps: 500, animationDuration: 2});
|
||||||
animator.stop()
|
animator.stop()
|
||||||
assert.equal(animator._time, 0);
|
assert.equal(animator._time, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("stop should take the pointer to start position for custom range", function(assert){
|
||||||
|
var animator = new torque.Animator(function(){}, {steps: 500, animationDuration: 2});
|
||||||
|
animator.stepsRange(42, 137);
|
||||||
|
animator.stop()
|
||||||
|
assert.equal(animator._time, 42);
|
||||||
|
});
|
||||||
|
|
||||||
test("stop should call onStop", function(assert){
|
test("stop should call onStop", function(assert){
|
||||||
var animator = new torque.Animator(function(){}, {steps: 500, animationDuration: 2});
|
var animator = new torque.Animator(function(){}, {steps: 500, animationDuration: 2});
|
||||||
animator.options.onStop = function(){
|
animator.options.onStop = function(){
|
||||||
@ -61,14 +115,29 @@ test("altering steps should rescale", function(assert){
|
|||||||
assert.ok(animator.rescale.calledOnce);
|
assert.ok(animator.rescale.calledOnce);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("tick should set time to zero if steps are bigger than range", function(assert){
|
test("tick should set time to zero if steps are bigger than default range", function(assert){
|
||||||
var done = assert.async();
|
var done = assert.async();
|
||||||
var animatorb = new torque.Animator(function(){}, {steps: 500, animationDuration: 2});
|
var animatorb = new torque.Animator(function(){}, {steps: 500, animationDuration: 2});
|
||||||
animatorb.start();
|
animatorb.start();
|
||||||
animatorb.step(800);
|
animatorb.step(800);
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
console.log(animatorb.step());
|
console.log(animatorb.step());
|
||||||
assert.ok(animatorb.step() < 800);
|
assert.ok(animatorb.step() | 0 === 0);
|
||||||
|
done();
|
||||||
|
}, 20);
|
||||||
|
animatorb.pause();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("tick should set time to start step if steps are bigger than custom range", function(assert){
|
||||||
|
var done = assert.async();
|
||||||
|
var animatorb = new torque.Animator(function(){}, {steps: 500, animationDuration: 2});
|
||||||
|
animatorb.start();
|
||||||
|
animatorb.step(800);
|
||||||
|
animatorb.stepsRange(42, 137);
|
||||||
|
setTimeout(function(){
|
||||||
|
console.log(animatorb.step());
|
||||||
|
// round step to an integer
|
||||||
|
assert.ok(animatorb.step() | 0 === 42);
|
||||||
done();
|
done();
|
||||||
}, 20);
|
}, 20);
|
||||||
animatorb.pause();
|
animatorb.pause();
|
||||||
@ -80,5 +149,4 @@ test("tick should pause animation on end if loop is disabled", function(assert){
|
|||||||
animator.toggle();
|
animator.toggle();
|
||||||
animator.step(600);
|
animator.step(600);
|
||||||
assert.equal(animator._time,animator.options.animationDuration);
|
assert.equal(animator._time,animator.options.animationDuration);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -9,3 +9,4 @@ require('./provider.windshaft.test');
|
|||||||
require('./provider.json');
|
require('./provider.json');
|
||||||
require('./request');
|
require('./request');
|
||||||
require('./animator');
|
require('./animator');
|
||||||
|
require('./animator-steps-range');
|
||||||
|
Loading…
Reference in New Issue
Block a user