我使用chartjs和react-chartjs-2折线图表示正值和负值,对于正值我希望填充区域为绿色,负值区域为红色。
https://codesandbox.io/p/devbox/recursing-drake-v2rsj7
import React from "react";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Filler,
Legend,
} from "chart.js";
import { Line } from "react-chartjs-2";
import faker from "faker";
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Filler,
Legend,
);
export const options = {
responsive: true,
plugins: {
legend: {
display: false,
position: "top" as const,
},
title: {
display: false,
text: "Chart.js Line Chart",
},
},
scales: {
x: {
grid: {
display: false, // Hides X-axis grid lines
},
ticks: {
display: false, // Hides X-axis labels
},
border: {
display: false, // Hides X-axis border line
},
},
y: {
grid: {
display: false, // Hides Y-axis grid lines
},
ticks: {
display: false, // Hides Y-axis labels
},
border: {
display: false, // Hides X-axis border line
},
},
},
};
const generateChartData = () => {
const values = [3000, 4000, -1000, -2000, 2000, 3000, 5000];
const backgroundColors = values.map((val) =>
val >= 0 ? "rgba(50, 183, 73, 0.2)" : "rgba(212, 68, 90, 0.2)",
);
return {
labels: [
"Page A",
"Page B",
"Page C",
"Page D",
"Page E",
"Page F",
"Page G",
],
datasets: [
{
label: "Dataset 1",
data: values,
fill: true,
backgroundColor: backgroundColors,
borderColor: "rgb(75, 192, 192)",
tension: 0.4,
},
],
};
};
export function App() {
const data = generateChartData();
return <Line options={options} data={data} />;
}
这是预期的结果
要根据颜色设置填充,可以使用
fill
属性
与 target
、above
和 below
,按照 文档。
设置线条的颜色比较复杂,据我所知, 根据值的不同,没有选项可以做到这一点。所以一个人必须 计算每个段的颜色,这涉及一些插值 对于那些与
y
轴相交的线段。
即便如此,这也是线性插值,如果
tension
使用高值
并且点很稀疏(间隔很大),这和之间的区别
实际的三次曲线可能会在交叉点处变得可见。
这是一个可能的实现:基于您的示例:
const values = [3000, 4000, -1000, -2000, 2000, 3000, 5000];
const lineColorPlus = "rgba(50, 183, 73, 0.75)",
lineColorMinus = "rgba(212, 68, 90, 0.75)";
const data = {
labels: [
"Page A",
"Page B",
"Page C",
"Page D",
"Page E",
"Page F",
"Page G",
],
datasets: [
{
label: 'Dataset 1',
data: values,
tension: 0.4,
segment: {
borderWidth: 4,
borderColor: function(dataCtx){
const {p0, p1, p0DataIndex, p1DataIndex, datasetIndex, chart} = dataCtx;
const y0 = data.datasets[datasetIndex].data[p0DataIndex],
y1 = data.datasets[datasetIndex].data[p1DataIndex];
if(y0 >= 0 && y1 >= 0){
return lineColorPlus;
}
if(y0 <= 0 && y1 <= 0){
return lineColorMinus;
}
const frac = Math.abs(y0 / (y0 - y1));
const xg0 = p0.$animations?.x?._to || p0.x,
yg0 = p0.$animations?.y?._to || p0.y,
xg1 = p1.$animations?.x?._to || p1.x,
yg1 = p1.$animations?.y?._to || p1.y;
const ctx = chart.ctx;
const gradient = ctx.createLinearGradient(xg0, yg0, xg1, yg1);
const [col1, col2] = (y0 <= 0) ? [lineColorMinus, lineColorPlus] : [lineColorPlus, lineColorMinus] ;
gradient.addColorStop(0, col1);
gradient.addColorStop(frac, col1);
gradient.addColorStop(frac, col2);
gradient.addColorStop(1, col2);
return gradient;
},
},
pointRadius: 0,
fill: {
target: 'origin',
above: "rgba(50, 183, 73, 0.5)",
below: "rgba(212, 68, 90, 0.5)"
}
}
]
};
const config = {
type: 'line',
data: data,
options: {
responsive: true,
},
};
new Chart(document.querySelector('#chart1'), config);
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js" integrity="sha512-ZwR1/gSZM3ai6vCdI+LVF1zSq/5HznD3ZSTk7kajkaj4D292NLuduDCO1c/NT8Id+jE58KYLKT7hXnbtryGmMg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div style="min-height: 60vh">
<canvas id="chart1">
</canvas>
</div>