From 53a3eb2284dcba06b0b83c706c9aa73e7e0957f8 Mon Sep 17 00:00:00 2001 From: Jukka Kurkela Date: Wed, 23 Oct 2019 02:14:54 +0300 Subject: [PATCH] Implement `dataset.order` (#6268) Allow sorting datasets based on the `order` property --- docs/charts/bar.md | 2 + docs/charts/bubble.md | 10 +- docs/charts/line.md | 2 + docs/charts/mixed.md | 26 +++ docs/charts/polar.md | 1 + docs/charts/radar.md | 3 + docs/charts/scatter.md | 1 + src/controllers/controller.bar.js | 36 ++-- src/controllers/controller.line.js | 24 ++- src/core/core.controller.js | 61 ++++-- src/core/core.interaction.js | 29 ++- src/core/core.scale.js | 13 ++ src/core/core.tooltip.js | 3 + src/plugins/plugin.filler.js | 6 +- src/plugins/plugin.legend.js | 9 +- src/scales/scale.linear.js | 175 +++++++++--------- .../stacking/order-default.json | 42 +++++ .../controller.bar/stacking/order-default.png | Bin 0 -> 3671 bytes .../stacking/order-specified.json | 45 +++++ .../stacking/order-specified.png | Bin 0 -> 3576 bytes .../controller.line/fill/order-default.js | 45 +++++ .../controller.line/fill/order-default.png | Bin 0 -> 12627 bytes test/fixtures/controller.line/fill/order.js | 45 +++++ test/fixtures/controller.line/fill/order.png | Bin 0 -> 11272 bytes .../controller.line/stacking/order-default.js | 45 +++++ .../stacking/order-default.png | Bin 0 -> 10694 bytes .../stacking/order-specified.js | 47 +++++ .../stacking/order-specified.png | Bin 0 -> 10066 bytes test/specs/core.tooltip.tests.js | 159 ++++++++++++++++ test/specs/plugin.legend.tests.js | 75 ++++++++ 30 files changed, 748 insertions(+), 156 deletions(-) create mode 100644 test/fixtures/controller.bar/stacking/order-default.json create mode 100644 test/fixtures/controller.bar/stacking/order-default.png create mode 100644 test/fixtures/controller.bar/stacking/order-specified.json create mode 100644 test/fixtures/controller.bar/stacking/order-specified.png create mode 100644 test/fixtures/controller.line/fill/order-default.js create mode 100644 test/fixtures/controller.line/fill/order-default.png create mode 100644 test/fixtures/controller.line/fill/order.js create mode 100644 test/fixtures/controller.line/fill/order.png create mode 100644 test/fixtures/controller.line/stacking/order-default.js create mode 100644 test/fixtures/controller.line/stacking/order-default.png create mode 100644 test/fixtures/controller.line/stacking/order-specified.js create mode 100644 test/fixtures/controller.line/stacking/order-specified.png diff --git a/docs/charts/bar.md b/docs/charts/bar.md index 328b1df0e19..a4e54915ad4 100644 --- a/docs/charts/bar.md +++ b/docs/charts/bar.md @@ -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. diff --git a/docs/charts/bubble.md b/docs/charts/bubble.md index b94c98c17d5..6536395c279 100644 --- a/docs/charts/bubble.md +++ b/docs/charts/bubble.md @@ -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 diff --git a/docs/charts/line.md b/docs/charts/line.md index bd2a24c98d2..0ad87730182 100644 --- a/docs/charts/line.md +++ b/docs/charts/line.md @@ -54,6 +54,7 @@ The line chart allows a number of properties to be specified for each dataset. T | [`fill`](#line-styling) | boolean|string | 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. diff --git a/docs/charts/mixed.md b/docs/charts/mixed.md index 9f83f2ea6d8..5ead1fb343a 100644 --- a/docs/charts/mixed.md +++ b/docs/charts/mixed.md @@ -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 +}); +``` diff --git a/docs/charts/polar.md b/docs/charts/polar.md index 8403a387230..84275dd9357 100644 --- a/docs/charts/polar.md +++ b/docs/charts/polar.md @@ -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'` diff --git a/docs/charts/radar.md b/docs/charts/radar.md index e5f3b313766..942425ed818 100644 --- a/docs/charts/radar.md +++ b/docs/charts/radar.md @@ -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) | boolean|string | 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 diff --git a/docs/charts/scatter.md b/docs/charts/scatter.md index 0107fd4c238..8fc7726d3d8 100644 --- a/docs/charts/scatter.md +++ b/docs/charts/scatter.md @@ -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 diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index cd07fdbc1de..4fa3f429013 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -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)) { diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index c2d67549bfa..dc1fc689b24 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -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() { diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 694e7764611..04d86a3d97a 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -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 }; } diff --git a/src/core/core.interaction.js b/src/core/core.interaction.js index e163f1182a3..f5051fbff1c 100644 --- a/src/core/core.interaction.js +++ b/src/core/core.interaction.js @@ -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); } }); diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 6a5f7bf012b..29134180cae 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -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); + }); } }); diff --git a/src/core/core.tooltip.js b/src/core/core.tooltip.js index 97f7f16df75..f42ede285a0 100644 --- a/src/core/core.tooltip.js +++ b/src/core/core.tooltip.js @@ -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 diff --git a/src/plugins/plugin.filler.js b/src/plugins/plugin.filler.js index 8acbc40742c..8fed6d9057e 100644 --- a/src/plugins/plugin.filler.js +++ b/src/plugins/plugin.filler.js @@ -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; diff --git a/src/plugins/plugin.legend.js b/src/plugins/plugin.legend.js index 78a5efe7076..c358ff6804c 100644 --- a/src/plugins/plugin.legend.js +++ b/src/plugins/plugin.legend.js @@ -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); } } }, diff --git a/src/scales/scale.linear.js b/src/scales/scale.linear.js index 004b7d8e6ea..1c3da726d7d 100644 --- a/src/scales/scale.linear.js +++ b/src/scales/scale.linear.js @@ -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; - - function IDMatches(datasetMeta) { - return isHorizontal ? datasetMeta.xAxisID === me.id : datasetMeta.yAxisID === me.id; - } + var metasets = me._getMatchingVisibleMetas(); + var hasStacks = opts.stacked; + var stacks = {}; + var ilen = metasets.length; + var i, meta, data, values; - // 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 diff --git a/test/fixtures/controller.bar/stacking/order-default.json b/test/fixtures/controller.bar/stacking/order-default.json new file mode 100644 index 00000000000..53f25a93705 --- /dev/null +++ b/test/fixtures/controller.bar/stacking/order-default.json @@ -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 + } + } +} diff --git a/test/fixtures/controller.bar/stacking/order-default.png b/test/fixtures/controller.bar/stacking/order-default.png new file mode 100644 index 0000000000000000000000000000000000000000..59e10242bb89b7e07baca5387fe506438a7767a9 GIT binary patch literal 3671 zcmeH~YfMvT9LAsH87?1u;g*bR%X09WjMDWQCw$t@OmO zF?A}@EWnh)ZpP>YHzx=R6xpVRqA;d%u@thAl$BB%?v%EBPbpopPy1vtLcjF?p7TEE zZGY!E|K~kNlD8%BR|l;Iz)##9{|>NnY6>#>J5R(08#6sP`{ z$>KRF^23i*>>CiR5#U!UHUj54Pz+HzDQ~{);&YnGMlv7zn>3S)Qa&zF%+5mm-!FdEKq*yubG8wi`Q+4D?XIF5GpXOd z=>gK`M4@_4GXBUCnjUSi3m=4dF&w3sOJ0Q40q6-@Ips0b3XR9^jcX2S{6Sli(cTs2 za#m=KhJ=$fmIGx^V{88g6hzN2487ZOa%xOHIoH-?&FC;3nl$y1BMGKUB~{J!_T024 z*J$g-8P~qwCJqieY8_NooeVjTG}Dt8jJH&gV=)t4osj*c9dMb=DURsSZ!+yJ3d~Nn z6C9?Py)^S7Tard2!sWdXxyuN))z|THj_o?6*|b7eN9iPN*^6-U&_tlzT?XR`8vPt} zv%QD39699ukO#44HvDrSktnI#)WfS7B^hS?zITCyS8 zaR*|_h9o$}>`b=}N$e51$M3h@a*y9j`K;XIcaoJvzFZe_+{3J3a^w4(zWt)-1nJO7 Me0y7bO`QDj-=VNZ(*OVf literal 0 HcmV?d00001 diff --git a/test/fixtures/controller.bar/stacking/order-specified.json b/test/fixtures/controller.bar/stacking/order-specified.json new file mode 100644 index 00000000000..d4f497b0209 --- /dev/null +++ b/test/fixtures/controller.bar/stacking/order-specified.json @@ -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 + } + } +} diff --git a/test/fixtures/controller.bar/stacking/order-specified.png b/test/fixtures/controller.bar/stacking/order-specified.png new file mode 100644 index 0000000000000000000000000000000000000000..b927f337ac9148756ef071f157a06aabd5802e66 GIT binary patch literal 3576 zcmeH}{ZCs}9LAr!EA5;VjBJAyni6NkMAO15vYR zyG5-V3lKL2ls9b%%N!I(vVvu_2|?Ue_ZAUmg$^1SN}(8BOA9NWLiq=bF$VeR-h1vn z=X=lddA`rRXEM@X<80z?0>DYzBi|2fAg2^IvdE#o`c@7ZH>Js6IZ#wTJ^am$&)mF$ zcUvpR8+T7Cx2Bvb!JE&veE7`fD;HFpd%?oNc0owX-qQuiN$+h`q&_e1sy$b?i`ug5 zgP7gUrGqx>{>F!M_U_)h97jL?Thev|Vo-=_>O~G=E+4*zu!bhe)(w;s9og z<<>Fs64}|Rk7yuP)G3Mrn7X=#F*0hgID*-LGCMmbkz9&I;ywzft-HT1fovL-~GSWmE?vk63d>@J}eFjd<={D88a(JJ1ooUPMl>%eC&V+<&Z3 zDmhGFmD(9~vZwUUr#v3CrB&|)Nw!YUq-=muHO+-ah71m_P_j6597Ts17g@NE<_HY$ z#4ryBXeJLCq-i7J2*D*vwi7Rq1mHl$#vr02v6+UI1tZNIK{W?wDds56j8L+8e9uBZ z%vUM%44Sz(Of!d|v_h#~+vNt>=JQ&c)c5k#g6RzO|!6KIYMF!aNbB?Rzt2{$G` zfFj%4rIdLdXmz$A@&lmq$HgUbQz$LlQlvK4 yGN3sa-_YQE^kj&p8gA<7v(?z literal 0 HcmV?d00001 diff --git a/test/fixtures/controller.line/fill/order-default.js b/test/fixtures/controller.line/fill/order-default.js new file mode 100644 index 00000000000..5fcade52611 --- /dev/null +++ b/test/fixtures/controller.line/fill/order-default.js @@ -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 + } + } +}; diff --git a/test/fixtures/controller.line/fill/order-default.png b/test/fixtures/controller.line/fill/order-default.png new file mode 100644 index 0000000000000000000000000000000000000000..6c07bd20b10da8deb10a310e014e052159e2e468 GIT binary patch literal 12627 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 literal 0 HcmV?d00001 diff --git a/test/fixtures/controller.line/stacking/order-default.js b/test/fixtures/controller.line/stacking/order-default.js new file mode 100644 index 00000000000..d8b292e956d --- /dev/null +++ b/test/fixtures/controller.line/stacking/order-default.js @@ -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 + } + } +}; diff --git a/test/fixtures/controller.line/stacking/order-default.png b/test/fixtures/controller.line/stacking/order-default.png new file mode 100644 index 0000000000000000000000000000000000000000..3355da629235094ec460b10b7ca579aaac678661 GIT binary patch literal 10694 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 literal 0 HcmV?d00001 diff --git a/test/fixtures/controller.line/stacking/order-specified.js b/test/fixtures/controller.line/stacking/order-specified.js new file mode 100644 index 00000000000..5a95441343d --- /dev/null +++ b/test/fixtures/controller.line/stacking/order-specified.js @@ -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 + } + } +}; diff --git a/test/fixtures/controller.line/stacking/order-specified.png b/test/fixtures/controller.line/stacking/order-specified.png new file mode 100644 index 0000000000000000000000000000000000000000..ff3edfaf1120ee50120186d18b76e3cac666ff0f GIT binary patch literal 10066 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 PR*ufp(A=O>9~S+8UX#KN literal 0 HcmV?d00001 diff --git a/test/specs/core.tooltip.tests.js b/test/specs/core.tooltip.tests.js index 29c449a8be4..89898677ad7 100755 --- a/test/specs/core.tooltip.tests.js +++ b/test/specs/core.tooltip.tests.js @@ -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', diff --git a/test/specs/plugin.legend.tests.js b/test/specs/plugin.legend.tests.js index 06c8b2cf4c4..1fd4821bb59 100644 --- a/test/specs/plugin.legend.tests.js +++ b/test/specs/plugin.legend.tests.js @@ -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',