如何在Chart.js的甜甜圈图上使用径向CanvasGradients?

如何解决如何在Chart.js的甜甜圈图上使用径向CanvasGradients?

我正在尝试创建两个用于Charts.js doughnut chart的径向渐变。

渐变应该看起来像下面的图片,但是红色。

enter image description here

使用香草javascript和DOM创建渐变(createRadialGradient)非常简单,如以下代码段所示:

'use strict'

const red = "hsla(1,73.7%,38.8%,1)"
const redDark = "hsla(1,60%,30%,1)"
const redDarker = "hsla(1,20%,1)"
const redLight = "hsla(1,48%,1)"

const canvasList = document.querySelectorAll('canvas.vanilla')

var {ctx,gradient} = createGradient1(canvasList[0].getContext('2d'))
ctx.fillStyle = gradient
drawRect(ctx)

var {ctx,gradient} = createGradient1(canvasList[1].getContext('2d'))
ctx.strokeStyle = gradient
ctx.lineWidth = 42
drawArc(ctx)

var {ctx,gradient} = createGradient2(canvasList[2].getContext('2d'))
ctx.fillStyle = gradient
drawRect(ctx)

var {ctx,gradient} = createGradient2(canvasList[3].getContext('2d'))
ctx.strokeStyle = gradient
ctx.lineWidth = 42
drawArc(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,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 }
}
function createGradient2 (ctx) {
    // The inner circle is at x=110,70);

    // Add three color stops
    const innerColor = "hsla(1,90%,10%,1)"
    const mainColor = "hsla(1,1)"
    const outerColor = "transparent"
    gradient.addColorStop(0,mainColor);
    gradient.addColorStop(.7,mainColor);
    gradient.addColorStop(.73,gradient }
}

function drawRect (ctx) {
    // ctx.fillRect(x,y,width,height)
    ctx.fillRect(20,20,160,160);
}

function drawArc (ctx) {
    ctx.beginPath();
    // ctx.arc(x,radius,startAngle,endAngle [,anticlockwise])
    ctx.arc(100,50,2 * Math.PI);
    ctx.stroke()
}
.vanilla {
    display: inline-block;
}
<canvas class="vanilla" width="180" height="180"></canvas>
<canvas class="vanilla" width="180" height="180"></canvas>
<canvas class="vanilla" width="180" height="180"></canvas>
<canvas class="vanilla" width="180" height="180"></canvas>

但是,当我对Charts.js应用相同的2个渐变时,会得到灰色的甜甜圈。使用单个渐变不会更改结果。但是,使用两种Hsla颜色可以正常工作(red"white")。

/** @type {CanvasRenderingContext2D} */
const ctx = document.querySelector('.d-goal--canvas').getContext('2d')
const red = "hsla(1,1)"
const { gradient1 } = createGradient1(ctx)
const { gradient2 } = createGradient2(ctx)
const donut = new Chart(ctx,{
    type: 'doughnut',data: {
        labels: [
            "Pledged","Missing"
        ],datasets: [{
            label: "Donations",data: [420,80],cubicInterpolationMode: "monotone",// borderColor: [red,"white"],// backgroundColor: [red,borderColor: [gradient1,gradient2],backgroundColor: [gradient1,}]
    },options: {
        legend: {
            display: false
        }
    }
})

function createGradient1 (ctx) {
    // The inner circle is at x=110,1)"
    const mainColor = red
    const outerColor = "hsla(1,1)"
    gradient.addColorStop(0,gradient }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas class="d-goal--canvas"></canvas>

我在做什么错了?

我读了Jelena Jovanovic's gradient tutorial,这是应用于折线图的线性渐变(createLinearGradient),但看不到我在做些什么。据我所知,也许我的渐变区域是错误的,但这不应导致显示灰色图表。

The Charts.js documentation has a section about colors,其中描述了CanvasGradient的用法,但仅用于createLinearGradient,这让我认为这可能是Charts.js中的错误...

解决方法

问题是渐变填充样式实际上应用于甜甜圈的方式。您(也是我最初的假设)是,chart.js将负责将渐变放置和缩放到适当的大小,以填充甜甜圈。好吧,这不是不是情况。而是使用渐变在画布上的大小和位置。

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

const red = "hsla(1,73.7%,38.8%,1)"
const gradient = ctx.createRadialGradient(100,100,31,70);
const innerColor = "hsla(1,60%,30%,1)"
const mainColor = red
const outerColor = "hsla(1,48%,1)"
gradient.addColorStop(0,innerColor);
gradient.addColorStop(.04,innerColor);
gradient.addColorStop(.05,mainColor);
gradient.addColorStop(1,outerColor);

这将在x = 100和y = 100处生成一个直径为140像素的渐变,例如:

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

渐变是完全,而不是甜甜圈形状!

要修复此问题,渐变将需要位于甜甜圈的中心,并具有适当的大小以完全填充它。有点像这样:

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

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

  • 使用chart.js创建甜甜圈,但给它填充
  • 等到chart.js触发 resize事件以获取画布的实际大小
  • 根据画布的尺寸计算渐变的尺寸并将其绘制在中心
  • 最后用渐变填充甜甜圈的backgroundColor

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

const canvas = document.querySelector('.d-goal--canvas');
const ctx = canvas.getContext('2d')
const red = "hsla(1,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);

  const innerColor = "hsla(1,1)"
  const mainColor = red
  const outerColor = "hsla(1,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,90%,10%,1)"
  const mainColor = "hsla(1,20%,1)"
  const outerColor = "transparent"
  gradient.addColorStop(0,mainColor);
  gradient.addColorStop(.99,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>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res