如何在调整窗口大小时保持chartjs / ng2-charts渐变?

时间:2019-11-19 14:18:12

标签: javascript html angular chart.js

我对我的chartjs图表应用了一些渐变规则。正如您在下面看到的那样,它看起来很棒 enter image description here

但是,当调整浏览器窗口的大小(即窗口的宽度较小)时,渐变会破坏(底部的蓝色消失)。截图:

enter image description here

我想用所有值保持图形的渐变并适合不同的宽度(响应)。有什么办法吗?这是我尝试过但无法使用的内容:

.TS文件

    ngAfterViewInit() {
        const ctx = (<HTMLCanvasElement>this.myChart.nativeElement).getContext('2d');
        const purple_orange_gradient = ctx.createLinearGradient(0, 200, 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");


        const bar_chart = new Chart(ctx, {
          type: "horizontalBar",
          data: {
            labels: []=this.histogramLabels.reverse(),
            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: []=this.histogramGraphData
            }]
          },
        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"
                    }
                }]
            }
        }
        }

        )

     }

.HTML

<div class="row my-2">
   <div class="col-md-6">
      <canvas id=”myChart” #myChart height="130"></canvas>
   </div>
</div>

2 个答案:

答案 0 :(得分:1)

每当画布调整大小时,都必须更改渐变。花了我一段时间来找出一个好的结构,以减少代码行并优化性能。这是我能达到的最好成绩。

虽然chart.js onResize()被解雇了,但我无法完全解决这个问题。但是对于简单的调整大小,它应该可以工作。

完整代码(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()
}

答案 1 :(得分:1)

example gif

HTML Canvas的createLinearGradient()取决于您作为参数传递的y轴坐标。您每次都传递了静态200(即ctx.createLinearGradient(0, 200, 0, 20);)。

这就是为什么渐变步长每次都保持不变的原因。为了更新渐变,您必须重新计算窗口调整大小时<canvas>元素的 height ,然后再次将其传递到createLinearGradient()

您可以通过以下方式完成此操作:

  • 将创建渐变的块分隔为单独的函数。 eleHeight检索canvas元素的高度。
  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;
  }
  • 将onresize事件处理程序添加到包含<div>的事件处理程序中,然后再次生成渐变。 您还需要在每次更改时以编程方式更新图表以重新呈现。
<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
  }
  • 更新barchartDatangAfterViewInit的属性(使用渐变)。我们在这里需要这样做,因为我们只希望填充数据的<canvas>元素的高度。如果不填充数据,则元素会小得多。
  ngAfterViewInit(){
    this.barChartData.forEach((d, i) => {
      d.backgroundColor = this.generateGradient();
    });
    this.chart.chart.update(); //update the chart to re-render it
  }

看看我创建的这个 Stackblitz example⚡⚡