Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Chart.Animation/animations/Tooltip importable #5382

Merged
merged 1 commit into from Apr 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .htmllintrc
@@ -1,5 +1,6 @@
{
"indent-style": "tabs",
"line-end-style": false,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@loicbourgois I had to disable this rule, else we can't run gulp lint on Windows with Git configured to AutoCrlf.

"attr-quote-style": "double",
"spec-char-escape": false,
"attr-bans": [
Expand Down
5 changes: 3 additions & 2 deletions src/chart.js
Expand Up @@ -8,6 +8,8 @@ Chart.helpers = require('./helpers/index');
// @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests!
require('./core/core.helpers')(Chart);

Chart.Animation = require('./core/core.animation');
Chart.animationService = require('./core/core.animations');
Chart.defaults = require('./core/core.defaults');
Chart.Element = require('./core/core.element');
Chart.elements = require('./elements/index');
Expand All @@ -16,13 +18,12 @@ Chart.layouts = require('./core/core.layouts');
Chart.platform = require('./platforms/platform');
Chart.plugins = require('./core/core.plugins');
Chart.Ticks = require('./core/core.ticks');
Chart.Tooltip = require('./core/core.tooltip');

require('./core/core.animation')(Chart);
require('./core/core.controller')(Chart);
require('./core/core.datasetController')(Chart);
require('./core/core.scaleService')(Chart);
require('./core/core.scale')(Chart);
require('./core/core.tooltip')(Chart);

require('./scales/scale.linearbase')(Chart);
require('./scales/scale.category')(Chart);
Expand Down
201 changes: 36 additions & 165 deletions src/core/core.animation.js
@@ -1,172 +1,43 @@
/* global window: false */
'use strict';

var defaults = require('./core.defaults');
var Element = require('./core.element');
var helpers = require('../helpers/index');

defaults._set('global', {
animation: {
duration: 1000,
easing: 'easeOutQuart',
onProgress: helpers.noop,
onComplete: helpers.noop
}
});

module.exports = function(Chart) {

Chart.Animation = Element.extend({
chart: null, // the animation associated chart instance
currentStep: 0, // the current animation step
numSteps: 60, // default number of steps
easing: '', // the easing to use for this animation
render: null, // render function used by the animation service

onAnimationProgress: null, // user specified callback to fire on each step of the animation
onAnimationComplete: null, // user specified callback to fire when the animation finishes
});

Chart.animationService = {
frameDuration: 17,
animations: [],
dropFrames: 0,
request: null,

/**
* @param {Chart} chart - The chart to animate.
* @param {Chart.Animation} animation - The animation that we will animate.
* @param {Number} duration - The animation duration in ms.
* @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
*/
addAnimation: function(chart, animation, duration, lazy) {
var animations = this.animations;
var i, ilen;

animation.chart = chart;

if (!lazy) {
chart.animating = true;
}

for (i = 0, ilen = animations.length; i < ilen; ++i) {
if (animations[i].chart === chart) {
animations[i] = animation;
return;
}
}

animations.push(animation);

// If there are no animations queued, manually kickstart a digest, for lack of a better word
if (animations.length === 1) {
this.requestAnimationFrame();
}
},

cancelAnimation: function(chart) {
var index = helpers.findIndex(this.animations, function(animation) {
return animation.chart === chart;
});

if (index !== -1) {
this.animations.splice(index, 1);
chart.animating = false;
}
},

requestAnimationFrame: function() {
var me = this;
if (me.request === null) {
// Skip animation frame requests until the active one is executed.
// This can happen when processing mouse events, e.g. 'mousemove'
// and 'mouseout' events will trigger multiple renders.
me.request = helpers.requestAnimFrame.call(window, function() {
me.request = null;
me.startDigest();
});
}
},

/**
* @private
*/
startDigest: function() {
var me = this;
var startTime = Date.now();
var framesToDrop = 0;
var exports = module.exports = Element.extend({
chart: null, // the animation associated chart instance
currentStep: 0, // the current animation step
numSteps: 60, // default number of steps
easing: '', // the easing to use for this animation
render: null, // render function used by the animation service

if (me.dropFrames > 1) {
framesToDrop = Math.floor(me.dropFrames);
me.dropFrames = me.dropFrames % 1;
}

me.advance(1 + framesToDrop);

var endTime = Date.now();

me.dropFrames += (endTime - startTime) / me.frameDuration;

// Do we have more stuff to animate?
if (me.animations.length > 0) {
me.requestAnimationFrame();
}
},

/**
* @private
*/
advance: function(count) {
var animations = this.animations;
var animation, chart;
var i = 0;

while (i < animations.length) {
animation = animations[i];
chart = animation.chart;

animation.currentStep = (animation.currentStep || 0) + count;
animation.currentStep = Math.min(animation.currentStep, animation.numSteps);

helpers.callback(animation.render, [chart, animation], chart);
helpers.callback(animation.onAnimationProgress, [animation], chart);

if (animation.currentStep >= animation.numSteps) {
helpers.callback(animation.onAnimationComplete, [animation], chart);
chart.animating = false;
animations.splice(i, 1);
} else {
++i;
}
}
}
};

/**
* Provided for backward compatibility, use Chart.Animation instead
* @prop Chart.Animation#animationObject
* @deprecated since version 2.6.0
* @todo remove at version 3
*/
Object.defineProperty(Chart.Animation.prototype, 'animationObject', {
get: function() {
return this;
}
});
onAnimationProgress: null, // user specified callback to fire on each step of the animation
onAnimationComplete: null, // user specified callback to fire when the animation finishes
});

/**
* Provided for backward compatibility, use Chart.Animation#chart instead
* @prop Chart.Animation#chartInstance
* @deprecated since version 2.6.0
* @todo remove at version 3
*/
Object.defineProperty(Chart.Animation.prototype, 'chartInstance', {
get: function() {
return this.chart;
},
set: function(value) {
this.chart = value;
}
});
// DEPRECATIONS

/**
* Provided for backward compatibility, use Chart.Animation instead
* @prop Chart.Animation#animationObject
* @deprecated since version 2.6.0
* @todo remove at version 3
*/
Object.defineProperty(exports.prototype, 'animationObject', {
get: function() {
return this;
}
});

};
/**
* Provided for backward compatibility, use Chart.Animation#chart instead
* @prop Chart.Animation#chartInstance
* @deprecated since version 2.6.0
* @todo remove at version 3
*/
Object.defineProperty(exports.prototype, 'chartInstance', {
get: function() {
return this.chart;
},
set: function(value) {
this.chart = value;
}
});
129 changes: 129 additions & 0 deletions src/core/core.animations.js
@@ -0,0 +1,129 @@
/* global window: false */
'use strict';

var defaults = require('./core.defaults');
var helpers = require('../helpers/index');

defaults._set('global', {
animation: {
duration: 1000,
easing: 'easeOutQuart',
onProgress: helpers.noop,
onComplete: helpers.noop
}
});

module.exports = {
frameDuration: 17,
animations: [],
dropFrames: 0,
request: null,

/**
* @param {Chart} chart - The chart to animate.
* @param {Chart.Animation} animation - The animation that we will animate.
* @param {Number} duration - The animation duration in ms.
* @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
*/
addAnimation: function(chart, animation, duration, lazy) {
var animations = this.animations;
var i, ilen;

animation.chart = chart;

if (!lazy) {
chart.animating = true;
}

for (i = 0, ilen = animations.length; i < ilen; ++i) {
if (animations[i].chart === chart) {
animations[i] = animation;
return;
}
}

animations.push(animation);

// If there are no animations queued, manually kickstart a digest, for lack of a better word
if (animations.length === 1) {
this.requestAnimationFrame();
}
},

cancelAnimation: function(chart) {
var index = helpers.findIndex(this.animations, function(animation) {
return animation.chart === chart;
});

if (index !== -1) {
this.animations.splice(index, 1);
chart.animating = false;
}
},

requestAnimationFrame: function() {
var me = this;
if (me.request === null) {
// Skip animation frame requests until the active one is executed.
// This can happen when processing mouse events, e.g. 'mousemove'
// and 'mouseout' events will trigger multiple renders.
me.request = helpers.requestAnimFrame.call(window, function() {
me.request = null;
me.startDigest();
});
}
},

/**
* @private
*/
startDigest: function() {
var me = this;
var startTime = Date.now();
var framesToDrop = 0;

if (me.dropFrames > 1) {
framesToDrop = Math.floor(me.dropFrames);
me.dropFrames = me.dropFrames % 1;
}

me.advance(1 + framesToDrop);

var endTime = Date.now();

me.dropFrames += (endTime - startTime) / me.frameDuration;

// Do we have more stuff to animate?
if (me.animations.length > 0) {
me.requestAnimationFrame();
}
},

/**
* @private
*/
advance: function(count) {
var animations = this.animations;
var animation, chart;
var i = 0;

while (i < animations.length) {
animation = animations[i];
chart = animation.chart;

animation.currentStep = (animation.currentStep || 0) + count;
animation.currentStep = Math.min(animation.currentStep, animation.numSteps);

helpers.callback(animation.render, [chart, animation], chart);
helpers.callback(animation.onAnimationProgress, [animation], chart);

if (animation.currentStep >= animation.numSteps) {
helpers.callback(animation.onAnimationComplete, [animation], chart);
chart.animating = false;
animations.splice(i, 1);
} else {
++i;
}
}
}
};