之前介紹了Canvas畫圖基礎,這篇介紹一下畫一個帶漸變效果的圓。
一個漸變的圓環
漸變色應用廣泛,和圓環結合做進度條非常酷,今天我們就來畫一個這樣的圓環:
Canvas漸變
在Canvas畫圖基礎中我們知道給canvas上色主要是ctx.fillStyle
和ctx.strokeStyle
方法,這裡是圓環,所以主要講strokeStyle
方法,fillStyle
方法也同樣適用。
看一下上面那個圓,像把一個線性的漸變給『掰彎』成一個圓。Canvas中有線性漸變的支援,我們可以試一下:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
ctx.lineWidth = 7;
ctx.beginPath(); // 開一條新路
ctx.moveTo(170, 120);
var grd=ctx.createLinearGradient(0,0,170,0);
grd.addColorStop("0","black");
grd.addColorStop("0.3","magenta");
grd.addColorStop("0.5","blue");
grd.addColorStop("0.6","green");
grd.addColorStop("0.8","yellow");
grd.addColorStop(1,"red");
ctx.strokeStyle = grd;
ctx.arc(120, 120, 50, 0 ,Math.PI*2);
ctx.stroke(); // 畫圓複製程式碼
畫出來的效果:
ctx.createLinearGradient
就是建立一個線性漸變的物件,其中前兩個引數是起始點的x,y座標,後兩個引數是結束點的x,y座標,這裡是一個水平的線性漸變。grd.addColorStop
就是設定漸變點,類似css3漸變中的color-stop
。- 設定完漸變的物件,把漸變物件用於
strokeStyle
就可以實現漸變效果了。
再加點動畫上去,方便後面做進度條:
var canvas = document.getElementById("canvas1");
var ctx1 = canvas.getContext('2d');
//
// 中間設定漸變引數的程式碼一樣
//
function draw(ctx, x) {
ctx.clearRect(0, 0, 300, 300);
ctx.beginPath();
ctx.strokeStyle = grd;//'#ff4444';
if (x < Math.PI*2) {
x += Math.PI/100;
} else {
x = 0;
}
ctx.arc(80, 80, 50, 0, x, false); // 畫圓
ctx.stroke();
requestAnimationFrame(function () {
draw(ctx, x);
});
}
requestAnimationFrame(function () {
draw(ctx1, 0);
});複製程式碼
現在動畫有了,漸變也有了,但是一個最大的問題是,這個畫出來的是一個從左到右的漸變,上下顏色是對稱的。而我們想要的效果是上下非對稱的。
非對稱的漸變圓環
Canvas提供了線性漸變和徑向漸變(就是從圓心往外漸變,一個圓周上的顏色相同),二者都無法滿足我們設計師畫出的這個騷氣的圓。
於是,這裡要藉助另一個東東,ctx.createPattern
。
關於createPattern
方法的定義如下:
createPattern() 方法在指定的方向內重複指定的元素。元素可以是圖片、視訊,或者其他 canvas 元素。被重複的元素可用於繪製/填充矩形、圓形或線條等等。
上面說可以指定用圖片來繪製圓形,斯國一。
來上程式碼:
var canvas = document.getElementById("canvas2");
var ctx2 = canvas.getContext('2d');
ctx2.lineWidth = 8;
ctx2.lineCap="round";
var img;
img = new Image();
img.src = "./bg.png";
if (img.complete) {
setImageFill();
} else {
img.onload = setImageFill;
}
var newFill = null;
function setImageFill() {
newFill = ctx2.createPattern(img, 'no-repeat');
drawNew(ctx2, 0);
}
function drawNew(ctx, x) {
ctx.clearRect(0, 0, 300, 300);
ctx.beginPath();
ctx.strokeStyle = newFill;
if (x < Math.PI*2) {
x += Math.PI/100;
} else {
x = 0;
}
ctx.arc(50, 50, 46, 0, x, false);
ctx.stroke();
requestAnimationFrame(function () {
drawNew(ctx, x);
});
}複製程式碼
畫出來的效果:
程式碼很多有幾點需要注意:
- 首先是載入圖片,要等圖片載入完之後再去進行繪製,也可以考慮將圖片base64進去;
ctx2.createPattern(img, 'no-repeat')
建立Pattern的時候不對圖片做repeat;ctx.arc(50, 50, 46, 0, x, false);
畫圓的時候需要注意 如果想畫出來的半徑為50的話,需要用50減去描邊寬度的一半,也就是50-8/2 這個就是這裡半徑設定46的由來。因為描邊是把線放在中間然後往兩邊擴充套件來描,所以設定lineWidth
為8的時候,實際我們看到的描邊是4;ctx2.lineCap="round";
設定描邊的兩頭是圓形。
另外我們用的圖片是這樣的:
如果考慮到想支援各種Size可以現把圖片畫到另一個canvas上,做個resize。
var bg = $('<canvas>')[0];
var size = 100;
bg.width = size;
bg.height = size;
bg.getContext('2d').drawImage(img, 0, 0, size, size);複製程式碼
至此,一個如此騷氣的圓環就畫完了。
完整程式碼:github.com/bob-chen/ca…
tips:移動端解決Canvas鋸齒問題
Canvas畫出來的實際上是點陣圖,在移動端高清屏橫行,我們需要根據window.devicePixelRatio
來畫一個更大的Canvas,然後再縮小,原理類似於移動端使用雙倍圖,這樣可以很大程度上解決鋸齒問題,白色背景下基本看不出來。不過在黑色背景下細看還是很發現有一點鋸齒。
//Variables global to the chart
var width = context.canvas.width;
var height = context.canvas.height;
//High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
if (window.devicePixelRatio) {
context.canvas.style.width = width + "px";
context.canvas.style.height = height + "px";
context.canvas.height = height * window.devicePixelRatio;
context.canvas.width = width * window.devicePixelRatio;
context.scale(window.devicePixelRatio, window.devicePixelRatio);
}複製程式碼
參考
www.w3school.com.cn/tags/canvas…
www.w3school.com.cn/tags/canvas…
P.S 已新增svg的實現:一個比想象中更騷氣的圓 - svg 實現