React:chartjs 负区域不同颜色

问题描述 投票:0回答:1

我使用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} />;
}


这是当前结果

这是预期的结果

javascript reactjs chart.js react-chartjs-2
1个回答
0
投票

要根据颜色设置填充,可以使用

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>

© www.soinside.com 2019 - 2024. All rights reserved.