[英]How to use radial CanvasGradients with Chart.js's doughnut chart?
我正在嘗試創建兩個徑向漸變以與Charts.js 圓環圖一起使用。
使用 vanilla 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%, 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 = 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, 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 } } function createGradient2 (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 = "hsla(1, 90%, 10%, 1)" const mainColor = "hsla(1, 73.7%, 20%, 1)" const outerColor = "transparent" gradient.addColorStop(0, innerColor); gradient.addColorStop(.04, innerColor); gradient.addColorStop(.05, mainColor); gradient.addColorStop(.7, mainColor); gradient.addColorStop(.73, outerColor); return { ctx, gradient } } function drawRect (ctx) { // ctx.fillRect(x, y, width, height) ctx.fillRect(20, 20, 160, 160); } function drawArc (ctx) { ctx.beginPath(); // ctx.arc(x, y, radius, startAngle, endAngle [, anticlockwise]) ctx.arc(100, 100, 50, 0, 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, 73.7%, 38.8%, 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, "white"], borderColor: [gradient1, gradient2], backgroundColor: [gradient1, gradient2], }] }, options: { legend: { display: false } } }) 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 = "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); return { ctx, gradient } } function createGradient2 (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 = "hsla(1, 90%, 10%, 1)" const mainColor = "hsla(1, 73.7%, 20%, 1)" const outerColor = "transparent" gradient.addColorStop(0, innerColor); gradient.addColorStop(.04, innerColor); gradient.addColorStop(.05, mainColor); gradient.addColorStop(.7, mainColor); gradient.addColorStop(.73, outerColor); return { ctx, 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 的漸變教程,它是應用於折線圖的線性漸變 ( createLinearGradient
),但我看不出我在做什么不同。 也許我的漸變區域是錯誤的,但據我所知,這不應該導致灰色圖表。
該Charts.js文檔有一個關於色彩節,他們描述了如何使用CanvasGradient
但只有createLinearGradient
,這讓我覺得,這可能是在Charts.js的錯誤...
問題是漸變填充樣式實際上應用於甜甜圈的方式。 您和我最初的假設是 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 像素的漸變,例如:
現在,如果我們進一步挖掘並假設您繪制的實際畫布的大小是 797 x 419 像素,我們可以看到問題:
漸變完全脫離了甜甜圈的形狀!
要修復它,漸變需要位於甜甜圈的中心並具有適當的大小來完全填充它。 有點像這樣:
嗯,說起來容易做起來難,因為最初我們不知道畫布的確切大小,因為 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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.