]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Add ability to stack different dataset types (#8797)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Sat, 3 Apr 2021 13:23:35 +0000 (16:23 +0300)
committerGitHub <noreply@github.com>
Sat, 3 Apr 2021 13:23:35 +0000 (09:23 -0400)
docs/.vuepress/config.js
docs/charts/bar.md
docs/general/data-structures.md
docs/samples/other-charts/stacked-bar-line.md [new file with mode: 0644]
src/core/core.datasetController.js
test/fixtures/mixed/bar+line-stacked.js [new file with mode: 0644]
test/fixtures/mixed/bar+line-stacked.png [new file with mode: 0644]
test/specs/core.datasetController.tests.js

index 679ac299a6732bf5ba51c1abe63eff93ea245548..6a5595cb5bc9fe32ab002a6ea8688aa8212d17f5 100644 (file)
@@ -126,6 +126,7 @@ module.exports = {
             'other-charts/radar',
             'other-charts/radar-skip-points',
             'other-charts/combo-bar-line',
+            'other-charts/stacked-bar-line',
           ]
         },
         {
index d71b553decabb092cfbbe92b01f428b5c587cb58..d2ea8ba45d6e107832dba8d303a8b8beab3b4e28 100644 (file)
@@ -286,7 +286,7 @@ The following dataset properties are specific to stacked bar charts.
 
 | Name | Type | Description
 | ---- | ---- | -----------
-| `stack` | `string` | The ID of the group to which this dataset belongs to (when stacked, each group will be a separate stack).
+| `stack` | `string` | The ID of the group to which this dataset belongs to (when stacked, each group will be a separate stack). Defaults to `bar`.
 
 ## Horizontal Bar Chart
 
index b66f9e2a59736b374f153765b30933de1fb4bdb0..778aa295ab6763eed70359f327b7bd7f8202e43e 100644 (file)
@@ -67,7 +67,7 @@ In this mode, property name is used for `index` scale and value for `value` scal
 | `label` | `string` | The label for the dataset which appears in the legend and tooltips.
 | `clip` | `number`\|`object` | How to clip relative to chartArea. Positive value allows overflow, negative value clips that many pixels inside chartArea. 0 = clip at chartArea. Clipping can also be configured per side: clip: {left: 5, top: false, right: -2, bottom: 0}
 | `order` | `number` | The drawing order of dataset. Also affects order for stacking, tooltip and legend.
-| `stack` | `string` | The ID of the group to which this dataset belongs to (when stacked, each group will be a separate stack).
+| `stack` | `string` | The ID of the group to which this dataset belongs to (when stacked, each group will be a separate stack). Defaults to dataset `type`.
 | `parsing` | `boolean`\|`object` | How to parse the dataset. The parsing can be disabled by specifying parsing: false at chart options or dataset. If parsing is disabled, data must be sorted and in the formats the associated chart type and scales use internally.
 | `hidden`  | `boolean` | Configure the visibility of the dataset. Using `hidden: true` will hide the dataset from being rendered in the Chart.
 
diff --git a/docs/samples/other-charts/stacked-bar-line.md b/docs/samples/other-charts/stacked-bar-line.md
new file mode 100644 (file)
index 0000000..1afbbd4
--- /dev/null
@@ -0,0 +1,120 @@
+# Stacked bar/line
+
+```js chart-editor
+// <block:actions:2>
+const actions = [
+  {
+    name: 'Randomize',
+    handler(chart) {
+      chart.data.datasets.forEach(dataset => {
+        dataset.data = Utils.numbers({count: chart.data.labels.length, min: 0, max: 100});
+      });
+      chart.update();
+    }
+  },
+  {
+    name: 'Add Dataset',
+    handler(chart) {
+      const data = chart.data;
+      const dsColor = Utils.namedColor(chart.data.datasets.length);
+      const newDataset = {
+        label: 'Dataset ' + (data.datasets.length + 1),
+        backgroundColor: Utils.transparentize(dsColor, 0.5),
+        borderColor: dsColor,
+        borderWidth: 1,
+        stack: 'combined',
+        data: Utils.numbers({count: data.labels.length, min: 0, max: 100}),
+      };
+      chart.data.datasets.push(newDataset);
+      chart.update();
+    }
+  },
+  {
+    name: 'Add Data',
+    handler(chart) {
+      const data = chart.data;
+      if (data.datasets.length > 0) {
+        data.labels = Utils.months({count: data.labels.length + 1});
+
+        for (var index = 0; index < data.datasets.length; ++index) {
+          data.datasets[index].data.push(Utils.rand(0, 100));
+        }
+
+        chart.update();
+      }
+    }
+  },
+  {
+    name: 'Remove Dataset',
+    handler(chart) {
+      chart.data.datasets.pop();
+      chart.update();
+    }
+  },
+  {
+    name: 'Remove Data',
+    handler(chart) {
+      chart.data.labels.splice(-1, 1); // remove the label first
+
+      chart.data.datasets.forEach(dataset => {
+        dataset.data.pop();
+      });
+
+      chart.update();
+    }
+  }
+];
+// </block:actions>
+
+// <block:setup:1>
+const DATA_COUNT = 7;
+const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
+
+const labels = Utils.months({count: 7});
+const data = {
+  labels: labels,
+  datasets: [
+    {
+      label: 'Dataset 1',
+      data: Utils.numbers(NUMBER_CFG),
+      borderColor: Utils.CHART_COLORS.red,
+      backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
+      stack: 'combined',
+      type: 'bar'
+    },
+    {
+      label: 'Dataset 2',
+      data: Utils.numbers(NUMBER_CFG),
+      borderColor: Utils.CHART_COLORS.blue,
+      backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
+      stack: 'combined'
+    }
+  ]
+};
+// </block:setup>
+
+// <block:config:0>
+const config = {
+  type: 'line',
+  data: data,
+  options: {
+    plugins: {
+      title: {
+        display: true,
+        text: 'Chart.js Stacked Line/Bar Chart'
+      }
+    },
+    scales: {
+      y: {
+        stacked: true
+      }
+    }
+  },
+};
+// </block:config>
+
+module.exports = {
+  actions: actions,
+  config: config,
+};
+```
index e1a0f48e91292897657a7ecba264708181b813e4..8d8e9a95ec9435200ee8223934f83f83c3709d78 100644 (file)
@@ -111,7 +111,7 @@ function isStacked(scale, meta) {
 }
 
 function getStackKey(indexScale, valueScale, meta) {
-  return indexScale.id + '.' + valueScale.id + '.' + meta.stack + '.' + meta.type;
+  return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`;
 }
 
 function getUserBounds(scale) {
diff --git a/test/fixtures/mixed/bar+line-stacked.js b/test/fixtures/mixed/bar+line-stacked.js
new file mode 100644 (file)
index 0000000..17f28aa
--- /dev/null
@@ -0,0 +1,40 @@
+module.exports = {
+  config: {
+    data: {
+      datasets: [
+        {
+          type: 'bar',
+          stack: 'mixed',
+          data: [5, 20, 1, 10],
+          backgroundColor: '#00ff00',
+          borderColor: '#ff0000'
+        },
+        {
+          type: 'line',
+          stack: 'mixed',
+          data: [6, 16, 3, 19],
+          borderColor: '#0000ff',
+          fill: false
+        },
+      ]
+    },
+    options: {
+      scales: {
+        x: {
+          axis: 'y',
+          labels: ['a', 'b', 'c', 'd']
+        },
+        y: {
+          stacked: true
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
+};
diff --git a/test/fixtures/mixed/bar+line-stacked.png b/test/fixtures/mixed/bar+line-stacked.png
new file mode 100644 (file)
index 0000000..4768675
Binary files /dev/null and b/test/fixtures/mixed/bar+line-stacked.png differ
index a549679d84989aff4451f9027e25e16e45455b82..d9075754ca4330ab2fcbb843362c4317f8b1d617 100644 (file)
@@ -539,11 +539,11 @@ describe('Chart.DatasetController', function() {
     });
 
     expect(chart._stacks).toEqual({
-      'x.y.1.bar': {
+      'x.y.1': {
         0: {0: 1, 2: 3},
         1: {0: 10, 2: 30}
       },
-      'x.y.2.bar': {
+      'x.y.2': {
         0: {1: 2},
         1: {1: 20}
       }
@@ -553,11 +553,11 @@ describe('Chart.DatasetController', function() {
     chart.update();
 
     expect(chart._stacks).toEqual({
-      'x.y.1.bar': {
+      'x.y.1': {
         0: {0: 1},
         1: {0: 10}
       },
-      'x.y.2.bar': {
+      'x.y.2': {
         0: {1: 2, 2: 3},
         1: {1: 20, 2: 30}
       }
@@ -583,11 +583,11 @@ describe('Chart.DatasetController', function() {
     });
 
     expect(chart._stacks).toEqual({
-      'x.y.1.bar': {
+      'x.y.1': {
         0: {0: 1, 2: 3},
         1: {0: 10, 2: 30}
       },
-      'x.y.2.bar': {
+      'x.y.2': {
         0: {1: 2},
         1: {1: 20}
       }
@@ -597,11 +597,11 @@ describe('Chart.DatasetController', function() {
     chart.update();
 
     expect(chart._stacks).toEqual({
-      'x.y.1.bar': {
+      'x.y.1': {
         0: {0: 1, 2: 4},
         1: {0: 10}
       },
-      'x.y.2.bar': {
+      'x.y.2': {
         0: {1: 2},
         1: {1: 20}
       }