Canvas 繪制

畫圓:

arc(x, y, r, start, stop)

畫線:

moveTo(x, y) 定義線條開始坐標

lineTo(x, y) 定義線條結束坐標

填充:

fill()

繪制:

stroke()

1、畫一個點

初始化

? 瀏覽器不支持canvas!

找到??元素

let canvas = document.getElementById("canvas");

創建?context?對象

let ctx = canvas.getContext("2d");

畫圓

// 坐標(x, y)、半徑、開始角度、結束角度、順時針(逆時針)

ctx.arc(70,80,30,0, Math.PI*2, false);

2、畫很多點

//生成點

for(let i =0; i < dotsNum; i ++) {

????? x = Math.random() * canvas.width;?

?????y = Math.random() * canvas.height;?

?????r = Math.random() *4;? ?// 隨機生成 <4 的半徑值

????ctx.beginPath();? ctx.arc(x, y, r,0,2* Math.PI);?

?????ctx.fillStyle ="rgba(0,0,0,.8)";

? ????ctx.fill();?

?????ctx.closePath();

}

3、畫兩點一線

確定兩個點的坐標 + lineTo 、moveTo

for (let i =0; i <2; i++) {??

????ctx.beginPath()

????// 設置原點位置為(100,100),半徑為10

????ctx.arc(100+ i *150,100+ i *250,10,0, Math.PI*2, false)

????// 兩個點進行畫線

????ctx.moveTo(100,100)? ctx.lineTo(100+ i *150,100+ i *250)

????// 設置線的寬度,單位是像素

????ctx.lineWidth =2ctx.stroke()

????// 實心圓 - 填充顏色,默認是黑色// 實心圓 - 畫實心圓

????ctx.fill()?

?????ctx.closePath()

}

4、畫多點多線

當點很多、元素很多的時候再進行畫線操作會很繁瑣,對于多元素的情況,創建實例對象,把變量存儲在實例對象上。

定義一個Dots函數。

var Dots = function () {

????// 畫布

????this.canvas;this.ctx;

????// 畫點

????this.x;this.y;this.r;

};

添加一個用于點的生成的初始化方法。

Dots.prototype = {

// 初始化點的方法

init: function (canvas) {

????this.canvas = canvas;

????this.ctx =this.canvas.getContext('2d');

????this.x = Math.random() *this.canvas.width;

????this.y = Math.random() ????*this.canvas.height;

????this.r = Math.random() *4;???? // 隨機生成 <4 的半徑值

????this.ctx.beginPath();

????this.ctx.arc(this.x,this.y,this.r,0,2* ????Math.PI);

????this.ctx.fillStyle ="black";

????this.ctx.fill();

????this.ctx.closePath();

? }

};

在點與點之間進行畫線,每兩個點之間就有一條線,總共有C(n,2)條線。

// 繪制連線

for(var i =0; i < dotsNum; i ++) {

????for(var j = i +1;

?????j < dotsNum;?

????j ++) {

????var tx = dotsArr[i].x - dotsArr[j].x,? ? ??

????ty = dotsArr[i].y - dotsArr[j].y,

????// 三角形斜邊長

????s =Math.sqrt(Math.pow(tx,2) +Math.pow(ty,2));

????if(s < dotsDistance) {? ??

? ? ? ctx.beginPath();? ? ??

? ????ctx.moveTo(dotsArr[i].x, dotsArr[i].y);? ? ?

?????? ctx.lineTo(dotsArr[j].x, dotsArr[j].y);? ?

? ? ? ctx.strokeStyle ='rgba(0,0,0,'+(dotsDistance-s)/dotsDistance+')';? ? ??

????? ctx.strokeWidth =1;? ? ? ? ctx.stroke();? ? ? ? ctx.closePath();? ??

? }? ?

?}??

}

點與點之間連線

優化點:

限定點與點的連線距離(優化:根據點之間的距離添加連線顏色透明度)

5、requestAnimationFrame

Canvas 畫布的工作原理和顯示器工作原理一樣,都是通過不斷的刷新繪制。瀏覽器的刷新是實時的,而 Canvas 的刷新是手動觸發的,如果我們只想在 Canvas 上實現靜態的效果,就沒必不斷刷新。

requestAnimationFrame是瀏覽器用于定時循環操作的一個接口,類似于setTimeout,主要用途是按幀對網頁進行重繪。requestAnimationFrame不是自己指定回調函數運行的時間,而是跟著瀏覽器內建的刷新頻率來執行回調。

?優勢

瀏覽器可以優化并行的動畫動作,更合理的重新排列動作序列,并把能夠合并的動作放在一個渲染周期內完成,從而呈現出更流暢的動畫效果,一旦頁面不處于瀏覽器的當前標簽,就會自動停止刷新。

?使用方式

持續調用 requestAnimFrame

清除動畫調用 cancelAnimationFrame

?動效繪制大致路數:

var canvas =document.querySelector('canvas');

var context = canvas.getContext('2d');

// 畫布渲染

