You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中Chart.js折线图正负数值区域设置不同填充色问题

折线图正负值区域分色填充问题解决

问题说明

使用Chart.js + react-chartjs-2绘制折线图,需求是正值对应的填充区域为绿色半透明,负值对应的填充区域为红色半透明,但当前实现效果不符合预期:

当前效果:
当前效果

预期效果:
预期效果

原实现代码:

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} />;
}

解决方案

原代码为每个数据点单独设置背景色的方式无法实现区域按正负分割填充,需要利用Chart.js的线性渐变功能,结合Y轴0刻度的像素位置划分颜色:

修改后的完整代码

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";

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,
      },
      ticks: {
        display: false,
      },
      border: {
        display: false,
      },
    },
    y: {
      grid: {
        display: false,
      },
      ticks: {
        display: false,
      },
      border: {
        display: false,
      },
    },
  },
};

const generateChartData = (chart) => {
  const values = [3000, 4000, -1000, -2000, 2000, 3000, 5000];
  let gradient;

  if (chart) {
    const ctx = chart.ctx;
    const yAxis = chart.scales.y;
    // 获取Y轴上最大值、0值、最小值对应的像素位置
    const topPixel = yAxis.getPixelForValue(Math.max(...values));
    const zeroPixel = yAxis.getPixelForValue(0);
    const bottomPixel = yAxis.getPixelForValue(Math.min(...values));

    // 创建垂直线性渐变
    gradient = ctx.createLinearGradient(0, topPixel, 0, bottomPixel);
    // 渐变颜色节点:0值以上为绿色半透明,以下为红色半透明
    gradient.addColorStop(0, "rgba(50, 183, 73, 0.2)");
    gradient.addColorStop((zeroPixel - topPixel) / (bottomPixel - topPixel), "rgba(50, 183, 73, 0.2)");
    gradient.addColorStop((zeroPixel - topPixel) / (bottomPixel - topPixel), "rgba(212, 68, 90, 0.2)");
    gradient.addColorStop(1, "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: "origin", // 设置填充到Y轴原点(0线)
        backgroundColor: gradient || "rgba(75, 192, 192, 0.2)",
        borderColor: "rgb(75, 192, 192)",
        tension: 0.4,
      },
    ],
  };
};

export function App() {
  // 将generateChartData作为data传入,Chart会自动传入chart实例
  return <Line options={options} data={generateChartData} />;
}

关键修改点

  1. 渐变计算:通过chart实例获取Y轴的像素位置,创建以0值为分界的垂直线性渐变
  2. 填充目标设置:将fill设为'origin',让填充区域从折线延伸到Y轴0线,而非默认的图表底部
  3. 动态数据生成:将generateChartData改为接收chart实例的函数,确保渐变能基于实际图表尺寸计算

内容的提问来源于stack exchange,提问作者FeelRightz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 17:57:14