使用Chart Js为正值和负值提供不同的折线图边框颜色

w41d8nur  于 2023-05-17  发布在  Chart.js
关注(0)|答案(1)|浏览(146)

我已经使用charts JS创建了一个折线图,但我无法应用线条颜色更改。期望应该是:如果y值小于0(零),则该线应为红色,如果大于0(零)绿色。
我在这里创建了我的代码:codesandbox
我尝试使用数据集段borderColor;如果y值<0,我将颜色设置为红色,否则如果y值>0,颜色为绿色,但它并不像预期的那样工作。
在数据集中,我有{x: 42380, y: negative value (which is near by zero)},后面是{x: 42500, y: POSITIVE value(which very first positive value)}];这两个点之间的线段显示为红色,尽管从y = -185到0的负部分比从0到y = 2000的正部分短得多

ldioqlga

ldioqlga1#

根据点的符号改变线颜色的解决方案已经通过将borderColor设置为segment s来实现,并且对于具有相同符号的两端的所有段都工作良好;配置对象为

datasets:[{
    data: ....
    .......
    segment: {
        borderColor: (ctx) => {
            return getBorderColor(ctx);
        }
    },
}]

实际的计算在函数getBorderColor中实现(从原始的稍微修改,以简化下面我的扩展的介绍):

const getBorderColor = 
        (ctx, colPositive = "green", colNegative = "red") => {
    return ctx.p0.parsed.y >= 0 ? colPositive : colNegative;
};

为了适应与x轴相交的线段,我找到的解决方案是将颜色设置为LinearGradient,其中有四个color stops,如下表所示:

point:    p0       x-axis intersection      p1
coordinates:  (x0, y0)        (_, 0)           (x1, y1)
   fraction:     0             frac               1
      color:   green ------> green|red --------> red

其中frac很容易从两点的坐标计算。可以看出,这实际上不是视觉梯度,颜色从“绿色”到“红色”的变化(用作示例)是在同一点完成的,即线段与x轴的交点。
下面是代码,注解中有解释:

const getBorderColor = (ctx, colPositive = "green", colNegative = "red") => {
    if (ctx.p0.parsed.y * ctx.p1.parsed.y < 0) {
        // if the segment changes sign from p0 to p1
        const x0 = ctx.p0.parsed.x,
            x1 = ctx.p1.parsed.x,
            y0 = ctx.p0.parsed.y,
            y1 = ctx.p1.parsed.y,
            dataset = ctx.chart.data.datasets[ctx.datasetIndex],
            //identify the correct axes used for the dataset
            xAxisId = dataset.xAxisId ?? "x",
            yAxisId = dataset.yAxisId ?? "y",
            //transform values to pixels
            x0px = ctx.chart.scales[xAxisId].getPixelForValue(x0),
            x1px = ctx.chart.scales[xAxisId].getPixelForValue(x1),
            y0px = ctx.chart.scales[yAxisId].getPixelForValue(y0),
            y1px = ctx.chart.scales[yAxisId].getPixelForValue(y1);
        
        // create gradient form p0 to p1
        const gradient = ctx.chart.ctx.createLinearGradient(x0px, y0px, x1px, y1px);
        // calculate frac - the relative length of the portion of the segment
        // from p0 to the point where the segment intersects the x axis
        const frac = Math.abs(y0) / (Math.abs(y0) + Math.abs(y1));
        // set colors at the ends of the segment
        const [col_p0, col_p1] =
            y0 > 0 ? [colPositive, colNegative] : [colNegative, colPositive];
        gradient.addColorStop(0, col_p0);
        gradient.addColorStop(frac, col_p0);
        gradient.addColorStop(frac, col_p1);
        gradient.addColorStop(1, col_p1);
        return gradient;
    }
    return ctx.p0.parsed.y >= 0 ? colPositive : colNegative;
};

和原始codesandbox的the fork

相关问题