From 64f27952b206982f06201b67aefbc30dc1d44c2a Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Mon, 6 May 2019 15:15:23 -0700 Subject: [PATCH 1/4] Bar options should not be defined on scale --- docs/axes/cartesian/README.md | 2 +- docs/axes/styling.md | 2 +- docs/charts/bar.md | 41 +++++++---- samples/scales/time/financial.html | 5 +- src/controllers/controller.bar.js | 78 +++++++++++++++------ src/helpers/helpers.core.js | 7 ++ src/scales/scale.time.js | 15 ++-- test/specs/controller.bar.tests.js | 107 ++++++++++++++++++++++++++++- test/specs/scale.linear.tests.js | 48 ------------- 9 files changed, 208 insertions(+), 97 deletions(-) diff --git a/docs/axes/cartesian/README.md b/docs/axes/cartesian/README.md index 4a97dfb16b6..386fadc1114 100644 --- a/docs/axes/cartesian/README.md +++ b/docs/axes/cartesian/README.md @@ -15,7 +15,7 @@ All of the included cartesian axes support a number of common options. | ---- | ---- | ------- | ----------- | `type` | `string` | | Type of scale being employed. Custom scales can be created and registered with a string key. This allows changing the type of an axis for a chart. | `position` | `string` | | Position of the axis in the chart. Possible values are: `'top'`, `'left'`, `'bottom'`, `'right'` -| `offset` | `boolean` | `false` | If true, extra space is added to the both edges and the axis is scaled to fit into the chart area. This is set to `true` for a category scale in a bar chart by default. +| `offset` | `boolean` | `false` | If true, extra space is added to the both edges and the axis is scaled to fit into the chart area. This is set to `true` for a bar chart by default. | `id` | `string` | | The ID is used to link datasets and scale axes together. [more...](#axis-id) | `gridLines` | `object` | | Grid line configuration. [more...](../styling.md#grid-line-configuration) | `scaleLabel` | `object` | | Scale title configuration. [more...](../labelling.md#scale-title-configuration) diff --git a/docs/axes/styling.md b/docs/axes/styling.md index c5ae68df693..e7ca3371412 100644 --- a/docs/axes/styling.md +++ b/docs/axes/styling.md @@ -22,7 +22,7 @@ The grid line configuration is nested under the scale configuration in the `grid | `zeroLineColor` | `Color` | `'rgba(0, 0, 0, 0.25)'` | Stroke color of the grid line for the first index (index 0). | `zeroLineBorderDash` | `number[]` | `[]` | Length and spacing of dashes of the grid line for the first index (index 0). See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash). | `zeroLineBorderDashOffset` | `number` | `0.0` | Offset for line dashes of the grid line for the first index (index 0). See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset). -| `offsetGridLines` | `boolean` | `false` | If true, grid lines will be shifted to be between labels. This is set to `true` for a category scale in a bar chart by default. +| `offsetGridLines` | `boolean` | `false` | If true, grid lines will be shifted to be between labels. This is set to `true` for a bar chart by default. | `z` | `number` | `0` | z-index of gridline layer. Values <= 0 are drawn under datasets, > 0 on top. ## Tick Configuration diff --git a/docs/charts/bar.md b/docs/charts/bar.md index a4e54915ad4..9bb8e4c8b43 100644 --- a/docs/charts/bar.md +++ b/docs/charts/bar.md @@ -134,8 +134,8 @@ The interaction with each bar can be controlled with the following properties: All these values, if `undefined`, fallback to the associated [`elements.rectangle.*`](../configuration/elements.md#rectangle-configuration) options. -## Scale Configuration -The bar chart accepts the following configuration from the associated `scale` options: +## Dataset Configuration +The bar chart accepts the following configuration from the associated dataset options: | Name | Type | Default | Description | ---- | ---- | ------- | ----------- @@ -144,6 +144,33 @@ The bar chart accepts the following configuration from the associated `scale` op | `barThickness` | number|string | | Manually set width of each bar in pixels. If set to `'flex'`, it computes "optimal" sample widths that globally arrange bars side by side. If not set (default), bars are equally sized based on the smallest interval. [more...](#barthickness) | `maxBarThickness` | `number` | | Set this to ensure that bars are not sized thicker than this. | `minBarLength` | `number` | | Set this to ensure that bars have a minimum length in pixels. + +### Example Usage + +```javascript +data: { + datasets: [{ + barPercentage: 0.5, + barThickness: 6, + maxBarThickness: 8, + minBarLength: 2, + data: [10, 20, 30, 40, 50, 60, 70] + }] +}; +``` +### barThickness +If this value is a number, it is applied to the width of each bar, in pixels. When this is enforced, `barPercentage` and `categoryPercentage` are ignored. + +If set to `'flex'`, the base sample widths are calculated automatically based on the previous and following samples so that they take the full available widths without overlap. Then, bars are sized using `barPercentage` and `categoryPercentage`. There is no gap when the percentage options are 1. This mode generates bars with different widths when data are not evenly spaced. + +If not set (default), the base sample widths are calculated using the smallest interval that prevents bar overlapping, and bars are sized using `barPercentage` and `categoryPercentage`. This mode always generates bars equally sized. + +## Scale Configuration +The bar chart sets unique default values for the following configuration from the associated `scale` options: + +| Name | Type | Default | Description +| ---- | ---- | ------- | ----------- +| `offset` | `boolean` | `true` | If true, extra space is added to the both edges and the axis is scaled to fit into the chart area. | `gridLines.offsetGridLines` | `boolean` | `true` | If true, the bars for a particular data point fall between the grid lines. The grid line will move to the left by one half of the tick interval. If false, the grid line will go right down the middle of the bars. [more...](#offsetgridlines) ### Example Usage @@ -152,10 +179,6 @@ The bar chart accepts the following configuration from the associated `scale` op options = { scales: { xAxes: [{ - barPercentage: 0.5, - barThickness: 6, - maxBarThickness: 8, - minBarLength: 2, gridLines: { offsetGridLines: true } @@ -163,12 +186,6 @@ options = { } }; ``` -### barThickness -If this value is a number, it is applied to the width of each bar, in pixels. When this is enforced, `barPercentage` and `categoryPercentage` are ignored. - -If set to `'flex'`, the base sample widths are calculated automatically based on the previous and following samples so that they take the full available widths without overlap. Then, bars are sized using `barPercentage` and `categoryPercentage`. There is no gap when the percentage options are 1. This mode generates bars with different widths when data are not evenly spaced. - -If not set (default), the base sample widths are calculated using the smallest interval that prevents bar overlapping, and bars are sized using `barPercentage` and `categoryPercentage`. This mode always generates bars equally sized. ### offsetGridLines If true, the bars for a particular data point fall between the grid lines. The grid line will move to the left by one half of the tick interval, which is the space between the grid lines. If false, the grid line will go right down the middle of the bars. This is set to true for a category scale in a bar chart while false for other scales or chart types by default. diff --git a/samples/scales/time/financial.html b/samples/scales/time/financial.html index c4eb040423f..a402b0e959d 100644 --- a/samples/scales/time/financial.html +++ b/samples/scales/time/financial.html @@ -97,7 +97,6 @@ var color = Chart.helpers.color; var cfg = { - type: 'bar', data: { datasets: [{ label: 'CHRT - Chart.js Corporation', @@ -119,6 +118,7 @@ xAxes: [{ type: 'time', distribution: 'series', + offset: true, ticks: { major: { enabled: true, @@ -158,6 +158,9 @@ } }], yAxes: [{ + gridLines: { + drawBorder: false + }, scaleLabel: { display: true, labelString: 'Closing price ($)' diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index 4fa3f429013..4dd35a220b4 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -5,6 +5,9 @@ var defaults = require('../core/core.defaults'); var elements = require('../elements/index'); var helpers = require('../helpers/index'); +var deprecated = helpers._deprecated; +var valueOrDefault = helpers.valueOrDefault; + defaults._set('bar', { hover: { mode: 'label' @@ -13,8 +16,6 @@ defaults._set('bar', { scales: { xAxes: [{ type: 'category', - categoryPercentage: 0.8, - barPercentage: 0.9, offset: true, gridLines: { offsetGridLines: true @@ -27,6 +28,15 @@ defaults._set('bar', { } }); +defaults._set('global', { + datasets: { + bar: { + categoryPercentage: 0.8, + barPercentage: 0.9 + } + } +}); + /** * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap. * @private @@ -58,10 +68,13 @@ function computeFitCategoryTraits(index, ruler, options) { var thickness = options.barThickness; var count = ruler.stackCount; var curr = ruler.pixels[index]; + var min = helpers.isNullOrUndef(options.barThickness) + ? computeMinSampleSize(ruler.scale, ruler.pixels) + : -1; var size, ratio; if (helpers.isNullOrUndef(thickness)) { - size = ruler.min * options.categoryPercentage; + size = min * options.categoryPercentage; ratio = options.barPercentage; } else { // When bar thickness is enforced, category and bar percentages are ignored. @@ -124,18 +137,30 @@ module.exports = DatasetController.extend({ 'backgroundColor', 'borderColor', 'borderSkipped', - 'borderWidth' + 'borderWidth', + 'barPercentage', + 'barThickness', + 'categoryPercentage', + 'maxBarThickness', + 'minBarLength' ], initialize: function() { var me = this; - var meta; + var meta, scaleOpts; DatasetController.prototype.initialize.apply(me, arguments); meta = me.getMeta(); meta.stack = me.getDataset().stack; meta.bar = true; + + scaleOpts = me._getIndexScale().options; + deprecated('bar chart', scaleOpts.barPercentage, 'scales.[x/y]Axes.barPercentage', 'dataset.barPercentage'); + deprecated('bar chart', scaleOpts.barThickness, 'scales.[x/y]Axes.barThickness', 'dataset.barThickness'); + deprecated('bar chart', scaleOpts.categoryPercentage, 'scales.[x/y]Axes.categoryPercentage', 'dataset.categoryPercentage'); + deprecated('bar chart', me._getValueScale().options.minBarLength, 'scales.[x/y]Axes.minBarLength', 'dataset.minBarLength'); + deprecated('bar chart', scaleOpts.maxBarThickness, 'scales.[x/y]Axes.maxBarThickness', 'dataset.maxBarThickness'); }, update: function(reset) { @@ -173,7 +198,7 @@ module.exports = DatasetController.extend({ rectangle._model.borderSkipped = null; } - me._updateElementGeometry(rectangle, index, reset); + me._updateElementGeometry(rectangle, index, reset, options); rectangle.pivot(); }, @@ -181,15 +206,15 @@ module.exports = DatasetController.extend({ /** * @private */ - _updateElementGeometry: function(rectangle, index, reset) { + _updateElementGeometry: function(rectangle, index, reset, options) { var me = this; var model = rectangle._model; var vscale = me._getValueScale(); var base = vscale.getBasePixel(); var horizontal = vscale.isHorizontal(); var ruler = me._ruler || me.getRuler(); - var vpixels = me.calculateBarValuePixels(me.index, index); - var ipixels = me.calculateBarIndexPixels(me.index, index, ruler); + var vpixels = me.calculateBarValuePixels(me.index, index, options); + var ipixels = me.calculateBarIndexPixels(me.index, index, ruler, options); model.horizontal = horizontal; model.base = reset ? base : vpixels.base; @@ -266,18 +291,13 @@ module.exports = DatasetController.extend({ var me = this; var scale = me._getIndexScale(); var pixels = []; - var i, ilen, min; + var i, ilen; for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) { pixels.push(scale.getPixelForValue(null, i, me.index)); } - min = helpers.isNullOrUndef(scale.options.barThickness) - ? computeMinSampleSize(scale, pixels) - : -1; - return { - min: min, pixels: pixels, start: scale._startPixel, end: scale._endPixel, @@ -290,7 +310,7 @@ module.exports = DatasetController.extend({ * Note: pixel values are not clamped to the scale area. * @private */ - calculateBarValuePixels: function(datasetIndex, index) { + calculateBarValuePixels: function(datasetIndex, index, options) { var me = this; var chart = me.chart; var scale = me._getValueScale(); @@ -298,7 +318,7 @@ module.exports = DatasetController.extend({ 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 minBarLength = 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; @@ -349,9 +369,8 @@ module.exports = DatasetController.extend({ /** * @private */ - calculateBarIndexPixels: function(datasetIndex, index, ruler) { + calculateBarIndexPixels: function(datasetIndex, index, ruler, options) { var me = this; - var options = ruler.scale.options; var range = options.barThickness === 'flex' ? computeFlexCategoryTraits(index, ruler, options) : computeFitCategoryTraits(index, ruler, options); @@ -359,7 +378,7 @@ module.exports = DatasetController.extend({ var stackIndex = me.getStackIndex(datasetIndex, me.getMeta().stack); var center = range.start + (range.chunk * stackIndex) + (range.chunk / 2); var size = Math.min( - helpers.valueOrDefault(options.maxBarThickness, Infinity), + valueOrDefault(options.maxBarThickness, Infinity), range.chunk * range.ratio); return { @@ -389,5 +408,24 @@ module.exports = DatasetController.extend({ } helpers.canvas.unclipArea(chart.ctx); + }, + + /** + * @private + */ + _resolveDataElementOptions: function() { + var me = this; + var values = helpers.extend({}, DatasetController.prototype._resolveDataElementOptions.apply(me, arguments)); + var indexOpts = me._getIndexScale().options; + var valueOpts = me._getValueScale().options; + + values.barPercentage = valueOrDefault(indexOpts.barPercentage, values.barPercentage); + values.barThickness = valueOrDefault(indexOpts.barThickness, values.barThickness); + values.categoryPercentage = valueOrDefault(indexOpts.categoryPercentage, values.categoryPercentage); + values.maxBarThickness = valueOrDefault(indexOpts.maxBarThickness, values.maxBarThickness); + values.minBarLength = valueOrDefault(valueOpts.minBarLength, values.minBarLength); + + return values; } + }); diff --git a/src/helpers/helpers.core.js b/src/helpers/helpers.core.js index a97b2f7e814..350a2075091 100644 --- a/src/helpers/helpers.core.js +++ b/src/helpers/helpers.core.js @@ -306,6 +306,13 @@ var helpers = { ChartElement.__super__ = me.prototype; return ChartElement; + }, + + _deprecated: function(scope, value, previous, current) { + if (value !== undefined) { + console.warn(scope + ': "' + previous + + '" is deprecated. Please use "' + current + '" instead'); + } } }; diff --git a/src/scales/scale.time.js b/src/scales/scale.time.js index 38428c8ffd7..ec107904253 100644 --- a/src/scales/scale.time.js +++ b/src/scales/scale.time.js @@ -5,6 +5,7 @@ var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); var Scale = require('../core/core.scale'); +var deprecated = helpers._deprecated; var resolve = helpers.options.resolve; var valueOrDefault = helpers.valueOrDefault; @@ -61,14 +62,6 @@ var INTERVALS = { var UNITS = Object.keys(INTERVALS); -function deprecated(value, previous, current) { - if (value !== undefined) { - console.warn( - 'time scale: "' + previous + '" is deprecated. ' + - 'Please use "' + current + '" instead'); - } -} - function sorter(a, b) { return a - b; } @@ -460,9 +453,9 @@ module.exports = Scale.extend({ var adapter = me._adapter = new adapters._date(options.adapters.date); // DEPRECATIONS: output a message only one time per update - deprecated(time.format, 'time.format', 'time.parser'); - deprecated(time.min, 'time.min', 'ticks.min'); - deprecated(time.max, 'time.max', 'ticks.max'); + deprecated('time scale', time.format, 'time.format', 'time.parser'); + deprecated('time scale', time.min, 'time.min', 'ticks.min'); + deprecated('time scale', time.max, 'time.max', 'ticks.max'); // Backward compatibility: before introducing adapter, `displayFormats` was // supposed to contain *all* unit/string pairs but this can't be resolved diff --git a/test/specs/controller.bar.tests.js b/test/specs/controller.bar.tests.js index 4b33c939c61..3874c3325df 100644 --- a/test/specs/controller.bar.tests.js +++ b/test/specs/controller.bar.tests.js @@ -1514,9 +1514,10 @@ describe('Chart.controllers.bar', function() { var chart = window.acquireChart(this.config); var meta = chart.getDatasetMeta(0); var xScale = chart.scales[meta.xAxisID]; + var options = Chart.defaults.global.datasets.bar; - var categoryPercentage = xScale.options.categoryPercentage; - var barPercentage = xScale.options.barPercentage; + var categoryPercentage = options.categoryPercentage; + var barPercentage = options.barPercentage; var stacked = xScale.options.stacked; var totalBarWidth = 0; @@ -1690,7 +1691,7 @@ describe('Chart.controllers.bar', function() { expected = barThickness; } else { var scale = chart.scales.x; - var options = chart.options.scales.xAxes[0]; + var options = Chart.defaults.global.datasets.bar; var categoryPercentage = options.categoryPercentage; var barPercentage = options.barPercentage; var tickInterval = scale.getPixelForTick(1) - scale.getPixelForTick(0); @@ -1706,6 +1707,21 @@ describe('Chart.controllers.bar', function() { }); it('should correctly set bar width if maxBarThickness is specified', function() { + var chart = this.chart; + var i, ilen, meta; + + chart.data.datasets[0].maxBarThickness = 10; + chart.data.datasets[1].maxBarThickness = 10; + chart.update(); + + for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) { + meta = chart.getDatasetMeta(i); + expect(meta.data[0]._model.width).toBeCloseToPixel(10); + expect(meta.data[1]._model.width).toBeCloseToPixel(10); + } + }); + + it('should correctly set bar width if maxBarThickness is specified via deprecated option', function() { var chart = this.chart; var options = chart.options.scales.xAxes[0]; var i, ilen, meta; @@ -1722,4 +1738,89 @@ describe('Chart.controllers.bar', function() { }); }); }); + + it('minBarLength settings should be used on Y axis on bar chart', function() { + var minBarLength = 4; + var chart = window.acquireChart({ + type: 'bar', + data: { + datasets: [{ + minBarLength: minBarLength, + data: [0.05, -0.05, 10, 15, 20, 25, 30, 35] + }] + } + }); + + var data = chart.getDatasetMeta(0).data; + + expect(data[0]._model.base - minBarLength).toEqual(data[0]._model.y); + expect(data[1]._model.base + minBarLength).toEqual(data[1]._model.y); + }); + + it('minBarLength settings should be used on X axis on horizontalBar chart', function() { + var minBarLength = 4; + var chart = window.acquireChart({ + type: 'horizontalBar', + data: { + datasets: [{ + minBarLength: minBarLength, + data: [0.05, -0.05, 10, 15, 20, 25, 30, 35] + }] + } + }); + + var data = chart.getDatasetMeta(0).data; + + expect(data[0]._model.base + minBarLength).toEqual(data[0]._model.x); + expect(data[1]._model.base - minBarLength).toEqual(data[1]._model.x); + }); + + it('deprecated minBarLength settings should be used on Y axis on bar chart', function() { + var minBarLength = 4; + var chart = window.acquireChart({ + type: 'bar', + data: { + datasets: [{ + data: [0.05, -0.05, 10, 15, 20, 25, 30, 35] + }] + }, + options: { + scales: { + yAxes: [{ + minBarLength: minBarLength + }] + } + } + }); + + var data = chart.getDatasetMeta(0).data; + + expect(data[0]._model.base - minBarLength).toEqual(data[0]._model.y); + expect(data[1]._model.base + minBarLength).toEqual(data[1]._model.y); + }); + + it('deprecated minBarLength settings should be used on X axis on horizontalBar chart', function() { + var minBarLength = 4; + var chart = window.acquireChart({ + type: 'horizontalBar', + data: { + datasets: [{ + data: [0.05, -0.05, 10, 15, 20, 25, 30, 35] + }] + }, + options: { + scales: { + xAxes: [{ + minBarLength: minBarLength + }] + } + } + }); + + var data = chart.getDatasetMeta(0).data; + + expect(data[0]._model.base + minBarLength).toEqual(data[0]._model.x); + expect(data[1]._model.base - minBarLength).toEqual(data[1]._model.x); + }); + }); diff --git a/test/specs/scale.linear.tests.js b/test/specs/scale.linear.tests.js index ce59280028e..e99d101d785 100644 --- a/test/specs/scale.linear.tests.js +++ b/test/specs/scale.linear.tests.js @@ -1124,54 +1124,6 @@ describe('Linear Scale', function() { expect(chart.scales['x-axis-0'].max).toEqual(0); }); - it('minBarLength settings should be used on Y axis on bar chart', function() { - var minBarLength = 4; - var chart = window.acquireChart({ - type: 'bar', - data: { - datasets: [{ - data: [0.05, -0.05, 10, 15, 20, 25, 30, 35] - }] - }, - options: { - scales: { - yAxes: [{ - minBarLength: minBarLength - }] - } - } - }); - - var data = chart.getDatasetMeta(0).data; - - expect(data[0]._model.base - minBarLength).toEqual(data[0]._model.y); - expect(data[1]._model.base + minBarLength).toEqual(data[1]._model.y); - }); - - it('minBarLength settings should be used on X axis on horizontalBar chart', function() { - var minBarLength = 4; - var chart = window.acquireChart({ - type: 'horizontalBar', - data: { - datasets: [{ - data: [0.05, -0.05, 10, 15, 20, 25, 30, 35] - }] - }, - options: { - scales: { - xAxes: [{ - minBarLength: minBarLength - }] - } - } - }); - - var data = chart.getDatasetMeta(0).data; - - expect(data[0]._model.base + minBarLength).toEqual(data[0]._model.x); - expect(data[1]._model.base - minBarLength).toEqual(data[1]._model.x); - }); - it('Should generate max and min that are not equal when data contains values that are very close to each other', function() { var chart = window.acquireChart({ type: 'scatter', From 42194cb409eea26f56cb9c130658162270f05795 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Thu, 24 Oct 2019 08:11:31 -0700 Subject: [PATCH 2/4] Improve minimization --- src/controllers/controller.bar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index 4dd35a220b4..e56d03ec552 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -68,7 +68,7 @@ function computeFitCategoryTraits(index, ruler, options) { var thickness = options.barThickness; var count = ruler.stackCount; var curr = ruler.pixels[index]; - var min = helpers.isNullOrUndef(options.barThickness) + var min = helpers.isNullOrUndef(thickness) ? computeMinSampleSize(ruler.scale, ruler.pixels) : -1; var size, ratio; From a7a83ecd0889d4829c025c352a84d539b95947be Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Thu, 24 Oct 2019 12:32:25 -0700 Subject: [PATCH 3/4] Add tests --- .../bar-thickness-per-dataset-stacked.json | 55 ++++++++++++++++++ .../bar-thickness-per-dataset-stacked.png | Bin 0 -> 5747 bytes .../bar-thickness-per-dataset.json | 43 ++++++++++++++ .../bar-thickness-per-dataset.png | Bin 0 -> 5484 bytes 4 files changed, 98 insertions(+) create mode 100644 test/fixtures/controller.bar/bar-thickness-per-dataset-stacked.json create mode 100644 test/fixtures/controller.bar/bar-thickness-per-dataset-stacked.png create mode 100644 test/fixtures/controller.bar/bar-thickness-per-dataset.json create mode 100644 test/fixtures/controller.bar/bar-thickness-per-dataset.png diff --git a/test/fixtures/controller.bar/bar-thickness-per-dataset-stacked.json b/test/fixtures/controller.bar/bar-thickness-per-dataset-stacked.json new file mode 100644 index 00000000000..29210110ff2 --- /dev/null +++ b/test/fixtures/controller.bar/bar-thickness-per-dataset-stacked.json @@ -0,0 +1,55 @@ +{ + "config": { + "data": { + "labels": ["2016", "2018", "2020", "2024", "2030"], + "datasets": [{ + "type": "bar", + "barThickness": 16, + "backgroundColor": "#FF6384", + "data": [1, null, 3, 4, 5] + }, { + "type": "bar", + "barThickness": 8, + "backgroundColor": "#36A2EB", + "data": [5, 4, 3, null, 1] + }, { + "type": "bar", + "barThickness": 4, + "backgroundColor": "#FFCE56", + "data": [3, 5, 2, null, 4] + }] + }, + "options": { + "responsive": false, + "legend": false, + "title": false, + "scales": { + "xAxes": [{ + "type": "time", + "offset": true, + "stacked": true, + "display": false, + "time": { + "parser": "YYYY" + }, + "ticks": { + "source": "labels" + } + }], + "yAxes": [{ + "display": false, + "stacked": true, + "ticks": { + "beginAtZero": true + } + }] + } + } + }, + "options": { + "canvas": { + "height": 256, + "width": 512 + } + } +} diff --git a/test/fixtures/controller.bar/bar-thickness-per-dataset-stacked.png b/test/fixtures/controller.bar/bar-thickness-per-dataset-stacked.png new file mode 100644 index 0000000000000000000000000000000000000000..5e6f1538ee0a8a9f5367cf0d3069650e1621f08b GIT binary patch literal 5747 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 Date: Fri, 25 Oct 2019 06:06:49 -0700 Subject: [PATCH 4/4] Multiple datasets in test --- .../bar-thickness-per-dataset.json | 5 +++++ .../bar-thickness-per-dataset.png | Bin 5484 -> 6179 bytes 2 files changed, 5 insertions(+) diff --git a/test/fixtures/controller.bar/bar-thickness-per-dataset.json b/test/fixtures/controller.bar/bar-thickness-per-dataset.json index 713b55589c8..88f4ff1dc7d 100644 --- a/test/fixtures/controller.bar/bar-thickness-per-dataset.json +++ b/test/fixtures/controller.bar/bar-thickness-per-dataset.json @@ -7,6 +7,11 @@ "barThickness": 16, "backgroundColor": "#FF6384", "data": [1, null, 3, 4, 5] + }, { + "type": "bar", + "barThickness": 8, + "backgroundColor": "#36A2EB", + "data": [5, 4, 3, null, 1] }] }, "options": { diff --git a/test/fixtures/controller.bar/bar-thickness-per-dataset.png b/test/fixtures/controller.bar/bar-thickness-per-dataset.png index 231e1e1bbc7b5d3eb673e1026e427eafe7d2cdb3..1db187bdb956777be6abaa18455e082ab3dbd8b8 100644 GIT binary patch literal 6179 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