36

I am using Chart.js and everything is ok, but I want to replace current color background (fillColor : "rgba(250,174,50,0.5)") with a gradient. I have solution for replacing gradient but it's too dificult for me to implement this with my poor JS knowledge. I guess pretty easy for someone who know JS.

So my Chart.js code:

        <script>

        var data = {
            labels : ["02:00","04:00","06:00","08:00","10:00","12:00","14:00","16:00","18:00","20:00","22:00","00:00"],
            datasets: [
                {
                    fillColor : "rgba(250,174,50,0.5)",
                    strokeColor : "#ff6c23",
                    pointColor : "#fff",
                    pointStrokeColor : "#ff6c23",
                    pointHighlightFill: "#fff",
                    pointHighlightStroke: "#ff6c23",
                    data : [25.0,32.4,22.2,39.4,34.2,22.0,23.2,24.1,20.0,18.4,19.1,17.4]
                }
            ]
        };

        var options = {
            responsive: true,
            datasetStrokeWidth : 3,
            pointDotStrokeWidth : 4,
            tooltipFillColor: "rgba(0,0,0,0.8)",
            tooltipFontStyle: "bold",
            tooltipTemplate: "<%if (label){%><%=label + ' hod' %>: <%}%><%= value + '°C' %>",
            scaleLabel : "<%= Number(value).toFixed(0).replace('.', ',') + '°C'%>"
        };

        var ctx = document.getElementById("temp-chart").getContext("2d");
        var myLineChart = new Chart(ctx).Line(data, options);

    </script>

And here is solution with gradient. Can someone try implement this gradient background instead of my current solid background? Thanks for help.

I tryed implement it, but then other functions don't work (like scaleLabels etc.).

Apostolos
  • 10,033
  • 5
  • 24
  • 39
John Cavalier
  • 363
  • 1
  • 3
  • 4

8 Answers8

70

The link you provided was pretty clear, you have to put in the field fillColor in datasets a linearGradient object instead of a plain color. You can do complex gradients, but here is the code of a simple one (changing the opacity of the same orange) :

var gradient = ctx.createLinearGradient(0, 0, 0, 400);
gradient.addColorStop(0, 'rgba(250,174,50,1)');   
gradient.addColorStop(1, 'rgba(250,174,50,0)');

And your complete datasets :

datasets: [
            {
                fillColor : gradient, // Put the gradient here as a fill color
                strokeColor : "#ff6c23",
                pointColor : "#fff",
                pointStrokeColor : "#ff6c23",
                pointHighlightFill: "#fff",
                pointHighlightStroke: "#ff6c23",
                data : [25.0,32.4,22.2,39.4,34.2,22.0,23.2,24.1,20.0,18.4,19.1,17.4]
            }
        ]

See it in action in this JSFiddle

bviale
  • 5,245
  • 3
  • 28
  • 48
  • 1
    @bviale I get "`ctx` is not defined" – mesqueeb Sep 13 '18 at 12:36
  • 1
    @mesqueeb I had the same error, fixed it by defining ctx and canvas as variables. // var canvas = document.getElementById("name"); var ctx = canvas.getContext("2d"); – souzan Oct 10 '18 at 08:54
  • 18
    I had to use `backgroundColor` instead of `fillColor` – A Friend Apr 04 '19 at 00:30
  • All these answers give a gradient on the canvas level, did anyone achieve a consistent gradient in each bar of the bar chart? – Aadam Feb 05 '23 at 06:23
34

Note: For those people who is using newer version (v2.7.0) of Chart.js, find out that is not working while you're copy-paste @bviale's answer back to your code base; Some property names has changed:

fillColor -> backgroundColor
strokeColor -> borderColor
pointColor -> pointBackgroundColor
pointStrokeColor -> pointBorderColor

You will need to update those property names to make it work.

Reference: https://github.com/chartjs/Chart.js/blob/master/docs/charts/line.md#dataset-properties

AJ H
  • 687
  • 6
  • 8
13

For using in react I did the following way you need to pass an id to your component and then fetch the element using that id

import React, { Component } from 'react'
import { Line } from 'react-chartjs-2'

export default class GraphComponent extends Component{
  constructor(props){
    super(props)
    this.state = {
      chartData: {}
    }
  }

  componentDidMount(){
    //your code
    var ctx = document.getElementById('canvas').getContext("2d")
    var gradient = ctx.createLinearGradient(0, 0, 0, 400)
    gradient.addColorStop(0, 'rgba(229, 239, 255, 1)')
    gradient.addColorStop(1, '#FFFFFF')
    const newData = {
      labels: [1, 1],
      datasets: [
        {
          label: 'usd',
          data: [1,1],
          backgroundColor: gradient,
          borderColor: this.props.border_color,
          pointRadius: 0
        }
      ]

    }
    this.setState({chartData: newData})
  }

  //more of your code