var render =function(){

????// 清除畫布

????context.clearRect(0,0, canvas.width, canvas.height);

????// 繪制(在canvas畫布上繪制圖形的代碼)

????draw();

????// 繼續渲染

????requestAnimationFrame(render);

};

render();

上面的draw()就是在 canvas 畫布上繪制圖形的代碼,但是如果僅僅有上面代碼還不夠,如果是同一個位置不斷刷新,我們看到的還是靜止不動的效果,所以還需要一個運動變量。

?運動坐標變量:

var canvas =document.querySelector('canvas');

var context = canvas.getContext('2d');

// 坐標變量var x =0;

// 繪制方法

var draw =function(){? ?

?ball.x = x;

};

// 畫布渲染

var render =function(){

// 清除畫布

context.clearRect(0,0, canvas.width, canvas.height);

// 位置變化

x++;

// 繪制

draw();

// 繼續渲染

requestAnimationFrame(render);

};

render();

6、動起來的多點多線

動的是點,畫的是線

給 Dots 對象添加運動變量,sx 和 sy 兩個值表示點在x軸和y軸的運動量,此處為在[-2, 2)之間運動。

let Dots = function () {

// 畫布

this.canvas;this.ctx;

// 畫點

this.x;

this.y;

this.r;

// 移動

// 隨機確定點的移動速度與方向 速度值在 [-2, 2) 之間 提高數值可加快速度

?//(Math.random() 隨機返回[0,1)的數)

this.sx = Math.random() *4-2;this.sy = Math.random() *4-2;};

添加更新點的方法update()

// 更新點位置

update: function () {

this.x =this.x +this.sx;this.y =this.y +this.sy;

// 點超出 canvas 范圍時重新初始化

if(this.x <0||this.x >this.canvas.width) {

this.init(this.canvas);??

? }

if(this.y <0||this.y >this.canvas.height) {

????this.init(this.canvas);?

?? }

this.ctx.beginPath();

this.ctx.arc(this.x,this.y,this.r,0,2* Math.PI);

this.ctx.fillStyle ="rgba(0,0,0,.6)";

this.ctx.fill();

this.ctx.closePath();?

?}

動畫及連線

兼容 requestAnimationFrame

let requestAnimFrame = requestAnimationFrame || webkitRequestAnimationFrame|| oRequestAnimationFrame|| msRequestAnimationFrame;? requestAnimFrame(animateUpdate); // 兼容不同瀏覽器的 requestAnimationFrame

或者使用 setTimeout 向下兼容:

// requestAnimationFrame的向下兼容處理

if(!window.requestAnimationFrame) {?

? window.requestAnimationFrame = function(fn) {??

? ? ? ?setTimeout(fn,17);??

? ?};

}

由于點的位置不斷變換,因此需要將畫線的操作放在動畫內執行,點的位置 update 一次就執行一次連線。

function animateUpdate(){? ??

?ctx.clearRect(0,0, canvas.width, canvas.height);

// 清空canvas中原有的內容

for(let i =0; i < dotsNum; i ++) {?

?? ? dotsArr[i].update();? ?

?}

// 繪制連線

for(let i =0; i < dotsNum; i ++) {

for(let j = i +1; j < dotsNum; j ++) {

let tx = dotsArr[i].x - dotsArr[j].x,? ?

ty = dotsArr[i].y - dotsArr[j].y,

// 三角形斜邊長

s =Math.sqrt(Math.pow(tx,2) +Math.pow(ty,2));

if(s < dotsDistance) {? ??

? ? ? ctx.beginPath();??

? ? ? ? ctx.moveTo(dotsArr[i].x, dotsArr[i].y);??

? ? ? ? ctx.lineTo(dotsArr[j].x, dotsArr[j].y);??

? ? ? ? ctx.strokeStyle ='rgba(0,0,0,'+(dotsDistance-s)/dotsDistance+')';? ?

?? ? ? ctx.strokeWidth =1;? ? ??

? ? ctx.stroke();? ? ?

?? ? ctx.closePath();? ?

?? ? }??

? ? }

? ? }

// 繼續渲染

requestAnimFrame(animateUpdate);?

?}



附加知識點

1、canvas 畫的圓不是圓,是橢圓

不要在style里指定 Canvas 的寬度,Canvas 畫布的尺寸的大小和顯示的大小是有很大的區別的,在 canvas 里面設置的是才是 Canvas 本身的大小。

如果不給<canvas>設置 width、height 屬性時,則默認 width 為 300、height 為 150, 單位都是 px。也可以使用 css 屬性來設置寬高,但是如寬高屬性和初始比例不一致,他會出現扭曲。所以,建議永遠不要使用css屬性來設置<canvas>的寬高。

2、不要企圖通過閉合現有路徑來開始一條新路徑

畫新元素前記得要 beginPath()

不管用 moveTo 把畫筆移動到哪里,只要不調用beginPath(),一直都是在畫一條路徑

fillRect 與 strokeRect 這種直接畫出獨立區域的函數,也不會打斷當前的path

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容