摘要:運(yùn)動(dòng)坐標(biāo)變量坐標(biāo)變量繪制方法畫布渲染清除畫布位置變化繪制繼續(xù)渲染動(dòng)起來(lái)的多點(diǎn)多線動(dòng)的是點(diǎn),畫的是線給對(duì)象添加運(yùn)動(dòng)變量和兩個(gè)值表示點(diǎn)在軸和軸的運(yùn)動(dòng)量此處為在之間運(yùn)動(dòng)。
Canvas 點(diǎn)線動(dòng)畫案例
arc(x, y, r, start, stop)
moveTo(x, y) 定義線條開始坐標(biāo)lineTo(x, y) 定義線條結(jié)束坐標(biāo)
fill()
stroke()1、畫一個(gè)點(diǎn)
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
// 坐標(biāo)(x, y)、半徑、開始角度、結(jié)束角度、順時(shí)針(逆時(shí)針) ctx.arc(70, 80, 30, 0, Math.PI * 2, false);2、畫很多點(diǎn)
//生成點(diǎn) for (let i = 0; i < dotsNum; i ++) { x = Math.random() * canvas.width; y = Math.random() * canvas.height; r = Math.random() * 4; // 隨機(jī)生成 <4 的半徑值 ctx.beginPath(); ctx.arc(x, y, r, 0, 2 * Math.PI); ctx.fillStyle = "rgba(0,0,0,.8)"; ctx.fill(); ctx.closePath(); }3、畫兩點(diǎn)一線
確定兩個(gè)點(diǎn)的坐標(biāo) + lineTo 、moveTo
for (let i = 0; i < 2; i++) { ctx.beginPath() // 設(shè)置原點(diǎn)位置為(100,100),半徑為10 ctx.arc(100 + i * 150, 100 + i * 250, 10, 0, Math.PI * 2, false) // 兩個(gè)點(diǎn)進(jìn)行畫線 ctx.moveTo(100, 100) ctx.lineTo(100 + i * 150, 100 + i * 250) // 設(shè)置線的寬度,單位是像素 ctx.lineWidth = 2 ctx.stroke() // 實(shí)心圓 - 填充顏色,默認(rèn)是黑色 // 實(shí)心圓 - 畫實(shí)心圓 ctx.fill() ctx.closePath() }4、畫多點(diǎn)多線
當(dāng)點(diǎn)很多、元素很多的時(shí)候再進(jìn)行畫線操作會(huì)很繁瑣,對(duì)于多元素的情況,創(chuàng)建實(shí)例對(duì)象,把變量存儲(chǔ)在實(shí)例對(duì)象上。
var Dots = function () { // 畫布 this.canvas; this.ctx; // 畫點(diǎn) this.x; this.y; this.r; };
Dots.prototype = { // 初始化點(diǎn)的方法 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; // 隨機(jī)生成 <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(); } };
// 繪制連線 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, // 三角形斜邊長(zhǎng) 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(); } } }
點(diǎn)與點(diǎn)之間連線
優(yōu)化點(diǎn):
限定點(diǎn)與點(diǎn)的連線距離(優(yōu)化:根據(jù)點(diǎn)之間的距離添加連線顏色透明度)
Canvas 畫布的工作原理和顯示器工作原理一樣,都是通過(guò)不斷的刷新繪制。瀏覽器的刷新是實(shí)時(shí)的,而 Canvas 的刷新是手動(dòng)觸發(fā)的,如果我們只想在 Canvas 上實(shí)現(xiàn)靜態(tài)的效果,就沒(méi)必不斷刷新。
requestAnimationFrame是瀏覽器用于定時(shí)循環(huán)操作的一個(gè)接口,類似于setTimeout,主要用途是按幀對(duì)網(wǎng)頁(yè)進(jìn)行重繪。requestAnimationFrame不是自己指定回調(diào)函數(shù)運(yùn)行的時(shí)間,而是跟著瀏覽器內(nèi)建的刷新頻率來(lái)執(zhí)行回調(diào)。
瀏覽器可以優(yōu)化并行的動(dòng)畫動(dòng)作,更合理的重新排列動(dòng)作序列,并把能夠合并的動(dòng)作放在一個(gè)渲染周期內(nèi)完成,從而呈現(xiàn)出更流暢的動(dòng)畫效果,一旦頁(yè)面不處于瀏覽器的當(dāng)前標(biāo)簽,就會(huì)自動(dòng)停止刷新。
持續(xù)調(diào)用 requestAnimFrame清除動(dòng)畫調(diào)用 cancelAnimationFrame
var canvas = document.querySelector("canvas"); var context = canvas.getContext("2d"); // 畫布渲染 var render = function () { // 清除畫布 context.clearRect(0, 0, canvas.width, canvas.height); // 繪制(在canvas畫布上繪制圖形的代碼) draw(); // 繼續(xù)渲染 requestAnimationFrame(render); }; render();
上面的draw()就是在 canvas 畫布上繪制圖形的代碼,但是如果僅僅有上面代碼還不夠,如果是同一個(gè)位置不斷刷新,我們看到的還是靜止不動(dòng)的效果,所以還需要一個(gè)運(yùn)動(dòng)變量。
var canvas = document.querySelector("canvas"); var context = canvas.getContext("2d"); // 坐標(biāo)變量 var x = 0; // 繪制方法 var draw = function () { ball.x = x; }; // 畫布渲染 var render = function () { // 清除畫布 context.clearRect(0, 0, canvas.width, canvas.height); // 位置變化 x++; // 繪制 draw(); // 繼續(xù)渲染 requestAnimationFrame(render); }; render();6、動(dòng)起來(lái)的多點(diǎn)多線
動(dòng)的是點(diǎn),畫的是線
let Dots = function () { // 畫布 this.canvas; this.ctx; // 畫點(diǎn) this.x; this.y; this.r; // 移動(dòng) // 隨機(jī)確定點(diǎn)的移動(dòng)速度與方向 速度值在 [-2, 2) 之間 提高數(shù)值可加快速度 //(Math.random() 隨機(jī)返回[0,1)的數(shù)) this.sx = Math.random() * 4 - 2; this.sy = Math.random() * 4 - 2; };
// 更新點(diǎn)位置 update: function () { this.x = this.x + this.sx; this.y = this.y + this.sy; // 點(diǎn)超出 canvas 范圍時(shí)重新初始化 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); }; }
由于點(diǎn)的位置不斷變換,因此需要將畫線的操作放在動(dòng)畫內(nèi)執(zhí)行,點(diǎn)的位置 update 一次就執(zhí)行一次連線。
function animateUpdate() { ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空canvas中原有的內(nèi)容 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, // 三角形斜邊長(zhǎng) 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(); } } } // 繼續(xù)渲染 requestAnimFrame(animateUpdate); }類似的例子
星空效果、下雨效果等
你可能不知道的點(diǎn)不要在style里指定 Canvas 的寬度,Canvas 畫布的尺寸的大小和顯示的大小是有很大的區(qū)別的,在 canvas 里面設(shè)置的是才是 Canvas 本身的大小。
如果不給設(shè)置 width、height 屬性時(shí),則默認(rèn) width 為 300、height 為 150, 單位都是 px。也可以使用 css 屬性來(lái)設(shè)置寬高,但是如寬高屬性和初始比例不一致,他會(huì)出現(xiàn)扭曲。所以,建議永遠(yuǎn)不要使用css屬性來(lái)設(shè)置的寬高。
畫新元素前記得要 beginPath()
不管用 moveTo 把畫筆移動(dòng)到哪里,只要不調(diào)用beginPath(),一直都是在畫一條路徑
fillRect 與 strokeRect 這種直接畫出獨(dú)立區(qū)域的函數(shù),也不會(huì)打斷當(dāng)前的path
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/117514.html
摘要:在數(shù)學(xué)上,遞推關(guān)系,也就是差分方程,是一種遞推地定義一個(gè)序列的方程式序列的每一項(xiàng)目是定義為前一項(xiàng)的函數(shù)。 《每周一點(diǎn)canvas動(dòng)畫》——差分函數(shù)的妙用 每周一點(diǎn)canvas動(dòng)畫代碼文件 好像上次更新還是十一前,這唰唰唰的就過(guò)去大半個(gè)月了,現(xiàn)在才更新實(shí)在不好意思。這次我們不涉及canvas 3D的內(nèi)容,主要分享一個(gè)比較炫的動(dòng)畫效果,可以算是上一篇文章《每周一點(diǎn)canvas動(dòng)畫》——3D...
摘要:在數(shù)學(xué)上,遞推關(guān)系,也就是差分方程,是一種遞推地定義一個(gè)序列的方程式序列的每一項(xiàng)目是定義為前一項(xiàng)的函數(shù)。某些簡(jiǎn)單定義的遞推關(guān)系式可能會(huì)表現(xiàn)出非常復(fù)雜的混沌的性質(zhì),他們屬于數(shù)學(xué)中的非線性分析領(lǐng)域。 每周一點(diǎn)canvas動(dòng)畫代碼文件 好像上次更新還是十一前,這唰唰唰的就過(guò)去大半個(gè)月了,現(xiàn)在更新我也沒(méi)什么不好意思的。這次我們不涉及canvas 3D的內(nèi)容,主要分享一個(gè)比較炫的動(dòng)畫效果,可以算...
摘要:模擬飛機(jī)航班線路動(dòng)畫一款基于的飛機(jī)航班線路模擬動(dòng)畫,它模擬了許多航班在不同目的地的起飛降落數(shù)量。跳動(dòng)加載動(dòng)畫可調(diào)節(jié)參數(shù)這是一款基于的跳動(dòng)加載動(dòng)畫,它的另一個(gè)特點(diǎn)是可以動(dòng)態(tài)調(diào)節(jié)動(dòng)畫參數(shù)。 showImg(https://segmentfault.com/img/bVblze6?w=900&h=383); HTML5 動(dòng)畫在Canvas 上得到了充分的發(fā)揮,我們 VIP 視頻也分享過(guò)很多相...
閱讀 2589·2023-04-26 01:44
閱讀 2620·2021-09-10 10:50
閱讀 1451·2019-08-30 15:56
閱讀 2348·2019-08-30 15:44
閱讀 546·2019-08-29 11:14
閱讀 3454·2019-08-26 11:56
閱讀 3042·2019-08-26 11:52
閱讀 949·2019-08-26 10:27