]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Add new dataset update and draw plugin hooks
authorSimon Brunel <simonbrunel@users.noreply.github.com>
Sat, 18 Feb 2017 10:58:45 +0000 (11:58 +0100)
committerEvert Timberg <evert.timberg+github@gmail.com>
Wed, 22 Feb 2017 01:28:16 +0000 (20:28 -0500)
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.

.gitignore
src/controllers/controller.bar.js
src/controllers/controller.line.js
src/controllers/controller.radar.js
src/core/core.controller.js
src/core/core.datasetController.js
src/core/core.plugin.js
test/core.controller.tests.js

index 172413437e6c875b482719d6e49c91b2dbb6e260..e76d361a54a904a475dfa5895d6517bca0009ab4 100644 (file)
@@ -9,4 +9,5 @@
 .vscode
 bower.json
 
+*.log
 *.swp
index 0aa35a2e3a95b59ebe9457ed5e7a20b087ae4375..3863b3ca5c37370c279a24fc7440abed043a2568 100644 (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);
index 577ed75e2dabd4c12949d1dc4005a2462977bb81..72e49ce92e6aa74d43e6808194ca8ee81a6793e6 100644 (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);
                        }
                },
 
index fc0c4a285c9e89f03735c2216f9ea839105494a4..db8396a21c3a9c9157a7e964863519f1116e51cb 100644 (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];
index fc71401fa026019328e2b56837476e2fa6f22615..ddd02e7afdefd8f50e629df45e53dae359bb2b4f 100644 (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) {
index afd5ea37dc953517c2bb7eb5c0f0f319f39fed06..8f8495b362263a529ccf537b9bdef7f47eca59e3 100644 (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();
                        }
                },
 
index eeadc83aafda2b70b29492c27407134d8708a9f5..94e459736a96faef13106c340006d9015a334c71 100644 (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`,
index 68535eb88dfd543db144865ed0bba08ce18ae01a..18caee8bdb2799fcbc6e0cac2889449a8d8e92d6 100644 (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'
+                       ]);
+               });
        });
 });