如何使用 ChartJS v3 创建一个简单的 Gauge?

How to create a simple Gauge with ChartJS v3?

我在以前的项目中使用 ChartJS v2 创建仪表,如下所示:

在 React 集成期间,我需要做同样的事情,但是这个库的新安装的 v3 版本,从 Donut 修改本身开始。

这是当前配置:

export const GaugeChart: VFC<GaugeChartProps> = ({
  value,
  max = 100,
})  => {
  const percent = value / max;

  return <ChartJS
    type="doughnut"
    data={{
      datasets: [
        {
          backgroundColor: [
            'rgb(255, 99, 132)',
            '#ccc',
          ],
          data: [
            percent * 100,
            100 - (percent * 100),
          ],
        },
      ],
    }}
    options={{
      rotation: -1.0 * Math.PI, // start angle in radians
      circumference: Math.PI, // sweep angle in radians
    }}
  />
};

注意:typedataoptions 道具是 ChartJS 配置本身的一部分,组件只是一个包装器。

这是我得到的:

我错过了什么?

根据 v3 中的 migration guiderotationcircumference 选项以度数而不是弧度为单位,如果您将它们作为度数放置它就可以正常工作:

var options = {
  type: 'doughnut',
  data: {
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
    datasets: [{
      label: '# of Votes',
      data: [12, 19, 3, 5, 2, 3],
      backgroundColor: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"]
    }]
  },
  options: {
    rotation: 270, // start angle in degrees
    circumference: 180, // sweep angle in degrees
  }
}

var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
  <canvas id="chartJSContainer" width="600" height="400"></canvas>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.js"></script>
</body>

这是我使用的示例,它适用于 3.5.1 版

HTML

<div class="chartBox">
  <canvas id="gauge"></canvas>
</div>

CSS

.chartBox {
  width: 400px;
  padding: 20px;
  border-radius: 20px;
}

JavaScript

// setup
const data = {
  labels: ["Safe", "Risky", "High Risk"],
  datasets: [
    {
      label: "Gauge",
      data: [100, 65, 35],
      backgroundColor: [
        "rgba(75, 192, 192, 0.8)",
        "rgba(255, 206, 86, 0.8)",
        "rgba(255, 26, 104, 0.8)",
      ],
      needleValue: 50,
      borderColor: "white",
      borderWidth: 2,
      cutout: "95%",
      circumference: 180,
      rotation: 270,
      borderRadius: 5,
    },
  ],
};

//gaugeNeedle
const gaugeNeedle = {
  id: "gaugeNeedle",
  afterDatasetDraw(chart, args, options) {
    const {
      ctx,
      config,
      data,
      chartArea: { top, right, bottom, left, width, height },
    } = chart;
    ctx.save();
    const needleValue = data.datasets[0].needleValue;
    const dataTotal = data.datasets[0].data.reduce((a, b) => a + b, 0);

    if (needleValue <= 100) {
      var angle = Math.PI + (1 / 200) * needleValue * Math.PI;
      console.log(angle);
    } else if (needleValue <= 10000) {
      var angle =
        Math.PI +
        (1 / 200) * 100 * Math.PI +
        ((1 / 200) * needleValue * Math.PI * 65) / 10000;
    } else if (needleValue <= 1000000) {
      var angle =
        Math.PI +
        (1 / 200) * 100 * Math.PI +
        ((1 / 200) * 10000 * Math.PI * 65) / 10000 +
        ((1 / 200) * needleValue * Math.PI * 35) / 1000000;
    } else {
      var angle = 0;
    }

    const cx = width / 2;
    const cy = chart._metasets[0].data[0].y;

    //needle
    ctx.translate(cx, cy);
    ctx.rotate(angle);
    ctx.beginPath();
    ctx.moveTo(0, -2);
    ctx.lineTo(height - ctx.canvas.offsetTop - 160, 0); // change 160 value if the needle size gets changed
    ctx.lineTo(0, 2);
    ctx.fillStyle = "#444";
    ctx.fill();
    //needle dot
    ctx.translate(-cx, -cy);
    ctx.beginPath();
    ctx.arc(cx, cy, 5, 0, 10);
    ctx.fill();
    ctx.restore();

    //text
    ctx.font = "20px Ubuntu";
    ctx.fillStyle = "#444";
    ctx.fillText(needleValue + " CPM", cx, cy + 50);
    ctx.font = "10px Ubuntu";
    ctx.fillText(0, 5, cy + 20);
    ctx.fillText(100, cx, 90);
    ctx.fillText("10k", cx + 185, 200); // change values if the position gets changed
    ctx.fillText("1M", cx + 193, 320); // change values if the position gets changed
    ctx.textAlign = "center";
    ctx.restore();
  },
};
// config
const config = {
  type: "doughnut",
  data,
  options: {
    plugins: {
      legend: {
        display: false,
      },
      tooltip: {
        yAlign: "bottom",
        displayColors: false,
        callbacks: {
          label: function (tooltipItem, data, value) {
            return tooltipItem.label;
          },
        },
      },
    },
  },
  plugins: [gaugeNeedle],
};

// render init block
const myChart = new Chart(document.getElementById("gauge"), config);

注意:宽度设置为 400px 时效果很好。如果更改此值,则需要相应地更改其他参数。但是,受影响的位置在 JavaScript.

中进行了评论