如何解决如何在Chart.js的甜甜圈图上使用径向CanvasGradients?
我正在尝试创建两个用于Charts.js doughnut chart的径向渐变。
使用香草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 举报,一经查实,本站将立刻删除。