Sheixt
Sheixt

Reputation: 2626

Chart JS plugin to change line color depending on value

I am attempting to create a line chart where the color of the line (and the points) is dependant upon the value being plotted. For example if the value is above the following thresholds [0, 115, 125] then the color would be either ['green', 'yellow', 'red'] respectively.

The requirement is nearly identical to that which is achieved in this example: https://jsfiddle.net/egamegadrive16/zjdwr4fh/

The difference is that I am using react-chart-js-2 and as a result, the draw() method is not accessible in the same way. Instead, it is suggested to create a plugin to manipulate the chart.

This is the plugin code at present:

import { Chart } from "react-chartjs-2";

class variableLineColorUtils {
  selectColor(value, thresholds, colors) {
    let color = colors[0];
    thresholds.every((limit, index) => {
      if (value < limit) return false;
      else color = colors[index];
      return true;
    });

    return color;
  }
}

const variableLineColor = {
  id: "variableLineColor",
  afterDraw: (chart, easing) => {
    const options = chart.options.variableLineColor;
    if (options) {
      const utils = new variableLineColorUtils();
      const datasets = chart.config.data.datasets;

      datasets.forEach((set, i) => {
        const points = chart.getDatasetMeta(i).data;
        points.forEach((point, index) => {
          const color = utils.selectColor(
            datasets[i].data[point._index],
            options.thresholds,
            options.colors
          );

          point.custom = { borderColor: color, backgroundColor: color };
        });
        chart.update();
      });
    }
  }
};

Chart.pluginService.register(variableLineColor);

export default variableLineColor;

And these are the options used for the plugin:

variableLineColor: {
  thresholds: [0, 115, 125],
  colors: ["green", "yellow", "red"]
}

This approach only amends the color of the points themselves, not the line between the points. The line remains in the chart's default backgroundColor.

How can I amend the color of the line itself?

Upvotes: 11

Views: 16658

Answers (6)

Kader G&#243;mez
Kader G&#243;mez

Reputation: 53

In addition to @blacktide answer here is a snippet of how to do it with typescript and some tailwind classes:

Chart.register({
    id: "customLineColorPlugin",
    beforeRender: chart => {
        const ctx = chart.ctx;
        const yAxis = chart.scales["y"];
        const yPos = yAxis.getPixelForValue(0);

        const gradientFill = ctx.createLinearGradient(0, 0, 0, chart.height);
        gradientFill.addColorStop(0, "rgb(86,188,77)");
        gradientFill.addColorStop(yPos / chart.height, "rgb(86,188,77)");
        gradientFill.addColorStop(yPos / chart.height, "rgb(229,66,66)");
        gradientFill.addColorStop(1, "rgb(229,66,66)");

        const datasets = chart.data.datasets;
        datasets.forEach(dataset => {
            dataset.borderColor = gradientFill;
        });
    },
});
const LineChart: React.FC = () => {
const data = {
    labels: ["Enero", "Febrero", "Marzo", "Abril", "Mayo"],
    datasets: [
        {
            label: "Datos",
            data: [5, -2, 3, -4, 7],
            borderColor: "red",
        },
    ],
};

const options: ChartOptions<"line"> = {
    scales: {
        y: {
            beginAtZero: false,
            max: 10,
            min: -10,
        },
    },
};

useEffect(() => {
    const chart = new Chart(document.getElementById("myChart") as HTMLCanvasElement, {
        type: "line",
        data: data,
        options: options,
    });

    return () => {
        chart.destroy();
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
    <div>
        <canvas id="myChart" width={250} height={80} className="rounded-lg border bg-card p-5"></canvas>
    </div>
);
};

export default LineChart;

This is the result:

enter image description here

Upvotes: 0

Nate Millner
Nate Millner

Reputation: 31

My solution uses ChartJS version 3's new feature , being able to edit the line in segments you can write a function like this.

segment:{
  borderColor:function(context){
    const yval = context.p1.raw.y
    if (yval>=5){
      return "green"
    } else if(yval<=-5){
      return "red"
    } else{
      return "gray"
    }
  }
},

This code will return green if the value is above 5 and red if below, and gray if it's in between. I believe this is the most simplistic solution since it doesn't require making your own plugin or re-rendering the chart.

Upvotes: 2

blacktide
blacktide

Reputation: 12196

You can use the plugins array to create a new beforeRender plugin that will accomplish this.

plugins: [{
  beforeRender: (x, options) => {
    const c = x.chart;
    const dataset = x.data.datasets[0];
    const yScale = x.scales['y-axis-0'];
    const yPos = yScale.getPixelForValue(0);

    const gradientFill = c.ctx.createLinearGradient(0, 0, 0, c.height);
    gradientFill.addColorStop(0, 'rgb(86,188,77)');
    gradientFill.addColorStop(yPos / c.height, 'rgb(86,188,77)');
    gradientFill.addColorStop(yPos / c.height, 'rgb(229,66,66)');
    gradientFill.addColorStop(1, 'rgb(229,66,66)');

    const model = x.data.datasets[0]._meta[Object.keys(dataset._meta)[0]].dataset._model;
    model.borderColor = gradientFill;
  },
}];

The result will look something like this:

enter image description here

This will also work for the background color just by changing the model.borderColor line to model.backgroundColor. For example:

enter image description here

Upvotes: 6

Ehsan ul haq
Ehsan ul haq

Reputation: 107

Use borderColor or color instead of backgroundColor of line.

Upvotes: 0

Reyansh Mishra
Reyansh Mishra

Reputation: 1915

For that, you will have to manipulate your data something as I did check out the below code. I doubt if you can do it with the plugin.

import React from 'react';
import { Line } from 'react-chartjs-2';

const data = {
  labels: [1, 2, 3, 4, 5, 6, 7, 8, 9],
  datasets: [
    {
      label: 'First one',
      fill: false,
      borderColor: 'gray',
      data: [null, null, 2, 0, 3],
    },
    {
      label: 'Second one',
      fill: false,
      borderColor: 'blue',
      data: [2, 4, 2, null, null, null, null, null, null],
    },
    {
      label: 'Third one',
      fill: false,
      borderColor: 'cyan',
      data: [null, null, null, null, 3, 4, 1, null, null],
    },
  ],
}

function App() {
  return (
    <div>
      <Line
        data={data}
      />
    </div>
  );
}



export default App

Upvotes: 2

Deeksha gupta
Deeksha gupta

Reputation: 659

Try to use borderColor instead of backgroundColor and Please refer ChartJs StackOverflow. It may solve your problem.

Upvotes: 0

Related Questions