前端实现旗帜飘动效果系列 (Ⅲ):canvas2D实现(2)
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
? ? ?本講我們?cè)谏弦恢v的基礎(chǔ)上,給旗子添加高光,使其看起來(lái)更加有立體感。我會(huì)用兩種方式來(lái)分別實(shí)現(xiàn)這個(gè)效果,然后比較一下優(yōu)劣,還是先講原理。
?? ? 方法一:在原來(lái)的代碼drawImage之后通過 fillRect 函數(shù)來(lái)增加一個(gè)白色蒙層,通過透明度的遞增和遞減來(lái)模擬。具體多少透明度?當(dāng)然你可以用數(shù)學(xué)的方法來(lái)求導(dǎo)計(jì)算出某一點(diǎn)的斜率,根據(jù)其大小和正負(fù)得出其透明度大小,斜率越大,透明度越小。這里用一種更取巧也效率更高的方法,即保存某一點(diǎn)前一個(gè)點(diǎn)的y軸坐標(biāo),與該點(diǎn)的y坐標(biāo)相減,即可得到斜率的相對(duì)大小,因?yàn)閮牲c(diǎn)之間的x軸上距離都是1px,所以y軸變化越大,|斜率|則越大。
? ? 方法二:先通過遍歷 getImageData 函數(shù)返回的元素逐像素獲取原始畫布每個(gè)點(diǎn)的rgba值,然后每一幀通過運(yùn)動(dòng)函數(shù)對(duì)每個(gè)點(diǎn)的位置進(jìn)行偏移,對(duì)比原畫布,獲取該點(diǎn)在原位置的rgba值,然后直接對(duì)a分量進(jìn)行修改,修改的依據(jù)仍然是斜率。
這是方法一的代碼,我只貼出修改的部分(// +++ 之間):
var y = 0 // +++++++++++++++++++++ var lastY = 0 // +++++++++++++++++++++ var distance = 0 var tick = function () {if (stop) return falsetimeNow = Date.now()delta = timeNow - timeLastif (delta > interval) {timeLast = timeNowdistance += (delta / 1000 * v)ctx.clearRect(0, 0, canvasWidth, canvasHeight)for (var x = 0; x < imgWidth; x++) {y = cftA * x * Math.sin(cftX * (x - distance)) + amplitudectx.drawImage(image, x, 0, 1, imgHeight, x, y, 1, imgHeight)// +++++++++++++++++++++ctx.fillStyle = 'rgba(255,255,255,' + (x === 0 ? 0 : (y - lastY) * 0.5) + ')'ctx.fillRect(x, y, 1, imgHeight)// +++++++++++++++++++++lastY = y}}requestAnimationFrame(tick) }完整代碼戳這里
Demo:See the Pen?flag waving by canvas2d(rect) ?by Kay (@oj8kay) on?CodePen.
方法二的核心代碼如下:
var tick = function () {if (stop) return falsetimeNow = Date.now()delta = timeNow - timeLastif (delta > interval) {timeLast = timeNowdistance += (delta / 1000 * v)// +++++++++++++++++++++for (var i = 0; i < canvasHeight; i++) {for (var j = 0; j < canvasWidth; j++) {if (i === 0) {yBuf[j] = cftA * j * Math.sin(cftX * (j - distance))}r = (i * canvasWidth + j) * 4g = r + 1b = r + 2a = r + 3oR = r + (~~(0.5 + yBuf[j])) * canvasWidth * 4oG = oR + 1oB = oR + 2oA = oR + 3offset = j === 0 ? 0 : (yBuf[j] - lastY) * 100pixels[r] = oPixels[oR] + offsetpixels[g] = oPixels[oG] + offsetpixels[b] = oPixels[oB] + offsetpixels[a] = oPixels[oA]lastY = yBuf[j]}}ctx.putImageData(imgData, 0, 0)// +++++++++++++++++++++}requestAnimationFrame(tick) }這個(gè)方法做出的另外一點(diǎn)修改是,由于操作是對(duì)畫布逐像素進(jìn)行的,包括透明元素,所以既不用clearRect,也不用對(duì)Y軸進(jìn)行偏移。
完整代碼戳這里
Demo:See the Pen?flag waving by canvas2d(pixel) ?by Kay (@oj8kay) on?CodePen.
兩個(gè)方法的效果圖如下
通過chrome dev tool對(duì)兩者的性能進(jìn)行分析:
這是方法1的CPU占有率的變化:
這是方法2的:
哪個(gè)性能更好顯而易見。方法二的性能雖然差,但是它的好處是靈活性更大,你甚至可以任意改變“光源”的位置。
? ?下一講我會(huì)通過webgl對(duì)其進(jìn)行重寫,使其大部分的渲染邏輯從CPU轉(zhuǎn)到GPU,可以使其的性能得到成倍的提高。建議大家先學(xué)習(xí)一下webgl的一些基本用法,包括矩陣的知識(shí),著色器等。
轉(zhuǎn)載于:https://my.oschina.net/codingDog/blog/1839099
總結(jié)
以上是生活随笔為你收集整理的前端实现旗帜飘动效果系列 (Ⅲ):canvas2D实现(2)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WIFI搜索的到别人,却找不到自己家的w
- 下一篇: 简单介绍tomcat中maxThread