canvas用於在網頁上繪製圖像、動畫,能夠將其理解爲畫布,在這個畫布上構建想要的效果。javascript
canvas能夠繪製動態效果,除了經常使用的規則動畫以外,還能夠採用粒子的概念來實現較複雜的動效,本文分別採用普通動效與粒子特效實現了一個簡單的時鐘。java
普通動效即利用canvas的api,實現有規則的圖案、動畫。canvas
該效果實現比較簡單,主要分析一下刻度與指針角度偏移的實現。api
此例爲小時刻度的繪製:錶盤上共有12個小時,Math.PI爲180°,每小時佔據30°。 .save()表示保存canvas當前環境的狀態,在此基礎上進行繪製。繪製完成以後,返回以前保存過的路徑狀態和屬性。數組
分鐘刻度同理,改變角度與樣式便可。瀏覽器
// 小時時間刻度
offscreenCanvasCtx.save();
for (var i = 0; i < 12; i++) {
offscreenCanvasCtx.beginPath();
// 刻度顏色
offscreenCanvasCtx.strokeStyle = '#fff';
// 刻度寬度
offscreenCanvasCtx.lineWidth = 3;
// 每小時佔據30°
offscreenCanvasCtx.rotate(Math.PI / 6);
// 開始繪製的位置
offscreenCanvasCtx.lineTo(140, 0)
// 結束繪製的位置;
offscreenCanvasCtx.lineTo(120, 0);
// 繪製路徑
offscreenCanvasCtx.stroke();
}
offscreenCanvasCtx.restore();
複製代碼
以秒針爲例:獲取當前時間的秒數,並計算對應的偏移角度dom
var now = new Date(),
sec = now.getSeconds(),
min = now.getMinutes(),
hr = now.getHours();
hr = hr > 12 ? hr - 12 : hr;
//秒針
offscreenCanvasCtx.save();
offscreenCanvasCtx.rotate(sec * (Math.PI / 30));
......
offscreenCanvasCtx.stroke();
複製代碼
canvas能夠用來繪製複雜,不規則的動畫。粒子特效能夠用來實現複雜、隨機的動態效果。函數
粒子,指圖像數據imageData
中的每個像素點,獲取到每一個像素點以後,添加屬性或事件對區域內的粒子進行交互,達到動態效果。動畫
如下圖的圖片轉化爲例,該效果是先在canvas上渲染圖片,而後獲取文字所在區域的每一個像素點。ui
let image = new Image();
image.src='../image/logo.png';
let pixels=[]; //存儲像素數據
let imageData;
image.width = 300;
image.height = 300
// 渲染圖片,並獲取該區域內像素信息
image.onload=function(){
ctx.drawImage(image,(canvas.width-image.width)/2,(canvas.height-image.height)/2,image.width,image.height);
imageData=ctx.getImageData((canvas.width-image.width)/2,(canvas.height-image.height)/2,image.width,image.height); //獲取圖表像素信息
//繪製圖像
};
複製代碼
圖片的大小爲300*300,共有90000個像素,每一個像素佔4位,存放rgba數據。
function getPixels(){
var pos=0;
var data=imageData.data; //RGBA的一維數組數據
//源圖像的高度和寬度爲300px
for(var i=1;i<=image.width;i++){
for(var j=1;j<=image.height;j++){
pos=[(i-1)*image.width+(j-1)]*4; //取得像素位置
if(data[pos]>=0){
var pixel={
x:(canvas.width-image.width)/2+j+Math.random()*20, //從新設置每一個像素的位置信息
y:(canvas.height-image.height)/2+i+Math.random()*20, //從新設置每一個像素的位置信息
fillStyle:'rgba('+data[pos]+','+(data[pos+1])+','+(data[pos+2])+','+(data[pos+3])+')'
}
pixels.push(pixel);
}
}
}
}
function drawPixels() {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0,0,canvas.width,canvas.height);
var len = pixels.length, curr_pixel = null;
for (var i = 0; i < len; i++) {
curr_pixel = pixels[i];
ctx.fillStyle = curr_pixel.fillStyle;
ctx.fillRect(curr_pixel.x, curr_pixel.y, 1, 1);
}
}
複製代碼
function time() {
ctx.clearRect(0,0,canvas.width,canvas.height)
ctx.font = "150px 黑體";
ctx.textBaseline='top';
ctx.fillStyle = "rgba(245,245,245,0.2)";
ctx.fillText(new Date().format('hh:mm:ss'),(canvas.width-textWidth)/2,(canvas.height-textHeight)/2,textWidth,textHeight);
}
複製代碼
文字轉換粒子概念同上,獲取選定區域的像素,根據篩選條件進行選擇並存入數組。通過遍歷後從新繪製。
function getPixels(){
let imgData = ctx.getImageData((canvas.width-textWidth)/2,(canvas.height-textHeight)/2,textWidth,textHeight);
let data = imgData.data
pixelsArr = []
for(let i=1;i<=textHeight;i++){
for(let j=1;j<=textWidth;j++){
pos=[(i-1)*textWidth+(j-1)]*4; //取得像素位置
if(data[pos]>=0){
var pixel={
x:j+Math.random()*20, //從新設置每一個像素的位置信息
y:i+Math.random()*20, //從新設置每一個像素的位置信息
fillStyle:'rgba('+data[pos]+','+(data[pos+1])+','+(data[pos+2])+','+(data[pos+3])+')'
};
pixelsArr.push(pixel);
}
}
}
}
複製代碼
imgData
保存了所選區域內的像素信息,每一個像素點佔據4位,保存了RGBA四位信息。篩選每一個像素的第四位,這段代碼中將全部透明度不爲0的像素都保存到了數組pixelsArr
中。
x
、y
記載了該粒子的位置信息,爲了產生效果圖中的運動效果,給每一個粒子添加了0-20個像素的偏移位置,每次重繪時,偏移位置隨機生成,產生運動效果。
獲取粒子以後,須要清除畫布中原有的文字,將獲取到的粒子從新繪製到畫布上去。
function drawPixels() {
// 清除畫布內容,進行重繪
ctx.clearRect(0,0,canvas.width,canvas.height);
for (let i in pixelsArr) {
ctx.fillStyle = pixelsArr[i].fillStyle;
let r = Math.random()*4
ctx.fillRect(pixelsArr[i].x, pixelsArr[i].y, r, r);
}
}
複製代碼
粒子重繪時的樣式爲篩選像素時本來的顏色與透明度,而且每一個在畫布上繪製每一個粒子時,定義大小參數r,r取值爲0-4中隨機的數字。最終生成的粒子大小隨機。
獲取粒子併成功重繪以後,須要頁面實時刷新時間。這裏採用window.requestAnimationFrame(callback)
方法。
function time() {
......
getpixels(); //獲取粒子
drawPixels(); // 重繪粒子
requestAnimationFrame(time);
}
複製代碼
window.requestAnimationFrame(callback)
方法告訴瀏覽器您但願執行動畫並請求瀏覽器在下一次重繪以前調用指定的函數來更新動畫。該方法使用一個回調函數做爲參數,這個回調函數會在瀏覽器重繪以前調用。
該方法不須要設置時間間隔,調用頻率採用系統時間間隔(1s)。
本文主要經過兩種不一樣的方式實現了時鐘的動態效果,其中粒子時鐘具備更多的可操做性。在之後的canvas系列中會針對粒子系統實現更多的動態效果。