Add new dataset update and draw plugin hooks

In order to take full advantage of the new plugin hooks called before and after a dataset is drawn, all drawing operations must happen on stable meta data, so make sure that transitions are performed before.
This commit is contained in:
Simon Brunel
2017-02-18 11:58:45 +01:00
committed by Evert Timberg
parent cc90c5c643
commit 4741c6f09d
8 changed files with 190 additions and 51 deletions

1
.gitignore vendored
View File

@@ -9,4 +9,5 @@
.vscode
bower.json
*.log
*.swp

View File

@@ -248,19 +248,20 @@ module.exports = function(Chart) {
return yScale.getPixelForValue(value);
},
draw: function(ease) {
draw: function() {
var me = this;
var chart = me.chart;
var easingDecimal = ease || 1;
var metaData = me.getMeta().data;
var elements = me.getMeta().data;
var dataset = me.getDataset();
var i, len;
var ilen = elements.length;
var i = 0;
var d;
Chart.canvasHelpers.clipArea(chart.ctx, chart.chartArea);
for (i = 0, len = metaData.length; i < len; ++i) {
var d = dataset.data[i];
for (; i<ilen; ++i) {
d = dataset.data[i];
if (d !== null && d !== undefined && !isNaN(d)) {
metaData[i].transition(easingDecimal).draw();
elements[i].draw();
}
}
Chart.canvasHelpers.unclipArea(chart.ctx);

View File

@@ -280,29 +280,26 @@ module.exports = function(Chart) {
}
},
draw: function(ease) {
draw: function() {
var me = this;
var chart = me.chart;
var meta = me.getMeta();
var points = meta.data || [];
var easingDecimal = ease || 1;
var i, ilen;
var area = chart.chartArea;
var ilen = points.length;
var i = 0;
// Transition Point Locations
for (i=0, ilen=points.length; i<ilen; ++i) {
points[i].transition(easingDecimal);
}
Chart.canvasHelpers.clipArea(chart.ctx, area);
Chart.canvasHelpers.clipArea(chart.ctx, chart.chartArea);
// Transition and Draw the line
if (lineEnabled(me.getDataset(), chart.options)) {
meta.dataset.transition(easingDecimal).draw();
meta.dataset.draw();
}
Chart.canvasHelpers.unclipArea(chart.ctx);
// Draw the points
for (i=0, ilen=points.length; i<ilen; ++i) {
points[i].draw(chart.chartArea);
for (; i<ilen; ++i) {
points[i].draw(area);
}
},

View File

@@ -134,24 +134,6 @@ module.exports = function(Chart) {
});
},
draw: function(ease) {
var meta = this.getMeta();
var easingDecimal = ease || 1;
// Transition Point Locations
helpers.each(meta.data, function(point) {
point.transition(easingDecimal);
});
// Transition and Draw the line
meta.dataset.transition(easingDecimal).draw();
// Draw the points
helpers.each(meta.data, function(point) {
point.draw();
});
},
setHoverStyle: function(point) {
// Point
var dataset = this.chart.data.datasets[point._datasetIndex];

View File

@@ -409,12 +409,34 @@ module.exports = function(Chart) {
}
for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
me.getDatasetMeta(i).controller.update();
me.updateDataset(i);
}
plugins.notify(me, 'afterDatasetsUpdate');
},
/**
* Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`
* hook, in which case, plugins will not be called on `afterDatasetUpdate`.
* @private
*/
updateDataset: function(index) {
var me = this;
var meta = me.getDatasetMeta(index);
var args = {
meta: meta,
index: index
};
if (plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
return;
}
meta.controller.update();
plugins.notify(me, 'afterDatasetUpdate', [args]);
},
render: function(duration, lazy) {
var me = this;
@@ -467,6 +489,8 @@ module.exports = function(Chart) {
easingValue = 1;
}
me.transition(easingValue);
if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) {
return;
}
@@ -483,11 +507,26 @@ module.exports = function(Chart) {
me.drawDatasets(easingValue);
// Finally draw the tooltip
me.tooltip.transition(easingValue).draw();
me.tooltip.draw();
plugins.notify(me, 'afterDraw', [easingValue]);
},
/**
* @private
*/
transition: function(easingValue) {
var me = this;
for (var i=0, ilen=(me.data.datasets || []).length; i<ilen; ++i) {
if (me.isDatasetVisible(i)) {
me.getDatasetMeta(i).controller.transition(easingValue);
}
}
me.tooltip.transition(easingValue);
},
/**
* Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`
* hook, in which case, plugins will not be called on `afterDatasetsDraw`.
@@ -500,16 +539,39 @@ module.exports = function(Chart) {
return;
}
// Draw each dataset via its respective controller (reversed to support proper line stacking)
helpers.each(me.data.datasets, function(dataset, datasetIndex) {
if (me.isDatasetVisible(datasetIndex)) {
me.getDatasetMeta(datasetIndex).controller.draw(easingValue);
// Draw datasets reversed to support proper line stacking
for (var i=(me.data.datasets || []).length - 1; i >= 0; --i) {
if (me.isDatasetVisible(i)) {
me.drawDataset(i, easingValue);
}
}, me, true);
}
plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
},
/**
* Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`
* hook, in which case, plugins will not be called on `afterDatasetDraw`.
* @private
*/
drawDataset: function(index, easingValue) {
var me = this;
var meta = me.getDatasetMeta(index);
var args = {
meta: meta,
index: index,
easingValue: easingValue
};
if (plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
return;
}
meta.controller.draw(easingValue);
plugins.notify(me, 'afterDatasetDraw', [args]);
},
// Get the single element that was clicked on
// @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
getElementAtEvent: function(e) {

View File

@@ -208,12 +208,33 @@ module.exports = function(Chart) {
update: helpers.noop,
draw: function(ease) {
var easingDecimal = ease || 1;
var i, len;
var metaData = this.getMeta().data;
for (i = 0, len = metaData.length; i < len; ++i) {
metaData[i].transition(easingDecimal).draw();
transition: function(easingValue) {
var meta = this.getMeta();
var elements = meta.data || [];
var ilen = elements.length;
var i = 0;
for (; i<ilen; ++i) {
elements[i].transition(easingValue);
}
if (meta.dataset) {
meta.dataset.transition(easingValue);
}
},
draw: function() {
var meta = this.getMeta();
var elements = meta.data || [];
var ilen = elements.length;
var i = 0;
if (meta.dataset) {
meta.dataset.draw();
}
for (; i<ilen; ++i) {
elements[i].draw();
}
},

View File

@@ -209,6 +209,27 @@ module.exports = function(Chart) {
* @param {Object} options - The plugin options.
* @since version 2.1.5
*/
/**
* @method IPlugin#beforeDatasetUpdate
* @desc Called before updating the `chart` dataset at the given `args.index`. If any plugin
* returns `false`, the datasets update is cancelled until another `update` is triggered.
* @param {Chart} chart - The chart instance.
* @param {Object} args - The call arguments.
* @param {Object} args.index - The dataset index.
* @param {Number} args.meta - The dataset metadata.
* @param {Object} options - The plugin options.
* @returns {Boolean} `false` to cancel the chart datasets drawing.
*/
/**
* @method IPlugin#afterDatasetUpdate
* @desc Called after the `chart` datasets at the given `args.index` has been updated. Note
* that this hook will not be called if the datasets update has been previously cancelled.
* @param {Chart} chart - The chart instance.
* @param {Object} args - The call arguments.
* @param {Object} args.index - The dataset index.
* @param {Number} args.meta - The dataset metadata.
* @param {Object} options - The plugin options.
*/
/**
* @method IPlugin#beforeLayout
* @desc Called before laying out `chart`. If any plugin returns `false`,
@@ -274,6 +295,31 @@ module.exports = function(Chart) {
* @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
* @param {Object} options - The plugin options.
*/
/**
* @method IPlugin#beforeDatasetDraw
* @desc Called before drawing the `chart` dataset at the given `args.index` (datasets
* are drawn in the reverse order). If any plugin returns `false`, the datasets drawing
* is cancelled until another `render` is triggered.
* @param {Chart} chart - The chart instance.
* @param {Object} args - The call arguments.
* @param {Object} args.index - The dataset index.
* @param {Number} args.meta - The dataset metadata.
* @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
* @param {Object} options - The plugin options.
* @returns {Boolean} `false` to cancel the chart datasets drawing.
*/
/**
* @method IPlugin#afterDatasetDraw
* @desc Called after the `chart` datasets at the given `args.index` have been drawn
* (datasets are drawn in the reverse order). Note that this hook will not be called
* if the datasets drawing has been previously cancelled.
* @param {Chart} chart - The chart instance.
* @param {Object} args - The call arguments.
* @param {Object} args.index - The dataset index.
* @param {Number} args.meta - The dataset metadata.
* @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
* @param {Object} options - The plugin options.
*/
/**
* @method IPlugin#beforeEvent
* @desc Called before processing the specified `event`. If any plugin returns `false`,

View File

@@ -635,7 +635,7 @@ describe('Chart', function() {
describe('plugin.extensions', function() {
it ('should notify plugin in correct order', function(done) {
var plugin = this.plugin = {id: 'foobar'};
var plugin = this.plugin = {};
var sequence = [];
var hooks = {
init: [
@@ -647,6 +647,8 @@ describe('Chart', function() {
'beforeLayout',
'afterLayout',
'beforeDatasetsUpdate',
'beforeDatasetUpdate',
'afterDatasetUpdate',
'afterDatasetsUpdate',
'afterUpdate',
],
@@ -654,6 +656,8 @@ describe('Chart', function() {
'beforeRender',
'beforeDraw',
'beforeDatasetsDraw',
'beforeDatasetDraw',
'afterDatasetDraw',
'afterDatasetsDraw',
'afterDraw',
'afterRender',
@@ -675,6 +679,8 @@ describe('Chart', function() {
});
var chart = window.acquireChart({
type: 'line',
data: {datasets: [{}]},
plugins: [plugin],
options: {
responsive: true
@@ -702,5 +708,28 @@ describe('Chart', function() {
done();
});
});
it('should not notify before/afterDatasetDraw if dataset is hidden', function() {
var sequence = [];
var plugin = this.plugin = {
beforeDatasetDraw: function(chart, args) {
sequence.push('before-' + args.index);
},
afterDatasetDraw: function(chart, args) {
sequence.push('after-' + args.index);
}
};
window.acquireChart({
type: 'line',
data: {datasets: [{}, {hidden: true}, {}]},
plugins: [plugin]
});
expect(sequence).toEqual([
'before-2', 'after-2',
'before-0', 'after-0'
]);
});
});
});