mirror of
https://github.com/chartjs/Chart.js.git
synced 2026-03-06 08:24:05 +01:00
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:
committed by
Evert Timberg
parent
cc90c5c643
commit
4741c6f09d
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,4 +9,5 @@
|
||||
.vscode
|
||||
bower.json
|
||||
|
||||
*.log
|
||||
*.swp
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -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`,
|
||||
|
||||
@@ -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'
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user