1

I am trying to do the same thing provided in this SO answer, https://stackoverflow.com/a/66943726/1108057

Unfortunately that answer is for older versions of Chart.js and a lot of the needed elements are not supported in the new version, such as accessing _meta properties directly.

I was able to figure out how to get meta of the dataset in the new version, but I can't figure out the remaining part of it as I don't know what it was referencing in the previous version.

plugins: [{
    id: 'redLineLoss',
    beforeRender: (x, options) => {
        const c = x;
        const dataset = x.data.datasets[1];
        const yScale = x.scales['y'];
        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 datasetMeta = x.getDatasetMeta(1);

        console.log(datasetMeta['data']);

        // STUCK HERE -- what do I get from the dataset meta now?

        //console.log(datasetMeta.dataset.getProps(['x', 'y']));

        //console.log(model[Object.keys(x.getDatasetMeta(1))]);

        //const model = x.data.datasets[1]._meta[Object.keys(dataset._meta)[1]].dataset._model;

        //model.borderColor = gradientFill;
    },
}],

I want to only apply this to a specific dataset in the chart, not all of them. That's why I am selecting the dataset with key 1.

isherwood
  • 58,414
  • 16
  • 114
  • 157
zen
  • 1,115
  • 3
  • 28
  • 54

1 Answers1

1

Solution # 1

The pointBorderColor and pointBackgroundColor work perfectly when you only want to color the markers of the values. To do this, you need to predefine an array of colors from the array of values.

You can color the borderColor or backgroundColor of a line chart on a segment-by-segment basis. For this, you have the option of using segment.borderColor or segment.backgroundColor (when fill: true is set). These settings invoke a function to which you pass the current opening and closing values of the "segment". I have written an example that includes these as well, although I had to define the 0 value here to ensure that the segment consists only of positive or negative numbers... anyway, here is the example:

Chart.js Github Issue #1493

const ctx = document.getElementById("myChart").getContext("2d")
const data = [10, 20, 0, -10, -20, 0, 5]
const colors = data.map((value) => value < 0 ? 'red' : 'green')

const chart = new Chart(ctx, {
  type: "line",
  data: {
    labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"],
    datasets: [{
      label: "Sample Dataset",
      data: data,
      fill: true, // set true for "backgroundColor" using
      segment: {
        borderColor: (part) => {
          const prevValue = part.p0.parsed.y // start value
          const nextValue = part.p1.parsed.y // end value
          return prevValue < 0 || nextValue < 0 ? "red" : "green" // return with a color by rule
        },
        backgroundColor: (part) => {
          const prevValue = part.p0.parsed.y // start value
          const nextValue = part.p1.parsed.y // end value
          return prevValue < 0 || nextValue < 0 ? "red" : "green" // return with a color by rule
        },
      },
      pointBorderColor: colors, // with array of colors
      pointBackgroundColor: colors, // with array of colors
    }]
  },
  options: {
    responsive: true,
    scales: {
      y: {
        ticks: {
          beginAtZero: true
        }
      }
    }
  },
})
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

<canvas id="myChart"></canvas>

Solution # 2

To achieve gradient fill in Chart.js 3.x or higher versions, you can use the package called chartjs-plugin-gradient available at. I have provided a simple example code below:

const ctx = document.getElementById("myChart").getContext("2d")
const gradient = window['chartjs-plugin-gradient'] // call CDN "chartjs-plugin-gradient"

const chart = new Chart(ctx, {
  type: "line",
  data: {
    labels: ["Jan", "Feb", "Mar", "Apr", "May"],
    datasets: [{
      label: "Sample Dataset",
      data: [0, 1, 4, 16, 64],
      fill: true, // set true for "backgroundColor" using
      gradient: {
        // Can set gradient background (need "fill: true")
        backgroundColor: {
          axis: 'y', // 'x' or 'y'
          colors: {
            // from value: color hex
            0: 'red',
            4: 'yellow',
            20: 'green'
          }
        },
        // Can set gradient line
        borderColor: {
          axis: 'y', // 'x' or 'y'
          colors: {
            // from value: color hex
            0: 'red',
            4: 'yellow',
            20: 'green'
          }
        }
      }
    }]
  },
  options: {
    responsive: true,
    scales: {
      y: {
        ticks: {
          beginAtZero: true
        }
      }
    }
  },
  plugins: [gradient] // using "chartjs-plugin-gradient"
})
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-gradient#.js"></script>

<canvas id="myChart"></canvas>
rozsazoltan
  • 2,831
  • 2
  • 7
  • 20
  • Are you sure this plugin is needed to achieve the same effect? Technically I'm not looking for a gradient border fill, but just a way to customize when one color starts and ends and the next one begins. – zen Jun 19 '23 at 15:32
  • 1
    I have just updated my response. In "solution #1," Chart.js actually provides exactly this solution. You can determine the color of each segment using a function. – rozsazoltan Jun 19 '23 at 15:36
  • 1
    Awesome yeah the solution #1 works just fine. Thank you so much! – zen Jun 19 '23 at 17:22