Implement dataset.order (#6268)

Allow sorting datasets based on the `order` property
This commit is contained in:
Jukka Kurkela 2019-10-23 02:14:54 +03:00 committed by Evert Timberg
parent feaf418d4e
commit 6b6f1a4c51
30 changed files with 748 additions and 156 deletions

View File

@ -77,6 +77,7 @@ the color of the bars is generally set this way.
| [`hoverBorderColor`](#interactions) | [`Color`](../general/colors.md) | - | Yes | `undefined`
| [`hoverBorderWidth`](#interactions) | `number` | - | Yes | `1`
| [`label`](#general) | `string` | - | - | `''`
| [`order`](#general) | `number` | - | - | `0`
| [`xAxisID`](#general) | `string` | - | - | first x axis
| [`yAxisID`](#general) | `string` | - | - | first y axis
@ -85,6 +86,7 @@ the color of the bars is generally set this way.
| Name | Description
| ---- | ----
| `label` | The label for the dataset which appears in the legend and tooltips.
| `order` | The drawing order of dataset. Also affects order for stacking, tooltip, and legend.
| `xAxisID` | The ID of the x axis to plot this dataset on.
| `yAxisID` | The ID of the y axis to plot this dataset on.

View File

@ -49,14 +49,18 @@ The bubble chart allows a number of properties to be specified for each dataset.
| [`hoverBorderWidth`](#interactions) | `number` | Yes | Yes | `1`
| [`hoverRadius`](#interactions) | `number` | Yes | Yes | `4`
| [`hitRadius`](#interactions) | `number` | Yes | Yes | `1`
| [`label`](#labeling) | `string` | - | - | `undefined`
| [`label`](#general) | `string` | - | - | `undefined`
| [`order`](#general) | `number` | - | - | `0`
| [`pointStyle`](#styling) | `string` | Yes | Yes | `'circle'`
| [`rotation`](#styling) | `number` | Yes | Yes | `0`
| [`radius`](#styling) | `number` | Yes | Yes | `3`
### Labeling
### General
`label` defines the text associated to the dataset and which appears in the legend and tooltips.
| Name | Description
| ---- | ----
| `label` | The label for the dataset which appears in the legend and tooltips.
| `order` | The drawing order of dataset.
### Styling

View File

@ -54,6 +54,7 @@ The line chart allows a number of properties to be specified for each dataset. T
| [`fill`](#line-styling) | <code>boolean&#124;string</code> | Yes | - | `true`
| [`label`](#general) | `string` | - | - | `''`
| [`lineTension`](#line-styling) | `number` | - | - | `0.4`
| [`order`](#general) | `number` | - | - | `0`
| [`pointBackgroundColor`](#point-styling) | `Color` | Yes | Yes | `'rgba(0, 0, 0, 0.1)'`
| [`pointBorderColor`](#point-styling) | `Color` | Yes | Yes | `'rgba(0, 0, 0, 0.1)'`
| [`pointBorderWidth`](#point-styling) | `number` | Yes | Yes | `1`
@ -76,6 +77,7 @@ The line chart allows a number of properties to be specified for each dataset. T
| Name | Description
| ---- | ----
| `label` | The label for the dataset which appears in the legend and tooltips.
| `order` | The drawing order of dataset. Also affects order for stacking, tooltip, and legend.
| `xAxisID` | The ID of the x axis to plot this dataset on.
| `yAxisID` | The ID of the y axis to plot this dataset on.

View File

@ -70,3 +70,29 @@ At this point we have a chart rendering how we'd like. It's important to note th
}
}
{% endchartjs %}
## Drawing order
By default, datasets are drawn so that first one is top-most. This can be altered by specifying `order` option to datasets. `order` defaults to `0`.
```javascript
var mixedChart = new Chart(ctx, {
type: 'bar',
data: {
datasets: [{
label: 'Bar Dataset',
data: [10, 20, 30, 40],
// this dataset is drawn below
order: 1
}, {
label: 'Line Dataset',
data: [10, 10, 10, 10],
type: 'line',
// this dataset is drawn on top
order: 2
}],
labels: ['January', 'February', 'March', 'April']
},
options: options
});
```

View File

@ -70,6 +70,7 @@ All these values, if `undefined`, fallback to the associated [`elements.arc.*`](
### Border Alignment
The following values are supported for `borderAlign`.
* `'center'` (default)
* `'inner'`

View File

@ -52,6 +52,7 @@ They are often useful for comparing the points of two or more different data set
{% endchartjs %}
## Example Usage
```javascript
var myRadarChart = new Chart(ctx, {
type: 'radar',
@ -75,6 +76,7 @@ The radar chart allows a number of properties to be specified for each dataset.
| [`borderWidth`](#line-styling) | `number` | Yes | - | `3`
| [`fill`](#line-styling) | <code>boolean&#124;string</code> | Yes | - | `true`
| [`label`](#general) | `string` | - | - | `''`
| [`order`](#general) | `number` | - | - | `0`
| [`lineTension`](#line-styling) | `number` | - | - | `0`
| [`pointBackgroundColor`](#point-styling) | `Color` | Yes | Yes | `'rgba(0, 0, 0, 0.1)'`
| [`pointBorderColor`](#point-styling) | `Color` | Yes | Yes | `'rgba(0, 0, 0, 0.1)'`
@ -94,6 +96,7 @@ The radar chart allows a number of properties to be specified for each dataset.
| Name | Description
| ---- | ----
| `label` | The label for the dataset which appears in the legend and tooltips.
| `order` | The drawing order of dataset.
### Point Styling

View File

@ -32,6 +32,7 @@ var scatterChart = new Chart(ctx, {
```
## Dataset Properties
The scatter chart supports all of the same properties as the [line chart](./line.md#dataset-properties).
## Data Structure

View File

@ -207,21 +207,27 @@ module.exports = DatasetController.extend({
*/
_getStacks: function(last) {
var me = this;
var chart = me.chart;
var scale = me._getIndexScale();
var metasets = scale._getMatchingVisibleMetas(me._type);
var stacked = scale.options.stacked;
var ilen = last === undefined ? chart.data.datasets.length : last + 1;
var ilen = metasets.length;
var stacks = [];
var i, meta;
for (i = 0; i < ilen; ++i) {
meta = chart.getDatasetMeta(i);
if (meta.bar && chart.isDatasetVisible(i) &&
(stacked === false ||
(stacked === true && stacks.indexOf(meta.stack) === -1) ||
(stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
meta = metasets[i];
// stacked | meta.stack
// | found | not found | undefined
// false | x | x | x
// true | | x |
// undefined | | x | x
if (stacked === false || stacks.indexOf(meta.stack) === -1 ||
(stacked === undefined && meta.stack === undefined)) {
stacks.push(meta.stack);
}
if (meta.index === last) {
break;
}
}
return stacks;
@ -290,24 +296,26 @@ module.exports = DatasetController.extend({
var scale = me._getValueScale();
var isHorizontal = scale.isHorizontal();
var datasets = chart.data.datasets;
var metasets = scale._getMatchingVisibleMetas(me._type);
var value = scale._parseValue(datasets[datasetIndex].data[index]);
var minBarLength = scale.options.minBarLength;
var stacked = scale.options.stacked;
var stack = me.getMeta().stack;
var start = value.start === undefined ? 0 : value.max >= 0 && value.min >= 0 ? value.min : value.max;
var length = value.start === undefined ? value.end : value.max >= 0 && value.min >= 0 ? value.max - value.min : value.min - value.max;
var ilen = metasets.length;
var i, imeta, ivalue, base, head, size, stackLength;
if (stacked || (stacked === undefined && stack !== undefined)) {
for (i = 0; i < datasetIndex; ++i) {
imeta = chart.getDatasetMeta(i);
for (i = 0; i < ilen; ++i) {
imeta = metasets[i];
if (imeta.bar &&
imeta.stack === stack &&
imeta.controller._getValueScaleId() === scale.id &&
chart.isDatasetVisible(i)) {
if (imeta.index === datasetIndex) {
break;
}
stackLength = scale._parseValue(datasets[i].data[index]);
if (imeta.stack === stack) {
stackLength = scale._parseValue(datasets[imeta.index].data[index]);
ivalue = stackLength.start === undefined ? stackLength.end : stackLength.min >= 0 && stackLength.max >= 0 ? stackLength.max : stackLength.min;
if ((value.min < 0 && ivalue < 0) || (value.max >= 0 && ivalue > 0)) {

View File

@ -183,14 +183,21 @@ module.exports = DatasetController.extend({
var yScale = me._yScale;
var sumPos = 0;
var sumNeg = 0;
var i, ds, dsMeta;
var rightValue = +yScale.getRightValue(value);
var metasets = chart._getSortedVisibleDatasetMetas();
var ilen = metasets.length;
var i, ds, dsMeta, stackedRightValue;
if (yScale.options.stacked) {
for (i = 0; i < datasetIndex; i++) {
ds = chart.data.datasets[i];
dsMeta = chart.getDatasetMeta(i);
if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
var stackedRightValue = Number(yScale.getRightValue(ds.data[index]));
for (i = 0; i < ilen; ++i) {
dsMeta = metasets[i];
if (dsMeta.index === datasetIndex) {
break;
}
ds = chart.data.datasets[dsMeta.index];
if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id) {
stackedRightValue = +yScale.getRightValue(ds.data[index]);
if (stackedRightValue < 0) {
sumNeg += stackedRightValue || 0;
} else {
@ -199,14 +206,11 @@ module.exports = DatasetController.extend({
}
}
var rightValue = Number(yScale.getRightValue(value));
if (rightValue < 0) {
return yScale.getPixelForValue(sumNeg + rightValue);
}
return yScale.getPixelForValue(sumPos + rightValue);
}
return yScale.getPixelForValue(value);
return yScale.getPixelForValue(sumPos + rightValue);
},
updateBezierControlPoints: function() {

View File

@ -154,6 +154,14 @@ function positionIsHorizontal(position) {
return position === 'top' || position === 'bottom';
}
function compare2Level(l1, l2) {
return function(a, b) {
return a[l1] === b[l1]
? a[l2] - b[l2]
: a[l1] - b[l1];
};
}
var Chart = function(item, config) {
this.construct(item, config);
return this;
@ -422,6 +430,8 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
meta = me.getDatasetMeta(datasetIndex);
}
meta.type = type;
meta.order = dataset.order || 0;
meta.index = datasetIndex;
if (meta.controller) {
meta.controller.updateIndex(datasetIndex);
@ -513,11 +523,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
// Do this before render so that any plugins that need final scale updates can use it
plugins.notify(me, 'afterUpdate');
me._layers.sort(function(a, b) {
return a.z === b.z
? a._idx - b._idx
: a.z - b.z;
});
me._layers.sort(compare2Level('z', '_idx'));
if (me._bufferedRender) {
me._bufferedRequest = {
@ -717,6 +723,33 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
me.tooltip.transition(easingValue);
},
/**
* @private
*/
_getSortedDatasetMetas: function(filterVisible) {
var me = this;
var datasets = me.data.datasets || [];
var result = [];
var i, ilen;
for (i = 0, ilen = datasets.length; i < ilen; ++i) {
if (!filterVisible || me.isDatasetVisible(i)) {
result.push(me.getDatasetMeta(i));
}
}
result.sort(compare2Level('order', 'index'));
return result;
},
/**
* @private
*/
_getSortedVisibleDatasetMetas: function() {
return this._getSortedDatasetMetas(true);
},
/**
* Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`
* hook, in which case, plugins will not be called on `afterDatasetsDraw`.
@ -724,16 +757,15 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
*/
drawDatasets: function(easingValue) {
var me = this;
var metasets, i;
if (plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
return;
}
// 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);
}
metasets = me._getSortedVisibleDatasetMetas();
for (i = metasets.length - 1; i >= 0; --i) {
me.drawDataset(metasets[i], easingValue);
}
plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
@ -744,12 +776,11 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
* hook, in which case, plugins will not be called on `afterDatasetDraw`.
* @private
*/
drawDataset: function(index, easingValue) {
drawDataset: function(meta, easingValue) {
var me = this;
var meta = me.getDatasetMeta(index);
var args = {
meta: meta,
index: index,
index: meta.index,
easingValue: easingValue
};
@ -829,7 +860,9 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
controller: null,
hidden: null, // See isDatasetVisible() comment
xAxisID: null,
yAxisID: null
yAxisID: null,
order: dataset.order || 0,
index: datasetIndex
};
}

View File

@ -25,17 +25,13 @@ function getRelativePosition(e, chart) {
* @param {function} handler - the callback to execute for each visible item
*/
function parseVisibleItems(chart, handler) {
var datasets = chart.data.datasets;
var meta, i, j, ilen, jlen;
var metasets = chart._getSortedVisibleDatasetMetas();
var metadata, i, j, ilen, jlen, element;
for (i = 0, ilen = datasets.length; i < ilen; ++i) {
if (!chart.isDatasetVisible(i)) {
continue;
}
meta = chart.getDatasetMeta(i);
for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
var element = meta.data[j];
for (i = 0, ilen = metasets.length; i < ilen; ++i) {
metadata = metasets[i].data;
for (j = 0, jlen = metadata.length; j < jlen; ++j) {
element = metadata[j];
if (!element._view.skip) {
handler(element);
}
@ -120,15 +116,12 @@ function indexMode(chart, e, options) {
return [];
}
chart.data.datasets.forEach(function(dataset, datasetIndex) {
if (chart.isDatasetVisible(datasetIndex)) {
var meta = chart.getDatasetMeta(datasetIndex);
var element = meta.data[items[0]._index];
chart._getSortedVisibleDatasetMetas().forEach(function(meta) {
var element = meta.data[items[0]._index];
// don't count items that are skipped (null data)
if (element && !element._view.skip) {
elements.push(element);
}
// don't count items that are skipped (null data)
if (element && !element._view.skip) {
elements.push(element);
}
});

View File

@ -1416,6 +1416,19 @@ var Scale = Element.extend({
me._drawLabels.apply(me, arguments);
}
}];
},
/**
* @private
*/
_getMatchingVisibleMetas: function(type) {
var me = this;
var isHorizontal = me.isHorizontal();
return me.chart._getSortedVisibleDatasetMetas()
.filter(function(meta) {
return (!type || meta.type === type)
&& (isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id);
});
}
});

View File

@ -995,6 +995,9 @@ var exports = Element.extend({
me._active = [];
} else {
me._active = me._chart.getElementsAtEventForMode(e, options.mode, options);
if (options.reverse) {
me._active.reverse();
}
}
// Remember Last Actives

View File

@ -354,12 +354,12 @@ module.exports = {
},
beforeDatasetsDraw: function(chart) {
var count = (chart.data.datasets || []).length - 1;
var metasets = chart._getSortedVisibleDatasetMetas();
var ctx = chart.ctx;
var meta, i, el, view, points, mapper, color;
for (i = count; i >= 0; --i) {
meta = chart.getDatasetMeta(i).$filler;
for (i = metasets.length - 1; i >= 0; --i) {
meta = metasets[i].$filler;
if (!meta || !meta.visible) {
continue;

View File

@ -49,16 +49,15 @@ defaults._set('global', {
// lineJoin :
// lineWidth :
generateLabels: function(chart) {
var data = chart.data;
var datasets = chart.data.datasets;
var options = chart.options.legend || {};
var usePointStyle = options.labels && options.labels.usePointStyle;
return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
var meta = chart.getDatasetMeta(i);
return chart._getSortedDatasetMetas().map(function(meta, i) {
var style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
return {
text: dataset.label,
text: datasets[meta.index].label,
fillStyle: style.backgroundColor,
hidden: !chart.isDatasetVisible(i),
lineCap: style.borderCapStyle,
@ -73,7 +72,7 @@ defaults._set('global', {
// Below is extra data used for toggling the datasets
datasetIndex: i
};
}, this) : [];
}, this);
}
}
},

View File

@ -11,116 +11,113 @@ var defaultConfig = {
}
};
var DEFAULT_MIN = 0;
var DEFAULT_MAX = 1;
function getOrCreateStack(stacks, stacked, meta) {
var key = [
meta.type,
// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
stacked === undefined && meta.stack === undefined ? meta.index : '',
meta.stack
].join('.');
if (stacks[key] === undefined) {
stacks[key] = {
pos: [],
neg: []
};
}
return stacks[key];
}
function stackData(scale, stacks, meta, data) {
var opts = scale.options;
var stacked = opts.stacked;
var stack = getOrCreateStack(stacks, stacked, meta);
var pos = stack.pos;
var neg = stack.neg;
var ilen = data.length;
var i, value;
for (i = 0; i < ilen; ++i) {
value = scale._parseValue(data[i]);
if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden) {
continue;
}
pos[i] = pos[i] || 0;
neg[i] = neg[i] || 0;
if (opts.relativePoints) {
pos[i] = 100;
} else if (value.min < 0 || value.max < 0) {
neg[i] += value.min;
} else {
pos[i] += value.max;
}
}
}
function updateMinMax(scale, meta, data) {
var ilen = data.length;
var i, value;
for (i = 0; i < ilen; ++i) {
value = scale._parseValue(data[i]);
if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden) {
continue;
}
scale.min = Math.min(scale.min, value.min);
scale.max = Math.max(scale.max, value.max);
}
}
module.exports = LinearScaleBase.extend({
determineDataLimits: function() {
var me = this;
var opts = me.options;
var chart = me.chart;
var datasets = chart.data.datasets;
var isHorizontal = me.isHorizontal();
var DEFAULT_MIN = 0;
var DEFAULT_MAX = 1;
var datasetIndex, meta, value, data, i, ilen;
var metasets = me._getMatchingVisibleMetas();
var hasStacks = opts.stacked;
var stacks = {};
var ilen = metasets.length;
var i, meta, data, values;
function IDMatches(datasetMeta) {
return isHorizontal ? datasetMeta.xAxisID === me.id : datasetMeta.yAxisID === me.id;
}
// First Calculate the range
me.min = Number.POSITIVE_INFINITY;
me.max = Number.NEGATIVE_INFINITY;
var hasStacks = opts.stacked;
if (hasStacks === undefined) {
for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
meta = chart.getDatasetMeta(datasetIndex);
if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) && meta.stack !== undefined) {
hasStacks = true;
break;
}
for (i = 0; !hasStacks && i < ilen; ++i) {
meta = metasets[i];
hasStacks = meta.stack !== undefined;
}
}
if (opts.stacked || hasStacks) {
var valuesPerStack = {};
for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
meta = chart.getDatasetMeta(datasetIndex);
var key = [
meta.type,
// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
meta.stack
].join('.');
if (valuesPerStack[key] === undefined) {
valuesPerStack[key] = {
positiveValues: [],
negativeValues: []
};
}
// Store these per type
var positiveValues = valuesPerStack[key].positiveValues;
var negativeValues = valuesPerStack[key].negativeValues;
if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
data = datasets[datasetIndex].data;
for (i = 0, ilen = data.length; i < ilen; i++) {
value = me._parseValue(data[i]);
if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden) {
continue;
}
positiveValues[i] = positiveValues[i] || 0;
negativeValues[i] = negativeValues[i] || 0;
if (value.min === 0 && !opts.ticks.beginAtZero) {
value.min = value.max;
}
if (opts.relativePoints) {
positiveValues[i] = 100;
} else if (value.min < 0 || value.max < 0) {
negativeValues[i] += value.min;
} else {
positiveValues[i] += value.max;
}
}
}
}
helpers.each(valuesPerStack, function(valuesForType) {
var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
me.min = Math.min(me.min, helpers.min(values));
me.max = Math.max(me.max, helpers.max(values));
});
} else {
for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
meta = chart.getDatasetMeta(datasetIndex);
if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
data = datasets[datasetIndex].data;
for (i = 0, ilen = data.length; i < ilen; i++) {
value = me._parseValue(data[i]);
if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden) {
continue;
}
me.min = Math.min(value.min, me.min);
me.max = Math.max(value.max, me.max);
}
}
for (i = 0; i < ilen; ++i) {
meta = metasets[i];
data = datasets[meta.index].data;
if (hasStacks) {
stackData(me, stacks, meta, data);
} else {
updateMinMax(me, meta, data);
}
}
helpers.each(stacks, function(stackValues) {
values = stackValues.pos.concat(stackValues.neg);
me.min = Math.min(me.min, helpers.min(values));
me.max = Math.max(me.max, helpers.max(values));
});
me.min = helpers.isFinite(me.min) && !isNaN(me.min) ? me.min : DEFAULT_MIN;
me.max = helpers.isFinite(me.max) && !isNaN(me.max) ? me.max : DEFAULT_MAX;
// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
this.handleTickRangeOptions();
me.handleTickRangeOptions();
},
// Returns the maximum number of ticks based on the scale dimension

View File

@ -0,0 +1,42 @@
{
"config": {
"type": "bar",
"data": {
"labels": ["2016", "2018", "2020", "2024", "2030"],
"datasets": [{
"backgroundColor": "#FF6384",
"data": [1, null, 3, 4, 5]
}, {
"backgroundColor": "#36A2EB",
"data": [5, 4, 3, null, 1]
}, {
"backgroundColor": "#FFCE56",
"data": [3, 5, 2, null, 4]
}]
},
"options": {
"responsive": false,
"legend": false,
"title": false,
"scales": {
"xAxes": [{
"display": false,
"stacked": true
}],
"yAxes": [{
"display": false,
"stacked": true,
"ticks": {
"beginAtZero": true
}
}]
}
}
},
"options": {
"canvas": {
"height": 256,
"width": 512
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,45 @@
{
"config": {
"type": "bar",
"data": {
"labels": ["2016", "2018", "2020", "2024", "2030"],
"datasets": [{
"backgroundColor": "#FF6384",
"data": [1, null, 3, 4, 5],
"order": 20
}, {
"backgroundColor": "#36A2EB",
"data": [5, 4, 3, null, 1],
"order": 25
}, {
"backgroundColor": "#FFCE56",
"data": [3, 5, 2, null, 4],
"order": 10
}]
},
"options": {
"responsive": false,
"legend": false,
"title": false,
"scales": {
"xAxes": [{
"display": false,
"stacked": true
}],
"yAxes": [{
"display": false,
"stacked": true,
"ticks": {
"beginAtZero": true
}
}]
}
}
},
"options": {
"canvas": {
"height": 256,
"width": 512
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,45 @@
module.exports = {
config: {
type: 'line',
data: {
labels: [0, 1, 2, 3, 4, 5],
datasets: [
{
// option in dataset
data: [3, 1, 2, 0, 8, 1],
backgroundColor: '#ff0000'
},
{
// option in element (fallback)
data: [0, 4, 2, 6, 4, 8],
backgroundColor: '#00ff00'
}
]
},
options: {
legend: false,
title: false,
elements: {
line: {
fill: true
},
point: {
radius: 0
}
},
layout: {
padding: 32
},
scales: {
xAxes: [{display: false}],
yAxes: [{display: false}]
}
}
},
options: {
canvas: {
height: 256,
width: 512
}
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,45 @@
module.exports = {
config: {
type: 'line',
data: {
labels: [0, 1, 2, 3, 4, 5],
datasets: [
{
data: [3, 1, 2, 0, 8, 1],
backgroundColor: '#ff0000',
order: 2
},
{
data: [0, 4, 2, 6, 4, 8],
backgroundColor: '#00ff00',
order: 1
}
]
},
options: {
legend: false,
title: false,
elements: {
line: {
fill: true
},
point: {
radius: 0
}
},
layout: {
padding: 32
},
scales: {
xAxes: [{display: false}],
yAxes: [{display: false}]
}
}
},
options: {
canvas: {
height: 256,
width: 512
}
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,45 @@
module.exports = {
config: {
type: 'line',
data: {
labels: [0, 1, 2, 3, 4, 5],
datasets: [
{
// option in dataset
data: [3, 1, 2, 0, 8, 1],
backgroundColor: '#ff0000'
},
{
// option in element (fallback)
data: [0, 4, 2, 6, 4, 8],
backgroundColor: '#00ff00'
}
]
},
options: {
legend: false,
title: false,
elements: {
line: {
fill: true
},
point: {
radius: 0
}
},
layout: {
padding: 32
},
scales: {
xAxes: [{stacked: true, display: false}],
yAxes: [{stacked: true, display: false}]
}
}
},
options: {
canvas: {
height: 256,
width: 512
}
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,47 @@
module.exports = {
config: {
type: 'line',
data: {
labels: [0, 1, 2, 3, 4, 5],
datasets: [
{
// option in dataset
data: [3, 1, 2, 0, 8, 1],
backgroundColor: '#ff0000',
order: 2
},
{
// option in element (fallback)
data: [0, 4, 2, 6, 4, 8],
backgroundColor: '#00ff00',
order: 1
}
]
},
options: {
legend: false,
title: false,
elements: {
line: {
fill: true
},
point: {
radius: 0
}
},
layout: {
padding: 32
},
scales: {
xAxes: [{stacked: true, display: false}],
yAxes: [{stacked: true, display: false}]
}
}
},
options: {
canvas: {
height: 256,
width: 512
}
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -581,6 +581,165 @@ describe('Core.Tooltip', function() {
expect(tooltip._view.y).toBeCloseToPixel(155);
});
it('Should allow reversing items', function() {
var chart = window.acquireChart({
type: 'line',
data: {
datasets: [{
label: 'Dataset 1',
data: [10, 20, 30],
pointHoverBorderColor: 'rgb(255, 0, 0)',
pointHoverBackgroundColor: 'rgb(0, 255, 0)'
}, {
label: 'Dataset 2',
data: [40, 40, 40],
pointHoverBorderColor: 'rgb(0, 0, 255)',
pointHoverBackgroundColor: 'rgb(0, 255, 255)'
}],
labels: ['Point 1', 'Point 2', 'Point 3']
},
options: {
tooltips: {
mode: 'label',
reverse: true
}
}
});
// Trigger an event over top of the
var meta0 = chart.getDatasetMeta(0);
var point0 = meta0.data[1];
var node = chart.canvas;
var rect = node.getBoundingClientRect();
var evt = new MouseEvent('mousemove', {
view: window,
bubbles: true,
cancelable: true,
clientX: rect.left + point0._model.x,
clientY: rect.top + point0._model.y
});
// Manually trigger rather than having an async test
node.dispatchEvent(evt);
// Check and see if tooltip was displayed
var tooltip = chart.tooltip;
var globalDefaults = Chart.defaults.global;
expect(tooltip._view).toEqual(jasmine.objectContaining({
// Positioning
xAlign: 'left',
yAlign: 'center',
// Text
title: ['Point 2'],
beforeBody: [],
body: [{
before: [],
lines: ['Dataset 2: 40'],
after: []
}, {
before: [],
lines: ['Dataset 1: 20'],
after: []
}],
afterBody: [],
footer: [],
labelColors: [{
borderColor: globalDefaults.defaultColor,
backgroundColor: globalDefaults.defaultColor
}, {
borderColor: globalDefaults.defaultColor,
backgroundColor: globalDefaults.defaultColor
}]
}));
expect(tooltip._view.x).toBeCloseToPixel(267);
expect(tooltip._view.y).toBeCloseToPixel(155);
});
it('Should follow dataset order', function() {
var chart = window.acquireChart({
type: 'line',
data: {
datasets: [{
label: 'Dataset 1',
data: [10, 20, 30],
pointHoverBorderColor: 'rgb(255, 0, 0)',
pointHoverBackgroundColor: 'rgb(0, 255, 0)',
order: 10
}, {
label: 'Dataset 2',
data: [40, 40, 40],
pointHoverBorderColor: 'rgb(0, 0, 255)',
pointHoverBackgroundColor: 'rgb(0, 255, 255)',
order: 5
}],
labels: ['Point 1', 'Point 2', 'Point 3']
},
options: {
tooltips: {
mode: 'label'
}
}
});
// Trigger an event over top of the
var meta0 = chart.getDatasetMeta(0);
var point0 = meta0.data[1];
var node = chart.canvas;
var rect = node.getBoundingClientRect();
var evt = new MouseEvent('mousemove', {
view: window,
bubbles: true,
cancelable: true,
clientX: rect.left + point0._model.x,
clientY: rect.top + point0._model.y
});
// Manually trigger rather than having an async test
node.dispatchEvent(evt);
// Check and see if tooltip was displayed
var tooltip = chart.tooltip;
var globalDefaults = Chart.defaults.global;
expect(tooltip._view).toEqual(jasmine.objectContaining({
// Positioning
xAlign: 'left',
yAlign: 'center',
// Text
title: ['Point 2'],
beforeBody: [],
body: [{
before: [],
lines: ['Dataset 2: 40'],
after: []
}, {
before: [],
lines: ['Dataset 1: 20'],
after: []
}],
afterBody: [],
footer: [],
labelColors: [{
borderColor: globalDefaults.defaultColor,
backgroundColor: globalDefaults.defaultColor
}, {
borderColor: globalDefaults.defaultColor,
backgroundColor: globalDefaults.defaultColor
}]
}));
expect(tooltip._view.x).toBeCloseToPixel(267);
expect(tooltip._view.y).toBeCloseToPixel(155);
});
it('should filter items from the tooltip using the callback', function() {
var chart = window.acquireChart({
type: 'line',

View File

@ -163,6 +163,81 @@ describe('Legend block tests', function() {
}]);
});
it('should reverse correctly', function() {
var chart = window.acquireChart({
type: 'line',
data: {
datasets: [{
label: 'dataset1',
backgroundColor: '#f31',
borderCapStyle: 'round',
borderDash: [2, 2],
borderDashOffset: 5.5,
data: []
}, {
label: 'dataset2',
hidden: true,
borderJoinStyle: 'round',
data: []
}, {
label: 'dataset3',
borderWidth: 10,
borderColor: 'green',
pointStyle: 'crossRot',
fill: false,
data: []
}],
labels: []
},
options: {
legend: {
reverse: true
}
}
});
expect(chart.legend.legendItems).toEqual([{
text: 'dataset3',
fillStyle: 'rgba(0,0,0,0)',
hidden: false,
lineCap: 'butt',
lineDash: [],
lineDashOffset: 0,
lineJoin: 'miter',
lineWidth: 10,
strokeStyle: 'green',
pointStyle: undefined,
rotation: undefined,
datasetIndex: 2
}, {
text: 'dataset2',
fillStyle: 'rgba(0,0,0,0.1)',
hidden: true,
lineCap: 'butt',
lineDash: [],
lineDashOffset: 0,
lineJoin: 'round',
lineWidth: 3,
strokeStyle: 'rgba(0,0,0,0.1)',
pointStyle: undefined,
rotation: undefined,
datasetIndex: 1
}, {
text: 'dataset1',
fillStyle: '#f31',
hidden: false,
lineCap: 'round',
lineDash: [2, 2],
lineDashOffset: 5.5,
lineJoin: 'miter',
lineWidth: 3,
strokeStyle: 'rgba(0,0,0,0.1)',
pointStyle: undefined,
rotation: undefined,
datasetIndex: 0
}]);
});
it('should filter items', function() {
var chart = window.acquireChart({
type: 'bar',