如何使用 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
}}
/>
};
注意:type
、data
和 options
道具是 ChartJS 配置本身的一部分,组件只是一个包装器。
这是我得到的:
我错过了什么?
根据 v3 中的 migration guide,rotation
和 circumference
选项以度数而不是弧度为单位,如果您将它们作为度数放置它就可以正常工作:
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.
中进行了评论
我在以前的项目中使用 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
}}
/>
};
注意:type
、data
和 options
道具是 ChartJS 配置本身的一部分,组件只是一个包装器。
这是我得到的:
我错过了什么?
根据 v3 中的 migration guide,rotation
和 circumference
选项以度数而不是弧度为单位,如果您将它们作为度数放置它就可以正常工作:
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.
中进行了评论