score:2

Accepted answer

example gif

html canvas' createlineargradient() depends on the y axis coordinates that you pass in as argument. you had passed in a static 200 every time (i.e. ctx.createlineargradient(0, 200, 0, 20);).

that's why the gradient's steps remains the same everytime. for the gradient to update, you have to recalculate the height of the <canvas> element on window resize and pass it in to createlineargradient() again.

you can accomplish this by:

  • separating the block where you create the gradient into a separate function. eleheight retrieves the height of the canvas element.
  generategradient(){
    let eleheight = this.mychart.nativeelement.offsetheight;
    // console.log(eleheight)
    let purple_orange_gradient: canvasgradient = this.mychart.nativeelement.getcontext('2d').createlineargradient(0, eleheight, 0, 20);
    purple_orange_gradient.addcolorstop(0.1, "#000279");
    purple_orange_gradient.addcolorstop(0.2, "#0000f2");
    purple_orange_gradient.addcolorstop(0.3, "#0362fd");
    purple_orange_gradient.addcolorstop(0.4, "#04d3fd");
    purple_orange_gradient.addcolorstop(0.5, "#45ffb7");
    purple_orange_gradient.addcolorstop(0.6, "#b7ff46");
    purple_orange_gradient.addcolorstop(0.7, "#ffd401");
    purple_orange_gradient.addcolorstop(0.8, "#fe6500");
    purple_orange_gradient.addcolorstop(0.9, "#f30004");
    purple_orange_gradient.addcolorstop(1, "#7e0100");

    return purple_orange_gradient;
  }
  • add a onresize event handler to your containing <div> and generate the gradient again. you also need to programatically update the chart every time you make a change to re-render it.
<div style="display: block; max-height: 100%" (window:resize)="onresize($event)" >
...
</div>
  onresize(event?){
    // console.log("onresize");

    this.barchartdata.foreach((d, i) => {
      d.backgroundcolor = this.generategradient();
    })

    this.chart.chart.update(); //update the chart to re-render it
  }
  • update the barchartdata's properties (that uses gradient) in ngafterviewinit. we need to do this here because we only want the height of the <canvas> element with data populated. without data populated, the element is much smaller.
  ngafterviewinit(){
    this.barchartdata.foreach((d, i) => {
      d.backgroundcolor = this.generategradient();
    });
    this.chart.chart.update(); //update the chart to re-render it
  }

have a look at this stackblitz example⚡⚡ i have created.

score:1

you have to change the gradient whenever your canvas is resizing. took me a while to figure out a good structure to minimize lines of code and optimize performance. this is the best i could achieve.

there are exeptions when the chart.js onresize() fires though but i couldn't solve this issue completly bulletproof. but for simple resizes it should work.

complete code (same code in jsbin with live preview):

let sdata = {}
sdata.labels = []
sdata.data = []

const count = 50
for (let x = 0; x < count; x++) {
  sdata.data.push(math.floor(math.random()*100))
  sdata.labels.push(x)
}

const canvas = document.getelementbyid('chart')
const ctx = canvas.getcontext("2d")

let purple_orange_gradient

function updategradient() {
  let bottom = bar_chart.chartarea.bottom
  let top = bar_chart.chartarea.top
  purple_orange_gradient = ctx.createlineargradient(0, bottom+top, 0, top)
  purple_orange_gradient.addcolorstop(0.1, "#000279")
  purple_orange_gradient.addcolorstop(0.2, "#0000f2")
  purple_orange_gradient.addcolorstop(0.3, "#0362fd")
  purple_orange_gradient.addcolorstop(0.4, "#04d3fd")
  purple_orange_gradient.addcolorstop(0.5, "#45ffb7")
  purple_orange_gradient.addcolorstop(0.6, "#b7ff46")
  purple_orange_gradient.addcolorstop(0.7, "#ffd401")
  purple_orange_gradient.addcolorstop(0.8, "#fe6500")
  purple_orange_gradient.addcolorstop(0.9, "#f30004")
  purple_orange_gradient.addcolorstop(1.0, "#7e0100")

  return purple_orange_gradient
}

const bar_chart = new chart(ctx, {
  type: "horizontalbar",
  data: {
    labels: sdata.labels,
    datasets: [{
      bordercolor: purple_orange_gradient,
      pointbordercolor: purple_orange_gradient,
      pointbackgroundcolor: purple_orange_gradient,
      pointhoverbackgroundcolor: purple_orange_gradient,
      pointhoverbordercolor: purple_orange_gradient,
      pointborderwidth: 10,
      pointhoverradius: 10,
      pointhoverborderwidth: 1,
      pointradius: 3,
      fill: true,
      backgroundcolor: purple_orange_gradient,
      borderwidth: 4,
      data: sdata.data
    }]
  },
  options: {
    legend: {
      display: false,
      position: "bottom"
    },
    scales: {
      yaxes: [{
        ticks: {
          display: false,
          fontcolor: "rgba(0,0,0,0.5)",
          fontstyle: "bold",
          beginatzero: true,
          maxtickslimit: 1,
          padding: 20,
        },
        gridlines: {
          drawticks: false,
          display: false
        }
      }],
      xaxes: [{
        gridlines: {
          zerolinecolor: "transparent",
        },
        ticks: {
          padding: 20,
          beginatzero: true,
          fontcolor: "rgba(0,0,0,0.5)",
          fontstyle: "bold"
        }
      }]
    },
    onresize: function(chart, size) {
      // onresize gradient change
      changegradient()
    }
  }
});

// initial gradient change
changegradient()


function changegradient() {
  let newgradient = updategradient()

  bar_chart.data.datasets[0].bordercolor = newgradient
  bar_chart.data.datasets[0].pointbordercolor = newgradient
  bar_chart.data.datasets[0].pointbackgroundcolor = newgradient
  bar_chart.data.datasets[0].pointhoverbackgroundcolor = newgradient
  bar_chart.data.datasets[0].pointhoverbordercolor = newgradient
  bar_chart.data.datasets[0].backgroundcolor = newgradient

  bar_chart.update()
}

Related Query

More Query from same tag