]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Implement per-dataset type (default and per-chart) options (#5999)
authorBen McCann <322311+benmccann@users.noreply.github.com>
Mon, 6 May 2019 20:52:40 +0000 (13:52 -0700)
committerSimon Brunel <simonbrunel@users.noreply.github.com>
Mon, 6 May 2019 20:52:40 +0000 (22:52 +0200)
15 files changed:
docs/configuration/README.md
src/controllers/controller.bar.js
src/controllers/controller.bubble.js
src/controllers/controller.doughnut.js
src/controllers/controller.line.js
src/controllers/controller.polarArea.js
src/controllers/controller.radar.js
src/controllers/controller.scatter.js
src/core/core.controller.js
src/core/core.datasetController.js
src/core/core.defaults.js
test/specs/controller.line.tests.js
test/specs/controller.radar.tests.js
test/specs/controller.scatter.test.js
test/specs/core.controller.tests.js

index 0a4dee450c9edde0974e74b3c85d1e33b8dce974..9139d5f88e16bf4039fe8e053aa18ef697afb39c 100644 (file)
@@ -31,3 +31,40 @@ var chartDifferentHoverMode = new Chart(ctx, {
     }
 });
 ```
+
+## Dataset Configuration
+
+Options may be configured directly on the dataset. The dataset options can be changed at 3 different levels and are evaluated with the following priority:
+
+- per dataset: dataset.*
+- per chart: options.datasets[type].*
+- or globally: Chart.defaults.global.datasets[type].*
+
+where type corresponds to the dataset type.
+
+*Note:* dataset options take precedence over element options.
+
+The following example would set the `showLine` option to 'false' for all line datasets except for those overridden by options passed to the dataset on creation.
+
+```javascript
+// Do not show lines for all datasets by default
+Chart.defaults.global.datasets.line.showLine = false;
+
+// This chart would show a line only for the third dataset
+var chart = new Chart(ctx, {
+    type: 'line',
+    data: {
+        datasets: [{
+            data: [0, 0],
+        }, {
+            data: [0, 1]
+        }, {
+            data: [1, 0],
+            showLine: true // overrides the `line` dataset default
+        }, {
+            type: 'scatter', // 'line' dataset default does not affect this dataset since it's a 'scatter'
+            data: [1, 1]
+        }]
+    }
+});
+```
index 992333a25c214c270b626422295d2200956a95dd..7130a9d0905b2536ad75f20a6922dcca795f9ad5 100644 (file)
@@ -382,6 +382,7 @@ module.exports = DatasetController.extend({
                var chart = me.chart;
                var datasets = chart.data.datasets;
                var dataset = datasets[me.index];
+               var datasetOpts = me._config;
                var custom = rectangle.custom || {};
                var options = chart.options.elements.rectangle;
                var values = {};
@@ -406,7 +407,7 @@ module.exports = DatasetController.extend({
                        key = keys[i];
                        values[key] = resolve([
                                custom[key],
-                               dataset[key],
+                               datasetOpts[key],
                                options[key]
                        ], context, index);
                }
index d40b4393b515fd877bf9b7cfed8d29a104adcd92..d724432f446736d4248f15ce26adb66e48251655 100644 (file)
@@ -127,6 +127,7 @@ module.exports = DatasetController.extend({
                var chart = me.chart;
                var datasets = chart.data.datasets;
                var dataset = datasets[me.index];
+               var datasetOpts = me._config;
                var custom = point.custom || {};
                var options = chart.options.elements.point;
                var data = dataset.data[index];
@@ -158,7 +159,7 @@ module.exports = DatasetController.extend({
                        key = keys[i];
                        values[key] = resolve([
                                custom[key],
-                               dataset[key],
+                               datasetOpts[key],
                                options[key]
                        ], context, index);
                }
index 688368edac4902377bd83d068f4b0bf696079a67..daa1ed1bdfda2ade27fbf4b3deec42037919de7e 100644 (file)
@@ -315,7 +315,12 @@ module.exports = DatasetController.extend({
 
                for (i = 0, ilen = arcs.length; i < ilen; ++i) {
                        arc = arcs[i];
-                       options = controller ? controller._resolveElementOptions(arc, i) : arc._options;
+                       if (controller) {
+                               controller._configure();
+                               options = controller._resolveElementOptions(arc, i);
+                       } else {
+                               options = arc._options;
+                       }
                        if (options.borderAlign !== 'inner') {
                                borderWidth = options.borderWidth;
                                hoverWidth = options.hoverBorderWidth;
@@ -353,6 +358,7 @@ module.exports = DatasetController.extend({
                var me = this;
                var chart = me.chart;
                var dataset = me.getDataset();
+               var datasetOpts = me._config;
                var custom = arc.custom || {};
                var options = chart.options.elements.arc;
                var values = {};
@@ -380,7 +386,7 @@ module.exports = DatasetController.extend({
                        key = keys[i];
                        values[key] = resolve([
                                custom[key],
-                               dataset[key],
+                               datasetOpts[key],
                                options[key]
                        ], context, index);
                }
index 8bc14c3decdeb366e5da0f681f3c0e5aaaf7d828..c671d65793355630336ba7f47af0a964ed282cbf 100644 (file)
@@ -29,10 +29,6 @@ defaults._set('line', {
        }
 });
 
-function lineEnabled(dataset, options) {
-       return valueOrDefault(dataset.showLine, options.showLines);
-}
-
 module.exports = DatasetController.extend({
 
        datasetElementType: elements.Line,
@@ -44,9 +40,10 @@ module.exports = DatasetController.extend({
                var meta = me.getMeta();
                var line = meta.dataset;
                var points = meta.data || [];
+               var options = me.chart.options;
                var scale = me.getScaleForId(meta.yAxisID);
                var dataset = me.getDataset();
-               var showLine = lineEnabled(dataset, me.chart.options);
+               var showLine = me._showLine = valueOrDefault(me._config.showLine, options.showLines);
                var i, ilen;
 
                // Update Line
@@ -132,6 +129,7 @@ module.exports = DatasetController.extend({
                var me = this;
                var chart = me.chart;
                var dataset = chart.data.datasets[me.index];
+               var datasetOpts = me._config;
                var custom = element.custom || {};
                var options = chart.options.elements.point;
                var values = {};
@@ -164,8 +162,8 @@ module.exports = DatasetController.extend({
                        key = keys[i];
                        values[key] = resolve([
                                custom[key],
-                               dataset[ELEMENT_OPTIONS[key]],
-                               dataset[key],
+                               datasetOpts[ELEMENT_OPTIONS[key]],
+                               datasetOpts[key],
                                options[key]
                        ], context, index);
                }
@@ -181,6 +179,7 @@ module.exports = DatasetController.extend({
                var chart = me.chart;
                var datasetIndex = me.index;
                var dataset = chart.data.datasets[datasetIndex];
+               var datasetOpts = me._config;
                var custom = element.custom || {};
                var options = chart.options;
                var elementOptions = options.elements.line;
@@ -210,7 +209,7 @@ module.exports = DatasetController.extend({
                        key = keys[i];
                        values[key] = resolve([
                                custom[key],
-                               dataset[key],
+                               datasetOpts[key],
                                elementOptions[key]
                        ], context);
                }
@@ -218,9 +217,9 @@ module.exports = DatasetController.extend({
                // The default behavior of lines is to break at null values, according
                // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
                // This option gives lines the ability to span gaps
-               values.spanGaps = valueOrDefault(dataset.spanGaps, options.spanGaps);
-               values.tension = valueOrDefault(dataset.lineTension, elementOptions.tension);
-               values.steppedLine = resolve([custom.steppedLine, dataset.steppedLine, elementOptions.stepped]);
+               values.spanGaps = valueOrDefault(datasetOpts.spanGaps, options.spanGaps);
+               values.tension = valueOrDefault(datasetOpts.lineTension, elementOptions.tension);
+               values.steppedLine = resolve([custom.steppedLine, datasetOpts.steppedLine, elementOptions.stepped]);
 
                return values;
        },
@@ -319,11 +318,11 @@ module.exports = DatasetController.extend({
                var meta = me.getMeta();
                var points = meta.data || [];
                var area = chart.chartArea;
+               var i = 0;
                var ilen = points.length;
                var halfBorderWidth;
-               var i = 0;
 
-               if (lineEnabled(me.getDataset(), chart.options)) {
+               if (me._showLine) {
                        halfBorderWidth = (meta.dataset._model.borderWidth || 0) / 2;
 
                        helpers.canvas.clipArea(chart.ctx, {
index 19ceefddab7cce8a5f913a29317d94b446858730..582a0a78bf77bf79b7e1a76294c83655b91d3d06 100644 (file)
@@ -248,6 +248,7 @@ module.exports = DatasetController.extend({
                var me = this;
                var chart = me.chart;
                var dataset = me.getDataset();
+               var datasetOpts = me._config;
                var custom = arc.custom || {};
                var options = chart.options.elements.arc;
                var values = {};
@@ -275,7 +276,7 @@ module.exports = DatasetController.extend({
                        key = keys[i];
                        values[key] = resolve([
                                custom[key],
-                               dataset[key],
+                               datasetOpts[key],
                                options[key]
                        ], context, index);
                }
index f11af4dcc7f033bcc32edd7e0b78654bbd6fb624..1e32dd0a424c21f835fb2cdd80c65655eb5369fe 100644 (file)
@@ -115,6 +115,7 @@ module.exports = DatasetController.extend({
                var me = this;
                var chart = me.chart;
                var dataset = chart.data.datasets[me.index];
+               var datasetOpts = me._config;
                var custom = element.custom || {};
                var options = chart.options.elements.point;
                var values = {};
@@ -147,8 +148,8 @@ module.exports = DatasetController.extend({
                        key = keys[i];
                        values[key] = resolve([
                                custom[key],
-                               dataset[ELEMENT_OPTIONS[key]],
-                               dataset[key],
+                               datasetOpts[ELEMENT_OPTIONS[key]],
+                               datasetOpts[key],
                                options[key]
                        ], context, index);
                }
@@ -163,6 +164,7 @@ module.exports = DatasetController.extend({
                var me = this;
                var chart = me.chart;
                var dataset = chart.data.datasets[me.index];
+               var datasetOpts = me._config;
                var custom = element.custom || {};
                var options = chart.options.elements.line;
                var values = {};
@@ -183,7 +185,7 @@ module.exports = DatasetController.extend({
                        key = keys[i];
                        values[key] = resolve([
                                custom[key],
-                               dataset[key],
+                               datasetOpts[key],
                                options[key]
                        ]);
                }
index 319296d33ba804336ab7c6a26dd776a182a6caa3..177e563203f6cfea389b214ffeac1c71ec13fddb 100644 (file)
@@ -21,8 +21,6 @@ defaults._set('scatter', {
                }]
        },
 
-       showLines: false,
-
        tooltips: {
                callbacks: {
                        title: function() {
@@ -35,5 +33,13 @@ defaults._set('scatter', {
        }
 });
 
+defaults._set('global', {
+       datasets: {
+               scatter: {
+                       showLine: false
+               }
+       }
+});
+
 // Scatter charts use line controllers
 module.exports = LineController;
index 92cfcd01794f15c9a6a9529544dd587ccb9d830e..8abe3978e1af617dd0d975a6ff74d4103ef63f1e 100644 (file)
@@ -567,7 +567,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
                        return;
                }
 
-               meta.controller.update();
+               meta.controller._update();
 
                plugins.notify(me, 'afterDatasetUpdate', [args]);
        },
index afd021c1db1d9eaa6ccdc922a021385d0c417d9f..45a2e894236f5580db5ea59e5a36a04eba0fc4fa 100644 (file)
@@ -100,6 +100,7 @@ helpers.extend(DatasetController.prototype, {
                me.index = datasetIndex;
                me.linkScales();
                me.addElements();
+               me._type = me.getMeta().type;
        },
 
        updateIndex: function(datasetIndex) {
@@ -160,7 +161,7 @@ helpers.extend(DatasetController.prototype, {
        },
 
        reset: function() {
-               this.update(true);
+               this._update(true);
        },
 
        /**
@@ -236,6 +237,30 @@ helpers.extend(DatasetController.prototype, {
                me.resyncElements();
        },
 
+       /**
+        * Returns the merged user-supplied and default dataset-level options
+        * @private
+        */
+       _configure: function() {
+               var me = this;
+               me._config = helpers.merge({}, [
+                       me.chart.options.datasets[me._type],
+                       me.getDataset(),
+               ], {
+                       merger: function(key, target, source) {
+                               if (key !== '_meta' && key !== 'data') {
+                                       helpers._merger(key, target, source);
+                               }
+                       }
+               });
+       },
+
+       _update: function(reset) {
+               var me = this;
+               me._configure();
+               me.update(reset);
+       },
+
        update: helpers.noop,
 
        transition: function(easingValue) {
index 279491debaedc0b70e2dc8e3727b50c6a4cdba62..6c8e996a1a888a303c1200f81905611b5a1cdc59 100644 (file)
@@ -11,6 +11,8 @@ var defaults = {
        }
 };
 
+// TODO(v3): remove 'global' from namespace.  all default are global and
+// there's inconsistency around which options are under 'global'
 defaults._set('global', {
        defaultColor: 'rgba(0,0,0,0.1)',
        defaultFontColor: '#666',
index 285f5c988a2203c6a7aaca2ce62c21516d6ee6cd..953594deac130c72909ed4dc0b3d9566ae85d413 100644 (file)
@@ -573,6 +573,181 @@ describe('Chart.controllers.line', function() {
                expect(meta.dataset._model.borderWidth).toBe(0.55);
        });
 
+       describe('dataset global defaults', function() {
+               beforeEach(function() {
+                       this._defaults = Chart.helpers.clone(Chart.defaults.global.datasets.line);
+               });
+
+               afterEach(function() {
+                       Chart.defaults.global.datasets.line = this._defaults;
+                       delete this._defaults;
+               });
+
+               it('should utilize the dataset global default options', function() {
+                       Chart.defaults.global.datasets.line = Chart.defaults.global.datasets.line || {};
+
+                       Chart.helpers.merge(Chart.defaults.global.datasets.line, {
+                               spanGaps: true,
+                               lineTension: 0.231,
+                               backgroundColor: '#add',
+                               borderWidth: '#daa',
+                               borderColor: '#dad',
+                               borderCapStyle: 'round',
+                               borderDash: [0],
+                               borderDashOffset: 0.871,
+                               borderJoinStyle: 'miter',
+                               fill: 'start',
+                               cubicInterpolationMode: 'monotone'
+                       });
+
+                       var chart = window.acquireChart({
+                               type: 'line',
+                               data: {
+                                       datasets: [{
+                                               data: [0, 0],
+                                               label: 'dataset1'
+                                       }],
+                                       labels: ['label1', 'label2']
+                               }
+                       });
+
+                       var model = chart.getDatasetMeta(0).dataset._model;
+
+                       expect(model.spanGaps).toBe(true);
+                       expect(model.tension).toBe(0.231);
+                       expect(model.backgroundColor).toBe('#add');
+                       expect(model.borderWidth).toBe('#daa');
+                       expect(model.borderColor).toBe('#dad');
+                       expect(model.borderCapStyle).toBe('round');
+                       expect(model.borderDash).toEqual([0]);
+                       expect(model.borderDashOffset).toBe(0.871);
+                       expect(model.borderJoinStyle).toBe('miter');
+                       expect(model.fill).toBe('start');
+                       expect(model.cubicInterpolationMode).toBe('monotone');
+               });
+
+               it('should be overriden by user-supplied values', function() {
+                       Chart.defaults.global.datasets.line = Chart.defaults.global.datasets.line || {};
+
+                       Chart.helpers.merge(Chart.defaults.global.datasets.line, {
+                               spanGaps: true,
+                               lineTension: 0.231
+                       });
+
+                       var chart = window.acquireChart({
+                               type: 'line',
+                               data: {
+                                       datasets: [{
+                                               data: [0, 0],
+                                               label: 'dataset1',
+                                               spanGaps: true,
+                                               backgroundColor: '#dad'
+                                       }],
+                                       labels: ['label1', 'label2']
+                               },
+                               options: {
+                                       datasets: {
+                                               line: {
+                                                       lineTension: 0.345,
+                                                       backgroundColor: '#add'
+                                               }
+                                       }
+                               }
+                       });
+
+                       var model = chart.getDatasetMeta(0).dataset._model;
+
+                       // dataset-level option overrides global default
+                       expect(model.spanGaps).toBe(true);
+                       // chart-level default overrides global default
+                       expect(model.tension).toBe(0.345);
+                       // dataset-level option overrides chart-level default
+                       expect(model.backgroundColor).toBe('#dad');
+               });
+       });
+
+       it('should obey the chart-level dataset options', function() {
+               var chart = window.acquireChart({
+                       type: 'line',
+                       data: {
+                               datasets: [{
+                                       data: [0, 0],
+                                       label: 'dataset1'
+                               }],
+                               labels: ['label1', 'label2']
+                       },
+                       options: {
+                               datasets: {
+                                       line: {
+                                               spanGaps: true,
+                                               lineTension: 0.231,
+                                               backgroundColor: '#add',
+                                               borderWidth: '#daa',
+                                               borderColor: '#dad',
+                                               borderCapStyle: 'round',
+                                               borderDash: [0],
+                                               borderDashOffset: 0.871,
+                                               borderJoinStyle: 'miter',
+                                               fill: 'start',
+                                               cubicInterpolationMode: 'monotone'
+                                       }
+                               }
+                       }
+               });
+
+               var model = chart.getDatasetMeta(0).dataset._model;
+
+               expect(model.spanGaps).toBe(true);
+               expect(model.tension).toBe(0.231);
+               expect(model.backgroundColor).toBe('#add');
+               expect(model.borderWidth).toBe('#daa');
+               expect(model.borderColor).toBe('#dad');
+               expect(model.borderCapStyle).toBe('round');
+               expect(model.borderDash).toEqual([0]);
+               expect(model.borderDashOffset).toBe(0.871);
+               expect(model.borderJoinStyle).toBe('miter');
+               expect(model.fill).toBe('start');
+               expect(model.cubicInterpolationMode).toBe('monotone');
+       });
+
+       it('should obey the dataset options', function() {
+               var chart = window.acquireChart({
+                       type: 'line',
+                       data: {
+                               datasets: [{
+                                       data: [0, 0],
+                                       label: 'dataset1',
+                                       spanGaps: true,
+                                       lineTension: 0.231,
+                                       backgroundColor: '#add',
+                                       borderWidth: '#daa',
+                                       borderColor: '#dad',
+                                       borderCapStyle: 'round',
+                                       borderDash: [0],
+                                       borderDashOffset: 0.871,
+                                       borderJoinStyle: 'miter',
+                                       fill: 'start',
+                                       cubicInterpolationMode: 'monotone'
+                               }],
+                               labels: ['label1', 'label2']
+                       }
+               });
+
+               var model = chart.getDatasetMeta(0).dataset._model;
+
+               expect(model.spanGaps).toBe(true);
+               expect(model.tension).toBe(0.231);
+               expect(model.backgroundColor).toBe('#add');
+               expect(model.borderWidth).toBe('#daa');
+               expect(model.borderColor).toBe('#dad');
+               expect(model.borderCapStyle).toBe('round');
+               expect(model.borderDash).toEqual([0]);
+               expect(model.borderDashOffset).toBe(0.871);
+               expect(model.borderJoinStyle).toBe('miter');
+               expect(model.fill).toBe('start');
+               expect(model.cubicInterpolationMode).toBe('monotone');
+       });
+
        it('should handle number of data point changes in update', function() {
                var chart = window.acquireChart({
                        type: 'line',
index d00e3674a8cb88758bfef5500909c1daedcac017..8eff71b60ddce5f36e1bc8f14eb71030c18e091d 100644 (file)
@@ -154,7 +154,7 @@ describe('Chart.controllers.radar', function() {
                });
 
                // Now update controller and ensure proper updates
-               meta.controller.update();
+               meta.controller._update();
 
                [
                        {x: 256, y: 120, cppx: 246, cppy: 120, cpnx: 272, cpny: 120},
@@ -198,7 +198,7 @@ describe('Chart.controllers.radar', function() {
                chart.data.datasets[0].pointBorderColor = 'rgb(56, 57, 58)';
                chart.data.datasets[0].pointBorderWidth = 1.123;
 
-               meta.controller.update();
+               meta.controller._update();
 
                expect(meta.dataset._model).toEqual(jasmine.objectContaining({
                        backgroundColor: 'rgb(98, 98, 98)',
@@ -256,7 +256,7 @@ describe('Chart.controllers.radar', function() {
                        hitRadius: 5,
                };
 
-               meta.controller.update();
+               meta.controller._update();
 
                expect(meta.dataset._model).toEqual(jasmine.objectContaining({
                        backgroundColor: 'rgb(55, 55, 54)',
index bc1ff18bf49969f5be654bf64c63f48a6e861a52..a2744b9e4372aafbb0d0437c8bb9085b2f125ea2 100644 (file)
@@ -47,5 +47,28 @@ describe('Chart.controllers.scatter', function() {
                        expect(meta.dataset.draw.calls.count()).toBe(0);
                        expect(meta.data[0].draw.calls.count()).toBe(1);
                });
+
+               it('should draw a line if true', function() {
+                       var chart = window.acquireChart({
+                               type: 'scatter',
+                               data: {
+                                       datasets: [{
+                                               data: [{x: 10, y: 15}],
+                                               showLine: true,
+                                               label: 'dataset1'
+                                       }],
+                               },
+                               options: {}
+                       });
+
+                       var meta = chart.getDatasetMeta(0);
+                       spyOn(meta.dataset, 'draw');
+                       spyOn(meta.data[0], 'draw');
+
+                       chart.update();
+
+                       expect(meta.dataset.draw.calls.count()).toBe(1);
+                       expect(meta.data[0].draw.calls.count()).toBe(1);
+               });
        });
 });
index 946e9fabec5ce86b7462a838d8d477f53e66426f..2fb982276eea6693cbb2b9236b1a5f3bc28f5ad3 100644 (file)
@@ -91,9 +91,11 @@ describe('Chart', function() {
                });
 
                it('should override default options', function() {
+                       var callback = function() {};
                        var defaults = Chart.defaults;
 
                        defaults.global.responsiveAnimationDuration = 42;
+                       defaults.global.hover.onHover = callback;
                        defaults.line.hover.mode = 'x-axis';
                        defaults.line.spanGaps = true;
 
@@ -113,11 +115,13 @@ describe('Chart', function() {
 
                        var options = chart.options;
                        expect(options.responsiveAnimationDuration).toBe(4242);
+                       expect(options.showLines).toBe(defaults.global.showLines);
                        expect(options.spanGaps).toBe(false);
                        expect(options.hover.mode).toBe('dataset');
                        expect(options.title.position).toBe('bottom');
 
                        defaults.global.responsiveAnimationDuration = 0;
+                       defaults.global.hover.onHover = null;
                        defaults.line.hover.mode = 'label';
                        defaults.line.spanGaps = false;
                });