}
});
```
+
+## 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]
+ }]
+ }
+});
+```
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 = {};
key = keys[i];
values[key] = resolve([
custom[key],
- dataset[key],
+ datasetOpts[key],
options[key]
], context, index);
}
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];
key = keys[i];
values[key] = resolve([
custom[key],
- dataset[key],
+ datasetOpts[key],
options[key]
], context, index);
}
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;
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 = {};
key = keys[i];
values[key] = resolve([
custom[key],
- dataset[key],
+ datasetOpts[key],
options[key]
], context, index);
}
}
});
-function lineEnabled(dataset, options) {
- return valueOrDefault(dataset.showLine, options.showLines);
-}
-
module.exports = DatasetController.extend({
datasetElementType: elements.Line,
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
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 = {};
key = keys[i];
values[key] = resolve([
custom[key],
- dataset[ELEMENT_OPTIONS[key]],
- dataset[key],
+ datasetOpts[ELEMENT_OPTIONS[key]],
+ datasetOpts[key],
options[key]
], context, index);
}
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;
key = keys[i];
values[key] = resolve([
custom[key],
- dataset[key],
+ datasetOpts[key],
elementOptions[key]
], context);
}
// 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;
},
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, {
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 = {};
key = keys[i];
values[key] = resolve([
custom[key],
- dataset[key],
+ datasetOpts[key],
options[key]
], context, index);
}
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 = {};
key = keys[i];
values[key] = resolve([
custom[key],
- dataset[ELEMENT_OPTIONS[key]],
- dataset[key],
+ datasetOpts[ELEMENT_OPTIONS[key]],
+ datasetOpts[key],
options[key]
], context, index);
}
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 = {};
key = keys[i];
values[key] = resolve([
custom[key],
- dataset[key],
+ datasetOpts[key],
options[key]
]);
}
}]
},
- showLines: false,
-
tooltips: {
callbacks: {
title: function() {
}
});
+defaults._set('global', {
+ datasets: {
+ scatter: {
+ showLine: false
+ }
+ }
+});
+
// Scatter charts use line controllers
module.exports = LineController;
return;
}
- meta.controller.update();
+ meta.controller._update();
plugins.notify(me, 'afterDatasetUpdate', [args]);
},
me.index = datasetIndex;
me.linkScales();
me.addElements();
+ me._type = me.getMeta().type;
},
updateIndex: function(datasetIndex) {
},
reset: function() {
- this.update(true);
+ this._update(true);
},
/**
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) {
}
};
+// 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',
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',
});
// 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},
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)',
hitRadius: 5,
};
- meta.controller.update();
+ meta.controller._update();
expect(meta.dataset._model).toEqual(jasmine.objectContaining({
backgroundColor: 'rgb(55, 55, 54)',
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);
+ });
});
});
});
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;
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;
});