首页 > 解决方案 > 当 ChartJS 中没有重叠数据时,以全宽渲染来自多个数据集的条形图

问题描述

内的例子。作为参考,我使用的是最新版本的 ChartJS (3.2.1) 和最新版本的 react-chartjs-2 (3.0.3)。

我想知道如何在给定多个不同数据集的情况下以特定方式显示我的条形图。我希望图表上的条以标准宽度呈现,同时在必要时允许并排重叠。

当您使用一个数据集时,ChartJS 将以我的“理想”方式处理这个问题,该数据集可能有两个值落在同一个 X 轴坐标上,但在使用多个数据集时我似乎无法模仿这种行为。

似乎每当两个数据集共享一个轴时,条形宽度要么调整以适应两组数据,即使它们不占用相同的空间,或者它们在它们应该占用相同空间时堆叠在一起。我的目标是只在必要时让条“缩小”它们的宽度,否则保持它们的全宽。

这是我希望看到的多个数据集的示例(这就是 ChartJS 在有一个带有barThickness: "flex"集合的数据集时处理渲染的方式):

在中间,您会注意到条形宽度自动调整为彼此腾出空间。 ChartJS 条形宽度,单个数据集

这是我使用两个没有任何重叠点的数据集时得到的示例(barThickness: "flex"两者都设置了): ChartJS 条形宽度,多个数据集

最后,这是一个使用两个数据集时有一些重叠点的示例: 在此处输入图像描述

到目前为止,我什至找到解决此问题的唯一方法是创建多个 x 轴,一个用于一个数据集,一个用于另一个数据集,一个用于重叠。然后,通过操作我的数据结构,为每个轴创建数据集,其中包含与所需条形宽度相对应的数据点。

这当然是一个解决方案,但我正在处理一个生产代码库、数千行数据和几个额外的数据集(所有这些数据集都有不同的状态、可见性条件和规则)。像这样一起管理所有这些几乎是不可能的,更不用说以可维护的方式了。我已经浏览了绝大多数 StackOverflow 问题和 ChartJS 文档,试图找到一个更清洁的解决方案,但到目前为止还不够,希望能得到您的帮助。

以下代码的简化版本。我已经包含了一些未使用的零碎(大部分被注释掉)只是为了展示我迄今为止尝试过的东西:

var ctx1 = document.getElementById("canvas1").getContext("2d");
var ctx2 = document.getElementById("canvas2").getContext("2d");
var ctx3 = document.getElementById("canvas3").getContext("2d");

function getBackgroundColor(data) {
  const bar = data.dataset.data[data.dataIndex];
  return bar.projection ? "green" : "black";
}
const dataset1Labels = ['Mar 2021', 'Apr 2021', 'May 2021', 'Jun 2021', 'Jul 2021', 'Aug 2021']
const dataset2Labels = ['Jan 2020', 'Feb 2020', 'Mar 2020', 'Apr 2020', ...dataset1Labels]
const dataset3Labels = ['Jan 2020', 'Feb 2020', 'Mar 2020', 'Apr 2020', 'May 2020', 'Jun 2020', 'Jul 2020', 'Aug 2020', ...dataset1Labels]

const dataset1 = [
  { x: "Mar 2021", y: 1, projection: false },
  { x: "Apr 2021", y: 4, projection: false },
  { x: "May 2021", y: 6, projection: false },
  { x: "May 2021", y: 9, projection: true },
  { x: "Jun 2021", y: 11, projection: true },
  { x: "Jul 2021", y: 13, projection: true },
  { x: "Aug 2021", y: 16, projection: true },
]
const dataset2 = [
  { x: "Jan 2020", y: 1 },
  { x: "Feb 2020", y: 4 },
  { x: "Mar 2020", y: 6 },
  { x: "Apr 2020", y: 8 },
  { x: "Mar 2021", y: 6 },
  { x: "Apr 2021", y: 8 },
]

const dataset3 = [
  { x: "Jan 2020", y: 1 },
  { x: "Feb 2020", y: 4 },
  { x: "Mar 2020", y: 6 },
  { x: "Apr 2020", y: 8 },
  { x: "May 2020", y: 10 },
  { x: "Jun 2020", y: 12 },
  { x: "Jul 2020", y: 12 },
  { x: "Aug 2020", y: 16 },
  { x: "Mar 2021", y: 1 },
  { x: "Apr 2021", y: 4 },
  { x: "May 2021", y: 6 },
]

var myChart = new Chart(ctx1, {
  type: 'bar',
  data: {
    labels: dataset1Labels,
    datasets: [{
      label: "2 data types, distinguished by color",
      data: dataset1,
      backgroundColor: getBackgroundColor,
      barThickness: "flex",
    }]
  },
  options: {
    plugins: {
      title: {
        display: true,
        text: '1 dataset. Can Overlap. Full width bars.'
      },
      legend: {
        position: "bottom",
      },
    },
    scales: {
      x: {
        id: "dates",
        offset: true,
      },
    }
  }
});

var myChart2 = new Chart(ctx2, {
  type: 'bar',
  data: {
    labels: dataset2Labels,
    datasets: [
    {
      label: "previous year",
      data: dataset2,
      backgroundColor: "blue",
      xAxisID: "dates",

    },
    {
      label: "current year",
      data: dataset1,
      backgroundColor: "green",
    },
  ]},
  options: {
    plugins: {
      title: {
        display: true,
        text: '2 datasets. Cannot Overlap. Full width bars.'
      },
      legend: {
        position: "bottom",
      },
    },
    scales: {
      x: {
        id: "dates2",
        display: false,
        stacked: false,
        bounds: "ticks",
        grid: {
          offset: true,
        },
      },
    }
  }
});

var myChart3 = new Chart(ctx3, {
  type: 'bar',
  data: {
    labels: dataset3Labels,
    datasets: [
    {
      label: "previous year",
      data: dataset3,
      backgroundColor: "blue",
      // group: false,
      // barThickness: "flex",
      // categoryPercentage: 1,
      // barPercentage: 1,
    },
    {
      label: "current year",
      data: dataset1,
      backgroundColor: "green",
      // group: false,
      // categoryPercentage: 1,
      // barThickness: "flex",
      // barPercentage: 1,
    },
  ]},
  options: {
    plugins: {
      title: {
        display: true,
        text: '2 datasets. Can overlap. Half-width bars.'
      },
      legend: {
        position: "bottom",
      },
    },
    scales: {
      x: {
        id: "dates3",
        display: false,
        grid: {
          offset: true,
        },
      },
    }
  }
});
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.2.1/dist/chart.min.js"></script>
<h2>Chart #1</h2>
<canvas id="canvas1"></canvas>
<h2>Chart #2</h2>
<p>Note that March and April 2021 both have data from both datasets, but only one dataset is visible</p>
<canvas id="canvas2"></canvas>
<h2>Chart #3</h2>
<canvas id="canvas3"></canvas>

标签: chart.jsreact-chartjsreact-chartjs-2

解决方案


推荐阅读