You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Chart.js绘制带垂直边缘的填充面积图的正确实现方式问询

Chart.js绘制带垂直边缘的填充面积图的正确实现方式问询

我在使用Chart.js绘制带垂直边缘的堆叠填充面积图时遇到了一个问题:当多个数据系列存在重复的x值(比如不同任务的起始或结束时间重合)时,图表无法正确渲染出垂直边缘。

目前我临时的解决办法是给重复的x值添加一个极小的偏移量(比如1e-6),让它们变成近似值(比如11.999999)来避开重复,这样图表就能正常显示了,但这种实现方式总感觉不够优雅,肯定有更规范的方法来处理这种垂直边缘的绘制。

我的当前代码

JavaScript

const TASKS = [
  { start: 6.5, end: 23.5, value: 17 },
  { start: 0, end: 12, value: 8 },
  { start: 12, end: 23.5, value: 23 },
  { start: 0, end: 6.5, value: 1 },
  { start: 23.5, end: 24, value: 6 },
];
const COLORS = ["#80dfff80", "#ff80df80", "#dfff8080", "#e5d29980", "#99e5d280"];

function formatTasks(tasks, epsilon) {
  const xValues = [...new Set(tasks.flatMap(task => [task.start, task.end, Math.max(0, task.start - epsilon), task.end - epsilon]))].sort((a, b) => a - b);
  const result = tasks.map(task => xValues.map(x => ({
    x,
    y: x >= task.start && x < task.end ? task.value : 0
  })));
  console.log(result);
  return result;
}

; [0, 1e-6].forEach((EPSILON, chartIndex) => {
  new Chart('chart' + (chartIndex + 1), {
    "type": "scatter",
    "data": {
      "labels": [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23" ],
      "datasets": formatTasks(TASKS, EPSILON).map((data, index) => ({
          "type": "scatter",
          "label": "Task " + (index + 1),
          "yAxisID": "y",
          "showLine": true,
          "pointRadius": 0,
          "pointHoverRadius": 0,
          "borderWidth": 0,
          "borderColor": "transparent",
          "pointStyle": "rect",
          "backgroundColor": COLORS[index],
          "stack": "tasks",
          "fill": index ? "-1" : "origin",
          "data": data,
      })),
    },
    "options": {
      "responsive": true,
      "maintainAspectRatio": false,
      "animation": false,
      "plugins": {
        "legend": {
          "position": "bottom",
          "labels": {
            "usePointStyle": true
          }
        },
      },
      "scales": {
        "x": {
          "min": 0,
          "max": 24,
          "ticks": {
            "minRotation": 0,
            "maxRotation": 0,
            "stepSize": 1
          }
        },
        "y": {
          "type": "linear",
          "position": "left",
          "beginAtZero": true,
          "stacked": true,
          "ticks": {
            "format": {
              "maximumFractionDigits": 0
            }
          }
        },
      }
    }
  })
});

CSS

.chart-container { position: relative; margin: auto; height: 40vh; width: 80vw; min-height: 200px; }

HTML

Chart 1: (Epsilon = 0) 无法正常渲染
<div class="chart-container"><canvas id="chart1"></canvas></div>
Chart 2: (Epsilon = 1e-6) 可以工作,但实现方式不够优雅
<div class="chart-container"><canvas id="chart2"></canvas></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>

问题说明

  • epsilon=0时,由于存在重复的x值,Chart.js无法正确识别垂直边缘,导致填充区域渲染异常;
  • epsilon=1e-6时,通过给x值添加微小偏移避开重复,图表能正常显示,但这种用近似值的方式显然不是最佳方案。

想请教各位,在Chart.js中绘制这种带垂直边缘的堆叠填充面积图,正确的实现方式应该是什么?有没有不需要手动调整x值的方法?

备注:内容来源于stack exchange,提问作者tsh

火山引擎 最新活动