ChartJS Doughnut Charts Gradient Fill
Asked Answered
T

3

11

So I tried to make a gradient fill for the ChartJS doughnut chart, but this only works horizontal and not in a circle.

This is the code that I'm using:

   var ctx = document.getElementById("chart-area").getContext("2d");

   var gradient1 = ctx.createLinearGradient(0, 0, 0, 175);
   gradient1.addColorStop(0.0, '#ACE1DB');
   gradient1.addColorStop(1.0, '#7FBDB9');


   var gradient2 = ctx.createLinearGradient(0, 0, 400, 400);
   gradient2.addColorStop(0, '#B5D57B');
   gradient2.addColorStop(1, '#98AF6E');

   var gradient3 = ctx.createLinearGradient(0, 0, 0, 175);
   gradient3.addColorStop(0, '#E36392');
   gradient3.addColorStop(1, '#FE92BD');

   var gradient4 = ctx.createLinearGradient(0, 0, 0, 175);
   gradient4.addColorStop(1, '#FAD35E');
   gradient4.addColorStop(0, '#F4AD4F');

   /* ADD DATA TO THE DOUGHNUT CHART */
   var doughnutData = [
    {
      value: 80,
      color: gradient1,
      highlight: "#E6E6E6",
      label: "NUTRIENTS"
    },
    {
      value: 20,
      color:"#E6F1EE"

    },
    {
      value:50,
      color: gradient2,
      highlight: "#E6E6E6",
      label: "PROTEINE"
    },
    {
      value: 50,
      color:"#E6F1EE"
    },
    {
      value: 75,
      color: gradient3,
      highlight: "#E6E6E6",
      label: "FETTE"
    },
    {
      value:25,
      color:"#E6F1EE"
    },
    {
      value: 77,
      color: gradient4,
      highlight: "#E6E6E6",
      label: "CARBS"
    }
    {
      value: 23,
      color:"#E6F1EE"
    },
   ];

Is it possible to implement the gradient on a radius, as seen on this design?

https://static.mcmap.net/file/mcmap/ZG-AbGLDKwfpKnMxcF_AZVLQamyA/oItxw.png

Thanks!

Therrien answered 12/5, 2015 at 9:11 Comment(2)
This workaround works, it fills a gradient, but the problem is the angle of the gradient, because it is a circle!Therrien
I've posted an answer with a couple of possible options to create you gradient donut chart.Ethyne
E
11

ChartJS will not (properly) use gradient fill colors when drawing a linear gradient on non-linear paths like your donut chart. A linear gradient does not curve.

Possibility #1 -- use a radial gradient

You might experiment with a radial gradient and see if the results meets your design needs.

Possibility #2 -- use a gradient stroke (a DIY project)

Also, canvas's stroke will curve around a circle.

If you want to "roll-your-own" gradient donut chart, here's example code and a Demo that uses a gradient strokeStyle on a circular path (see my previous answer here: Angle gradient in canvas):

enter image description here

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");

function drawMultiRadiantCircle(xc, yc, r, radientColors) {
  var partLength = (2 * Math.PI) / radientColors.length;
  var start = 0;
  var gradient = null;
  var startColor = null,
      endColor = null;

  for (var i = 0; i < radientColors.length; i++) {
    startColor = radientColors[i];
    endColor = radientColors[(i + 1) % radientColors.length];

    // x start / end of the next arc to draw
    var xStart = xc + Math.cos(start) * r;
    var xEnd = xc + Math.cos(start + partLength) * r;
    // y start / end of the next arc to draw
    var yStart = yc + Math.sin(start) * r;
    var yEnd = yc + Math.sin(start + partLength) * r;

    ctx.beginPath();

    gradient = ctx.createLinearGradient(xStart, yStart, xEnd, yEnd);
    gradient.addColorStop(0, startColor);
    gradient.addColorStop(1.0, endColor);

    ctx.strokeStyle = gradient;
    ctx.arc(xc, yc, r, start, start + partLength);
    ctx.lineWidth = 30;
    ctx.stroke();
    ctx.closePath();

    start += partLength;
  }
}

var someColors = [];
someColors.push('#0F0');
someColors.push('#0FF');
someColors.push('#F00');
someColors.push('#FF0');
someColors.push('#F0F');

drawMultiRadiantCircle(150, 150, 120, someColors);
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>
Ethyne answered 13/5, 2015 at 15:52 Comment(0)
E
4

yes What I did on my end is this.

Step 1 - Grab your chart.

  @ViewChild('slideDoughnutChart') slideDoughnutChart: BaseChartDirective;

