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.
.vscode
bower.json
+*.log
*.swp
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);
}
},
- 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);
}
},
});
},
- 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];
}
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;
easingValue = 1;
}
+ me.transition(easingValue);
+
if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) {
return;
}
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`.
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) {
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();
}
},
* @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`,
* @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`,
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: [
'beforeLayout',
'afterLayout',
'beforeDatasetsUpdate',
+ 'beforeDatasetUpdate',
+ 'afterDatasetUpdate',
'afterDatasetsUpdate',
'afterUpdate',
],
'beforeRender',
'beforeDraw',
'beforeDatasetsDraw',
+ 'beforeDatasetDraw',
+ 'afterDatasetDraw',
'afterDatasetsDraw',
'afterDraw',
'afterRender',
});
var chart = window.acquireChart({
+ type: 'line',
+ data: {datasets: [{}]},
plugins: [plugin],
options: {
responsive: true
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'
+ ]);
+ });
});
});