如何在调整窗口大小时保持 Chart.js / ng2-charts 渐变效果?

3

我在我的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>

你不需要更新 ctx.createLinearGradient(0, 200, 0, 20) 中的像素吗? - HeadhunterKev
是的,但我不能总是更改它,它应该动态更改。 - Timuçin Çiçek
2个回答

2

example gif

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

这就是为什么渐变步骤每次都保持不变的原因。要更新渐变,您必须在窗口调整大小时重新计算<canvas>元素的高度并再次传递给createLinearGradient()

您可以通过以下方式实现此目标:

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

看一下我创建的Stackblitz example⚡⚡


1
你需要在画布大小调整时更改渐变。花费了我一些时间来构建一个良好的结构,以最小化代码行数并优化性能。这是我能够达到的最佳效果。
但是当 chart.jsonResize() 触发时,有例外情况,我无法完全解决这个问题。但对于简单的调整大小,它应该可以工作。
完整代码(在JSBin中具有实时预览的相同代码):
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()
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接