为了账号安全,请及时绑定邮箱和手机立即绑定

如何将径向 CanvasGradients 与 Chart.js 的圆环图一起使用?

如何将径向 CanvasGradients 与 Chart.js 的圆环图一起使用?

ABOUTYOU 2023-07-20 17:14:42
我正在尝试创建两个径向渐变以与Charts.js 圆环图一起使用。渐变应该看起来有点像下图,但是是红色的。createRadialGradient使用普通 javascript 和 DOM创建渐变 ( ) 非常简单,如下面的代码片段所示:'use strict'const red = "hsla(1, 73.7%, 38.8%, 1)"const redDark = "hsla(1, 60%, 30%, 1)"const redDarker = "hsla(1, 20%, 20%, 1)"const redLight = "hsla(1, 73.7%, 48%, 1)"const canvasList = document.querySelectorAll('canvas.vanilla')var {ctx, gradient} = createGradient1(canvasList[0].getContext('2d'))ctx.fillStyle = gradientdrawRect(ctx)var {ctx, gradient} = createGradient1(canvasList[1].getContext('2d'))ctx.strokeStyle = gradientctx.lineWidth = 42drawArc(ctx)var {ctx, gradient} = createGradient2(canvasList[2].getContext('2d'))ctx.fillStyle = gradientdrawRect(ctx)var {ctx, gradient} = createGradient2(canvasList[3].getContext('2d'))ctx.strokeStyle = gradientctx.lineWidth = 42drawArc(ctx)function createGradient1 (ctx) {    // The inner circle is at x=110, y=90, with radius=30    // The outer circle is at x=100, y=100, with radius=70    // ctx.createRadialGradient(x0, y0, r0, x1, y1, r1)    const gradient = ctx.createRadialGradient(100,100,31, 100,100,70);    // Add three color stops    const innerColor = redDark    const mainColor = red    const outerColor = redLight    gradient.addColorStop(0, innerColor);    gradient.addColorStop(.04, innerColor);    gradient.addColorStop(.05, mainColor);    gradient.addColorStop(1, outerColor);    return { ctx, gradient }}但是当我将相同的 2 个渐变应用于Charts.js时,我得到一个灰色的甜甜圈。使用单一梯度不会改变结果。但是,使用两种 Hsla 颜色可以按预期工作 ( red& "white")。
查看完整描述

1 回答

?
慕村225694

TA贡献1880条经验 获得超4个赞

问题在于渐变填充样式实际应用于甜甜圈的方式。你和我最初的假设是,chart.js 将负责定位渐变并将其缩放到适当的大小以填充甜甜圈。嗯,事实并非如此。相反,它使用画布上渐变的大小和位置。


为了更好地理解,让我们看一下其中一个渐变的代码:


const red = "hsla(1, 73.7%, 38.8%, 1)"

const gradient = ctx.createRadialGradient(100,100,31, 100,100,70);

const innerColor = "hsla(1, 60%, 30%, 1)"

const mainColor = red

const outerColor = "hsla(1, 73.7%, 48%, 1)"

gradient.addColorStop(0, innerColor);

gradient.addColorStop(.04, innerColor);

gradient.addColorStop(.05, mainColor);

gradient.addColorStop(1, outerColor);

这将在 x=100 和 y=100 处产生直径为 140 像素的渐变,如下所示:

//img1.sycdn.imooc.com//64b8fb4a0001f41701860187.jpg

现在,如果我们进一步挖掘并假设您绘制的实际画布的大小是 797 x 419 像素,我们可以看到问题:

//img1.sycdn.imooc.com//64b8fb560001f4ec06510341.jpg

渐变完全脱离了甜甜圈的形状!

为了解决这个问题,渐变需要位于甜甜圈的中心,并且具有适当的大小以完全填充它。有点像这样:

//img1.sycdn.imooc.com//64b8fb61000159c406480340.jpg

这说起来容易做起来难,因为最初我们不知道画布的确切大小,因为 Chart.js 会自动拉伸它以填充浏览器窗口。

因此,我们可以采取以下解决方法:

  • 使用 Chart.js 创建甜甜圈,但先不要填充它

  • 等到 Chart.js 触发调整大小事件以获取画布的实际大小

  • 根据画布的大小计算渐变的尺寸并将其绘制在中心

  • 最后用渐变填充甜甜圈的背景颜色

这是一个示例(请以“全页”运行,因为我们在 stackoverflow 的迷你预览框架中没有获得正确的窗口大小):

const canvas = document.querySelector('.d-goal--canvas');

const ctx = canvas.getContext('2d')

const red = "hsla(1, 73.7%, 38.8%, 1)"

let gradient1;

let gradient2;


function createGradient1(ctx) {

  const gradient = ctx.createRadialGradient(canvas.width / 2, canvas.height / 2, canvas.height / 4, canvas.width / 2, canvas.height / 2, canvas.height / 2);


  const innerColor = "hsla(1, 60%, 30%, 1)"

  const mainColor = red

  const outerColor = "hsla(1, 73.7%, 48%, 1)"

  gradient.addColorStop(0, innerColor);

  gradient.addColorStop(.12, innerColor);

  gradient.addColorStop(.121, mainColor);

  gradient.addColorStop(1, outerColor);


  return gradient;

}


function createGradient2(ctx) {

  const gradient = ctx.createRadialGradient(canvas.width / 2, canvas.height / 2, canvas.height / 4, canvas.width / 2, canvas.height / 2, canvas.height / 2);


  const innerColor = "hsla(1, 90%, 10%, 1)"

  const mainColor = "hsla(1, 73.7%, 20%, 1)"

  const outerColor = "transparent"

  gradient.addColorStop(0, innerColor);

  gradient.addColorStop(.12, innerColor);

  gradient.addColorStop(.121, mainColor);

  gradient.addColorStop(.99, mainColor);

  gradient.addColorStop(1, outerColor);


  return gradient;

}


function resized() {

  gradient1 = createGradient1(ctx);

  gradient2 = createGradient2(ctx);

  config.data.datasets[0].backgroundColor = [gradient1, gradient2];

  donut.update();

}

var config = {

  type: 'doughnut',

  data: {

    labels: [

      "Pledged",

      "Missing"

    ],

    datasets: [{

      label: "Donations",

      data: [420, 80],

      cubicInterpolationMode: "monotone"

    }]

  },

  options: {

    onResize: resized,

    legend: {

      display: false

    }

  }

};

const donut = new Chart(ctx, config);

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>

<canvas class="d-goal--canvas"></canvas>


查看完整回答
反对 回复 2023-07-20
  • 1 回答
  • 0 关注
  • 97 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信