  render(){
    return(
          <Line
            id='canvas'//you need to give any id you want
            data={this.state.chartData}
            width={100}
            height={30}
            options={{
              legend: {
                display: false
              }
            }}
          />

    )
  }
}

this is only my second answer so please forgive me if I have made any mistakes in writing

Nishith
  • 928
  • 9
  • 13
3

Updated version 2022

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

declare gradient after getting context element i.e ctx

var gradient = ctx.createLinearGradient(0, 0, 0, 400);
            gradient.addColorStop(0.2, 'rgb(255, 10, 86,0.5)');
            gradient.addColorStop(1, 'rgb(255, 10, 86,0.1)');

and your dataset will be

datasets: [{
                 label: 'Transactions',
                 data: [1,3,4,5]
                 backgroundColor: gradient,
                 borderColor: 'rgb(255, 10, 86,1)',
                 borderWidth: 2,
           }],
Apostolos
  • 10,033
  • 5
  • 24
  • 39
Siddharth Bagal
  • 499
  • 4
  • 7
3

The React solutions posted here may work with some effort but will most likely produce additional errors such as "createLinearGradient is not a function" or "document.getElementById() returning null" because it is looking for the chart id before the DOM has loaded. It doesn't help that ChartJS documentation for React is lacking.

I find a cleaner solution is to create the charts as a functional component and make sure all needed ChartJS assets are properly initialized.

1. Making sure ChartJS is properly initialized and registered

import { Line } from 'react-chartjs-2' import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend, Filler, ScriptableContext } from "chart.js";

ChartJS.register(CategoryScale,LinearScale,PointElement,LineElement,Title,Tooltip,Legend,Filler);

2. Using the ScriptableContext to add the gradient

backgroundColor: (context: ScriptableContext<"line">) => { const ctx = context.chart.ctx; const gradient = ctx.createLinearGradient(0, 0, 0, 200); gradient.addColorStop(0, "rgba(238,174,202,1)"); gradient.addColorStop(1, "rgba(238,174,202,0)"); return gradient; },

Live Codepen w/ Line Chart Gradient enter link description here

DevKev
  • 5,714
  • 6
  • 24
  • 29
  • Great, It worked for me. For regular react, I don't need ScriptableContext<"line">, Just context is fine. – Minhaz Jul 20 '23 at 12:19
2

for latest version do not forget to set fill: true

  function getGradient(ctx, chartArea) {
    let gradient = ctx.createLinearGradient(
      0,
      chartArea.bottom,
      0,
      chartArea.top
    );
    gradient.addColorStop(0.9, "rgba(102, 235, 169, .4)");
    gradient.addColorStop(0, "transparent");
    return gradient;
  }

set dataset options as below

fill: true,
backgroundColor: function (context) {
    const chart = context.chart;
    const { ctx, chartArea } = chart;

   // This case happens on initial chart load
   if (!chartArea) return;
   return getGradient(ctx, chartArea);
},
Hyzyr
  • 568
  • 4
  • 13
0

For anyone using Angular and ng2-charts, here is my solution. Chart setup was left out for brevity.

import { Component, OnInit, ViewChild, ChangeDetectorRef, AfterViewInit } from '@angular/core';
import { BaseChartDirective } from 'ng2-charts';
import { GenericLineChart } from './generic-line-chart';


@Component({
    selector: 'app-stats-chart',
    templateUrl: './stats-chart.component.html',
    styleUrls: ['./stats-chart.component.scss']
})
export class StatsChartComponent implements OnInit, AfterViewInit {
    @ViewChild(BaseChartDirective, { static: true }) chartDirective: BaseChartDirective;

    constructor(private changeDetectorRef: ChangeDetectorRef) { }

    ngOnInit() {
        // ...setup chart
    }

    ngAfterViewInit() {
        // set gradient
        const gradient = this.chartDirective.chart.ctx.createLinearGradient(0, 0, 0, 400);
        gradient.addColorStop(0, 'rgba(30, 214, 254, .3)');
        gradient.addColorStop(1, 'rgba(0,0,0,0)');
        this.chart.lineChartData[0].backgroundColor = gradient;

        this.changeDetectorRef.detectChanges();
    }

}
squirtgun
  • 629
  • 9
  • 12
0

You could use this npm package.

https://www.npmjs.com/package/chartjs-plugin-gradient

This makes it very easy to create a gradient backgroundColor or borderColor.

Example:

const chart = new Chart(ctx, {
  data: {
    datasets: [{
      // data
      gradient: {
        backgroundColor: {
          axis: 'y',
          colors: {
            0: 'red',
            50: 'yellow',
            100: 'green'
          }
        },
        borderColor: {
          axis: 'x',
          colors: {
            0: 'black',
            1: 'white',
            2: 'black',
            3: 'white'
          }
        }
      }
    }]
  }
});

Eric Goerens
  • 67
  • 11