Step 2 - Declare a const gradient and assign it.

const gradient = this.slideDoughnutChart.chart.ctx.createLinearGradient(0, 0, 0, 220);

Step 3 - Push the colors that you wan to see as Gradient.

const colors = [];
for (let i = 0; i < 4; i++) {
  gradient.addColorStop(0, 'rgb(37, 77, 180)');
  gradient.addColorStop(1, 'rgb(123, 98, 221)');
  colors.push(gradient);
}

Here I have pushed the same color.

Step 4 - Set doughnut chart colors variable to colors array.

this.slideDoughnutChartColors = [{ backgroundColor: colors }];

Step 5 - Assign slideDoughnutChartColors variable to colors binding in canvas.

<canvas class="chartjs canvasResponsive" baseChart #slideDoughnutChart="base-chart" [colors]="slideDoughnutChartColors" ></canvas>

If you follow the steps correctly, You will end with this.

enter image description here

For 4 different colors you need to create 4 different variables. For example something like this.

const gradientOne = this.slideDoughnutChart.chart.ctx.createLinearGradient(0, 0, 0, 400);
const gradientTwo = this.slideDoughnutChart.chart.ctx.createLinearGradient(0, 0, 100, 400);
const gradientThree = this.slideDoughnutChart.chart.ctx.createLinearGradient(0, 0, 0, 400);
const gradientFour = this.slideDoughnutChart.chart.ctx.createLinearGradient(0, 0, 0, 400);

then doing something like this.

 for (let i = 0; i < this.slideDoughnutChartData.length; i++) {
      switch (i) {
        case 0:
          gradientOne.addColorStop(0, 'rgb(223, 43, 100)');
          gradientOne.addColorStop(1, 'rgb(224, 105, 84)');
          colors.push(gradientOne);
          break;
        case 1:
          gradientTwo.addColorStop(0, 'rgb(248, 188, 80)');
          gradientTwo.addColorStop(1, 'rgb(243, 217, 53)');
          colors.push(gradientTwo);
          break;
        case 2:
          gradientThree.addColorStop(0, 'rgb(147, 229, 151)');
          gradientThree.addColorStop(1, 'rgb(3, 220, 179)');
          colors.push(gradientThree);
          break;
        case 3:
          gradientFour.addColorStop(0, 'rgb(123, 98, 221)');
          gradientFour.addColorStop(1, 'rgb(37, 77, 180)');
          colors.push(gradientFour);
          break;
      }
    }

will end you up with.

enter image description here

This is my data for the chart.

this.slideDoughnutChartData = [25, 35, 20, 25, 2];
Epiphyte answered 30/4, 2019 at 10:20 Comment(2)
For 4 different colors you need to create four different variables.Epiphyte
thanks! it looks like you put some thought into this... a jsfiddle would be perfect to go with this answer.Faradmeter
L
0

2023 Answer:

I know this question has been asked long ago and have been answered, but I thought it would be beneficial for anyone looking for an updated answer to know that in addition to the standard built-in linear and radial gradients, there is now a third - conical gradient - that does exactly what we're looking for.

Here's the link to the docs.

And a simple example of how it's implemented to achieve the effect in a Chartjs doughnut chart:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Doughnut Chart Example</title>
  <!-- Include Chart.js library -->
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
    <div style="width: 400px; height: 400px;">
      <canvas id="myDoughnutChart" width="400" height="400"></canvas>
    </div>

  <script>
    // Data for the doughnut chart
    const chartRef = document.getElementById('myDoughnutChart');
    
    let gradient = chartRef.getContext('2d').createConicGradient(0, 200, 200);

    gradient.addColorStop(0, "red");
    gradient.addColorStop(0.25, "orange");
    gradient.addColorStop(0.5, "yellow");
    gradient.addColorStop(0.75, "green");
    gradient.addColorStop(1, "blue");
    
    const data = {
      labels: ['Red-Orange', 'Orange-Yellow', 'Yellow-Green'],
      datasets: [{
        label: 'My Doughnut Chart',
        data: [30, 20, 50],
        backgroundColor: gradient,
        hoverOffset: 4
      }]
    };

    // Configuration for the doughnut chart
    const config = {
      type: 'doughnut',
      data: data,
    };

    // Create the chart
    const myDoughnutChart = new Chart(
      chartRef,
      config
    );
  </script>
</body>
</html>

The above implementation of the gradient to the chart is simply to display its effect. Ideally, the gradient should be applied to each segment separately, but this would require calculating each segment's starting angle.

Hope it helps!

Lye answered 13/12, 2023 at 12:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.