Skip to content

Commit 5c3f88f

Browse files
committed
Per-controller options to fix mixed charts
1 parent 8b07cc2 commit 5c3f88f

File tree

8 files changed

+188
-30
lines changed

8 files changed

+188
-30
lines changed

docs/configuration/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,34 @@ var chartDifferentHoverMode = new Chart(ctx, {
3131
}
3232
});
3333
```
34+
35+
## Dataset Configuration
36+
37+
Options may be configured direction on the dataset. Dataset defaults also allow for changing options globally across a dataset type avoiding the need to specify options for each dataset instance.
38+
39+
Chart.js merges user-specified dataset configuration with the dataset defaults appropriately. This way you can be as specific as you would like in your individual dataset configuration, while still changing the defaults for all datasets where applicable. The dataset general options are defined in `Chart.defaults.datasets.type` where `type` corresponds to the dataset type. Dataset options take precedence over element options. If you set a dataset type default, it will override all corresponding element options. The defaults for each dataset type are discussed in the documentation for that chart type.
40+
41+
The following example would set the `showLine` option to 'false' for all line datasets where this was not overridden by the options passed to the dataset on creation.
42+
43+
```javascript
44+
// Do not show lines for all datasets by default
45+
Chart.defaults.datasets.line.showLine = false;
46+
47+
// This chart would show a line only for the third dataset
48+
var chart = new Chart(ctx, {
49+
type: 'line',
50+
data: {
51+
datasets: [{
52+
data: [0, 0],
53+
}, {
54+
data: [0, 1]
55+
}, {
56+
data: [1, 0],
57+
showLine: true // overrides the `line` dataset default
58+
}, {
59+
type: 'scatter', // 'line' dataset default does not affect this dataset since it's a 'scatter'
60+
data: [1, 1]
61+
}]
62+
}
63+
});
64+
```

src/controllers/controller.line.js

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,6 @@ defaults._set('line', {
2929
}
3030
});
3131

32-
function lineEnabled(dataset, options) {
33-
return valueOrDefault(dataset.showLine, options.showLines);
34-
}
35-
3632
module.exports = DatasetController.extend({
3733

3834
datasetElementType: elements.Line,
@@ -44,9 +40,10 @@ module.exports = DatasetController.extend({
4440
var meta = me.getMeta();
4541
var line = meta.dataset;
4642
var points = meta.data || [];
43+
var options = me.chart.options;
4744
var scale = me.getScaleForId(meta.yAxisID);
4845
var dataset = me.getDataset();
49-
var showLine = lineEnabled(dataset, me.chart.options);
46+
var showLine = me._showLine = valueOrDefault(me._cfg.showLine, options.showLines);
5047
var i, ilen;
5148

5249
// Update Line
@@ -179,7 +176,7 @@ module.exports = DatasetController.extend({
179176
_resolveLineOptions: function(element) {
180177
var me = this;
181178
var chart = me.chart;
182-
var dataset = chart.data.datasets[me.index];
179+
var datasetOpts = me._cfg;
183180
var custom = element.custom || {};
184181
var options = chart.options;
185182
var elementOptions = options.elements.line;
@@ -202,17 +199,17 @@ module.exports = DatasetController.extend({
202199
key = keys[i];
203200
values[key] = resolve([
204201
custom[key],
205-
dataset[key],
202+
datasetOpts[key],
206203
elementOptions[key]
207204
]);
208205
}
209206

210207
// The default behavior of lines is to break at null values, according
211208
// to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
212209
// This option gives lines the ability to span gaps
213-
values.spanGaps = valueOrDefault(dataset.spanGaps, options.spanGaps);
214-
values.tension = valueOrDefault(dataset.lineTension, elementOptions.tension);
215-
values.steppedLine = resolve([custom.steppedLine, dataset.steppedLine, elementOptions.stepped]);
210+
values.spanGaps = resolve([datasetOpts.spanGaps, options.spanGaps]);
211+
values.tension = resolve([datasetOpts.tension, elementOptions.tension]);
212+
values.steppedLine = resolve([custom.steppedLine, datasetOpts.steppedLine, elementOptions.stepped]);
216213

217214
return values;
218215
},
@@ -311,11 +308,11 @@ module.exports = DatasetController.extend({
311308
var meta = me.getMeta();
312309
var points = meta.data || [];
313310
var area = chart.chartArea;
311+
var i = 0;
314312
var ilen = points.length;
315313
var halfBorderWidth;
316-
var i = 0;
317314

318-
if (lineEnabled(me.getDataset(), chart.options)) {
315+
if (me._showLine) {
319316
halfBorderWidth = (meta.dataset._model.borderWidth || 0) / 2;
320317

321318
helpers.canvas.clipArea(chart.ctx, {

src/controllers/controller.scatter.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ defaults._set('scatter', {
2121
}]
2222
},
2323

24-
showLines: false,
25-
2624
tooltips: {
2725
callbacks: {
2826
title: function() {
@@ -35,5 +33,11 @@ defaults._set('scatter', {
3533
}
3634
});
3735

36+
defaults._set('datasets', {
37+
scatter: {
38+
showLine: false
39+
}
40+
});
41+
3842
// Scatter charts use line controllers
3943
module.exports = LineController;

src/core/core.controller.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
417417
meta.controller = new ControllerClass(me, datasetIndex);
418418
newControllers.push(meta.controller);
419419
}
420+
meta.controller._config();
420421
}, me);
421422

422423
return newControllers;

src/core/core.datasetController.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22

3+
var defaults = require('./core.defaults');
34
var helpers = require('../helpers/index');
45

56
var resolve = helpers.options.resolve;
@@ -100,6 +101,7 @@ helpers.extend(DatasetController.prototype, {
100101
me.index = datasetIndex;
101102
me.linkScales();
102103
me.addElements();
104+
me._type = me.getMeta().type;
103105
},
104106

105107
updateIndex: function(datasetIndex) {
@@ -234,6 +236,27 @@ helpers.extend(DatasetController.prototype, {
234236
me.resyncElements();
235237
},
236238

239+
/**
240+
* Returns the merged user-supplied and default dataset-level options
241+
* @private
242+
*/
243+
_config: function() {
244+
var me = this;
245+
var dataset = me.getDataset();
246+
var datasetDefaults = defaults.datasets[me._type];
247+
var userOpts = {};
248+
var keys = Object.keys(dataset);
249+
var i, ilen, key;
250+
for (i = 0, ilen = keys.length; i < ilen; i++) {
251+
key = keys[i];
252+
if (key !== '_meta' && key !== 'data') {
253+
userOpts[key] = helpers.clone(dataset[key]);
254+
}
255+
}
256+
datasetDefaults = datasetDefaults !== undefined ? helpers.clone(datasetDefaults) : {};
257+
me._cfg = helpers.merge(datasetDefaults, userOpts);
258+
},
259+
237260
update: helpers.noop,
238261

239262
transition: function(easingValue) {

test/specs/controller.line.tests.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,96 @@ describe('Chart.controllers.line', function() {
573573
expect(meta.dataset._model.borderWidth).toBe(0.55);
574574
});
575575

576+
describe('dataset defaults', function() {
577+
beforeEach(function() {
578+
this._defaults = Chart.helpers.clone(Chart.defaults.datasets.line);
579+
});
580+
581+
afterEach(function() {
582+
Chart.defaults.datasets.line = this._defaults;
583+
delete this._defaults;
584+
});
585+
586+
it('should utilize the dataset default options', function() {
587+
Chart.defaults.datasets.line = Chart.defaults.datasets.line || {};
588+
var defaults = Chart.defaults.datasets.line;
589+
defaults.spanGaps = true;
590+
defaults.tension = 0.231;
591+
defaults.backgroundColor = '#add';
592+
defaults.borderWidth = '#daa';
593+
defaults.borderColor = '#dad';
594+
defaults.borderCapStyle = 'round';
595+
defaults.borderDash = [0];
596+
defaults.borderDashOffset = 0.871;
597+
defaults.borderJoinStyle = 'miter';
598+
defaults.fill = 'start';
599+
defaults.cubicInterpolationMode = 'monotone';
600+
601+
var chart = window.acquireChart({
602+
type: 'line',
603+
data: {
604+
datasets: [{
605+
data: [0, 0],
606+
label: 'dataset1'
607+
}],
608+
labels: ['label1', 'label2']
609+
}
610+
});
611+
612+
var model = chart.getDatasetMeta(0).dataset._model;
613+
614+
expect(model.spanGaps).toBe(true);
615+
expect(model.tension).toBe(0.231);
616+
expect(model.backgroundColor).toBe('#add');
617+
expect(model.borderWidth).toBe('#daa');
618+
expect(model.borderColor).toBe('#dad');
619+
expect(model.borderCapStyle).toBe('round');
620+
expect(model.borderDash).toEqual([0]);
621+
expect(model.borderDashOffset).toBe(0.871);
622+
expect(model.borderJoinStyle).toBe('miter');
623+
expect(model.fill).toBe('start');
624+
expect(model.cubicInterpolationMode).toBe('monotone');
625+
});
626+
});
627+
628+
it('should obey the dataset options', function() {
629+
var chart = window.acquireChart({
630+
type: 'line',
631+
data: {
632+
datasets: [{
633+
data: [0, 0],
634+
label: 'dataset1',
635+
spanGaps: true,
636+
tension: 0.231,
637+
backgroundColor: '#add',
638+
borderWidth: '#daa',
639+
borderColor: '#dad',
640+
borderCapStyle: 'round',
641+
borderDash: [0],
642+
borderDashOffset: 0.871,
643+
borderJoinStyle: 'miter',
644+
fill: 'start',
645+
cubicInterpolationMode: 'monotone'
646+
}],
647+
labels: ['label1', 'label2']
648+
}
649+
});
650+
651+
var model = chart.getDatasetMeta(0).dataset._model;
652+
653+
expect(model.spanGaps).toBe(true);
654+
expect(model.tension).toBe(0.231);
655+
expect(model.backgroundColor).toBe('#add');
656+
expect(model.borderWidth).toBe('#daa');
657+
expect(model.borderColor).toBe('#dad');
658+
expect(model.borderCapStyle).toBe('round');
659+
expect(model.borderDash).toEqual([0]);
660+
expect(model.borderDashOffset).toBe(0.871);
661+
expect(model.borderJoinStyle).toBe('miter');
662+
expect(model.fill).toBe('start');
663+
expect(model.cubicInterpolationMode).toBe('monotone');
664+
});
665+
576666
it('should handle number of data point changes in update', function() {
577667
var chart = window.acquireChart({
578668
type: 'line',

test/specs/controller.scatter.test.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,28 @@ describe('Chart.controllers.scatter', function() {
4747
expect(meta.dataset.draw.calls.count()).toBe(0);
4848
expect(meta.data[0].draw.calls.count()).toBe(1);
4949
});
50+
51+
it('should draw a line if true', function() {
52+
var chart = window.acquireChart({
53+
type: 'scatter',
54+
data: {
55+
datasets: [{
56+
data: [{x: 10, y: 15}],
57+
showLine: true,
58+
label: 'dataset1'
59+
}],
60+
},
61+
options: {}
62+
});
63+
64+
var meta = chart.getDatasetMeta(0);
65+
spyOn(meta.dataset, 'draw');
66+
spyOn(meta.data[0], 'draw');
67+
68+
chart.update();
69+
70+
expect(meta.dataset.draw.calls.count()).toBe(1);
71+
expect(meta.data[0].draw.calls.count()).toBe(1);
72+
});
5073
});
5174
});

test/specs/core.controller.tests.js

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,33 +64,22 @@ describe('Chart', function() {
6464
});
6565

6666
it('should initialize config with default options', function() {
67-
var callback = function() {};
68-
6967
var defaults = Chart.defaults;
70-
defaults.global.responsiveAnimationDuration = 42;
71-
defaults.global.hover.onHover = callback;
72-
defaults.line.hover.mode = 'x-axis';
73-
defaults.line.spanGaps = true;
7468

7569
var chart = acquireChart({
7670
type: 'line'
7771
});
7872

7973
var options = chart.options;
8074
expect(options.defaultFontSize).toBe(defaults.global.defaultFontSize);
81-
expect(options.showLines).toBe(defaults.line.showLines);
82-
expect(options.spanGaps).toBe(true);
83-
expect(options.responsiveAnimationDuration).toBe(42);
84-
expect(options.hover.onHover).toBe(callback);
85-
expect(options.hover.mode).toBe('x-axis');
75+
expect(options.showLines).toBe(defaults.global.showLines);
76+
expect(options.spanGaps).toBe(defaults.line.spanGaps);
77+
expect(options.responsiveAnimationDuration).toBe(defaults.global.responsiveAnimationDuration);
78+
expect(options.hover.onHover).toBe(defaults.global.hover.onHover);
79+
expect(options.hover.mode).toBe(defaults.line.hover.mode);
8680
});
8781

8882
it('should override default options', function() {
89-
var defaults = Chart.defaults;
90-
defaults.global.responsiveAnimationDuration = 42;
91-
defaults.line.hover.mode = 'x-axis';
92-
defaults.line.spanGaps = true;
93-
9483
var chart = acquireChart({
9584
type: 'line',
9685
options: {

0 commit comments

Comments
 (0)