亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > HTML5 > 正文

Canvas 文本轉粒子效果的實現代碼

2024-09-05 07:19:36
字體:
來源:轉載
供稿:網友

本文介紹了Canvas 文本轉粒子效果的實現代碼,分享給大家,希望對大家有所幫助,具體如下:

通過粒子來繪制文本讓人感覺很有意思,配合粒子的運動更會讓這個效果更加酷炫。本文介紹在 canvas 中通過粒子來繪制文本的方法。

實現原理

總的來說要做出將文本變成粒子展示的效果其實很簡單,實現的原理就是使用兩張 canvas,一張是用戶看不到的 A canvas,用來繪制文本;另一張是用戶看到的 B canvas,用來根據 A 的文本數據來生成粒子。直觀表示如圖:

創建離屏 canvas

HTML 只需要放置主 canvas 即可:

<!-- HTML 結構 --><html><head>  ...</head><body>  <canvas id="stage"></canvas></body></html>

然后創建一個離屏 canvas,并繪制文本:

const WIDTH = window.innerWidth;const HEIGHT = window.innerHeight;const offscreenCanvas = document.createElement('canvas');const offscreenCtx = offscreenCanvas.getContext('2d');offscreenCanvas.width = WIDTH;offscreenCanvas.height = HEIGHT;offscreenCtx.font = '100px PingFang SC';offscreenCtx.textAlign = 'center';offscreenCtx.baseline = 'middle';offscreenCtx.fillText('Hello', WIDTH / 2, HEIGHT / 2);

這時頁面上什么也沒有發生,但實際上可以想象在離屏 canvas 上,此時應該如圖所示:

核心方法 getImageData

使用 canvas 的 getImageData 方法,可以獲取一個 ImageData 對象,這個對象用來描述 canvas 指定區域內的像素數據。也就是說,我們可以獲取 “Hello” 這個文本每個像素點的位置和顏色,也就可以在指定位置生成粒子,最后形成的效果就是粒子拼湊成文本了。

要獲取像素信息,需要使用 ImageData 對象的 data 屬性,它將所有像素點的 rgba 值鋪開成了一個數組,每個像素點有 rgba 四個值,這個數組的個數也就是 像素點數量 * 4。

假設我選取了一個 3 * 4 區域,那么一共 12 個像素點,每個像素點有 rgba 四個值,所以 data 這個數組就會有 12 * 4 = 48 個元素。

如果打印出 data,可以看到即從左往右,從上往下排列這些像素點的 rgba。

當然我們要獲取的區域必須要包含文本,所以應該獲取整個離屏 canvas 的區域:

const imgData = offscreenCtx.getImageData(0, 0, WIDTH, HEIGHT).data;

生成粒子

拿到 ImageData 后,通過遍歷 data 數組,可以判斷在離屏 canvas 的畫布中,哪些點是有色彩的(處于文本中間),哪些點是沒有色彩的(不在文本上),把那些有色彩的像素位置記下來,然后在主 canvas 上生成粒子,就 ok 了。

首先創建一下粒子類:

class Particle {    constructor (options = {}) {        const { x = 0, y = 0, color = '#fff', radius = 5} = options;        this.radius = radius;        this.x = x;        this.y = y;        this.color = color;    }    draw (ctx) {        ctx.beginPath();        ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);        ctx.fillStyle = this.color;        ctx.fill();        ctx.closePath();    }}

遍歷 data,我們可以根據透明度,也就是 rgba 中的第四個元素是否不為 0 來判斷該像素是否在文本中。

const particles = [];const skip = 4;for (var y = 0; y < HEIGHT; y += skip) {    for (var x = 0; x < WIDTH; x += skip) {        var opacityIndex = (x + y * WIDTH) * 4 + 3;        if (imgData[opacityIndex] > 0) {            particles.push(new Particle({                x,                y,                radius: 1,                color: '#2EA9DF'            }));        }    }}

我們用 particles 數組來存放所有的粒子,這里的 skip 的作用是遍歷的步長,如果我們一個像素一個像素地掃,那么最后拼湊文本的粒子將會非常密集,增大這個值,最后產生的粒子就會更稀疏。

最后在創建主 canvas 并繪制即可:

const canvas = document.querySelector('#stage');canvas.width = WIDTH;canvas.height = HEIGHT;const ctx = canvas.getContext('2d');for (const particle of particles) {    particle.draw(ctx);}

效果如下:

完整代碼見01-basic-text-to-particles

添加效果

了解實現原理之后,其實其他的就都是給粒子添加一些動效了。首先可以讓粒子有一些隨機的位移,避免看上去過于整齊。

const particles = [];const skip = 4;for (var y = 0; y < HEIGHT; y += skip) {    for (var x = 0; x < WIDTH; x += skip) {        var opacityIndex = (x + y * WIDTH) * 4 + 3;        if (imgData[opacityIndex] > 0) {            // 創建粒子時加入隨機位移            particles.push(new Particle({                x: x + Math.random() * 6 - 3,                y: y + Math.random() * 6 - 3,                radius: 1,                color: '#2EA9DF'            }));        }    }}

效果如下:

如果想實現變大的效果,如:

這種要怎么實現呢,首先需要隨機產生粒子的大小,這只需要在創建粒子時對 radius 進行 random 即可。另外如果要讓粒子半徑動態改變,那么需要區分開粒子的渲染半徑和初始半徑,并使用 requestAnimationFrame 進行動畫渲染:

class Particle {    constructor (options = {}) {        const { x = 0, y = 0, color = '#fff', radius = 5} = options;        this.radius = radius;        // ...        this.dynamicRadius = radius; // 添加 dynamicRadius 屬性    }    draw (ctx) {        // ...        ctx.arc(this.x, this.y, this.dynamicRadius, 0, 2 * Math.PI, false); // 替換為 dynamicRadius        // ...    }        update () {        // TODO    }}requestAnimationFrame(function loop() {    requestAnimationFrame(loop);    ctx.fillStyle = '#fff';    ctx.fillRect(0, 0, WIDTH, HEIGHT);    for (const particle of particles) {        particle.update();        particle.draw(ctx);    }});

那么關鍵就在于粒子的 update 方法要如何實現了,假設我們想讓粒子半徑在 1 到 5 中平滑循環改變,很容易讓人聯想到三角函數,如:

橫軸應該是與時間相關,可以再維護一個變量每次調用 update 的時候進行加操作,簡單做也可以直接用時間戳來進行計算。update 方法示例如下:

update () {    this.dynamicRadius = 3 + 2 * Math.sin(new Date() / 1000 % 1000 * this.radius);}

完整代碼見 02-text-to-particles-with-size-changing

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产欧美一区二区三区视频| 亚洲女人天堂成人av在线| 亚洲欧美日韩精品| 日韩精品免费一线在线观看| 亚洲一区二区三区成人在线视频精品| 欧美午夜精品久久久久久人妖| 国产精品偷伦免费视频观看的| 国产成人一区二区在线| 国产女人18毛片水18精品| 久久亚洲精品国产亚洲老地址| 久久久久五月天| 国产一区二区在线免费| 91精品一区二区| 91久久久亚洲精品| 日韩女优人人人人射在线视频| 国产ts人妖一区二区三区| 欧美精品18videosex性欧美| 57pao成人国产永久免费| 狠狠躁夜夜躁人人躁婷婷91| 欧美午夜精品久久久久久久| 欧美日韩亚洲一区二| 日韩av手机在线观看| 国产精品久久久久久久美男| 国产欧美日韩高清| 亚洲欧洲午夜一线一品| 日韩在线视频观看| 亚洲精品电影在线| 国产精品视频播放| 精品中文字幕在线观看| 国产一区玩具在线观看| 国产午夜精品视频免费不卡69堂| 91在线观看免费高清完整版在线观看| 欧美日韩国产成人在线观看| 疯狂蹂躏欧美一区二区精品| 久久男人资源视频| 日韩久久免费视频| 亚洲天堂色网站| 亚洲理论在线a中文字幕| 伊人激情综合网| 亚洲国产精品字幕| 久久精品国产久精国产思思| 精品视频偷偷看在线观看| 亚洲一区二区三区成人在线视频精品| 久99九色视频在线观看| 亚洲第一中文字幕在线观看| 亚洲石原莉奈一区二区在线观看| 亚洲国产精品资源| 亚洲欧美制服另类日韩| 欧美做受高潮1| 久久久av一区| 精品视频偷偷看在线观看| 欧美成人精品在线视频| 国产精品久久一区| 亚洲国产成人爱av在线播放| 亚洲2020天天堂在线观看| 久久综合伊人77777尤物| 亚洲字幕一区二区| 国产精品欧美一区二区| 91亚洲国产成人久久精品网站| 亚洲第一色中文字幕| 国产亚洲精品久久久久久777| 日韩免费观看在线观看| 色琪琪综合男人的天堂aⅴ视频| 久久久久久久999精品视频| 国产亚洲视频在线| 伊人久久久久久久久久久| 国产成人精品电影久久久| 亚洲第一精品夜夜躁人人爽| 国产精品久久久久77777| 欧美日韩亚洲国产一区| 久久99精品久久久久久噜噜| 久久精品国产v日韩v亚洲| 欧美精品一本久久男人的天堂| 国产精品自产拍高潮在线观看| xvideos亚洲| 欧美精品国产精品日韩精品| 亚洲一区中文字幕在线观看| 91成人精品网站| 亚洲va欧美va国产综合久久| 中文字幕精品影院| 日韩在线视频二区| 欧美性20hd另类| 国产欧美日韩精品丝袜高跟鞋| 国产精品直播网红| 欧美人与性动交a欧美精品| 欧美性猛交xxxx乱大交蜜桃| 热草久综合在线| 一区二区三区美女xx视频| 美日韩精品视频免费看| 亚洲天堂免费观看| 中文字幕亚洲欧美一区二区三区| 亚洲欧美在线看| 欧美日本中文字幕| 亚洲香蕉伊综合在人在线视看| 日韩中文在线不卡| 色七七影院综合| 国产精品直播网红| 国产精品aaa| 欧美日韩成人精品| 国产亚洲视频在线观看| 亚洲欧洲黄色网| 成人乱人伦精品视频在线观看| 成人免费福利视频| 国产一区二区三区在线免费观看| 日韩精品免费在线播放| 日韩大片在线观看视频| 日韩精品中文字幕在线播放| 日韩美女免费观看| 在线视频欧美性高潮| 亚洲人成77777在线观看网| 亚洲综合大片69999| 日韩av在线一区二区| 成人做爽爽免费视频| 亚洲成人激情图| 成人字幕网zmw| 日韩免费在线电影| 国产日韩专区在线| 国产一区二区三区网站| 色综合久久88色综合天天看泰| 欧美日韩亚洲成人| 92看片淫黄大片看国产片| 欧美色另类天堂2015| 日韩中文字幕在线观看| 亚洲福利视频网| 国产综合香蕉五月婷在线| 国产91精品网站| 日本最新高清不卡中文字幕| 色偷偷偷亚洲综合网另类| 久久99精品国产99久久6尤物| 国产日韩欧美日韩大片| 亚洲欧洲免费视频| 亚洲成人久久一区| 欧美乱人伦中文字幕在线| 久久久久久成人精品| 色狠狠av一区二区三区香蕉蜜桃| 2018中文字幕一区二区三区| 一夜七次郎国产精品亚洲| 亚洲欧美日韩直播| 欧美成人午夜影院| 97久久国产精品| 57pao国产成人免费| 精品国产乱码久久久久酒店| 福利二区91精品bt7086| 亚洲国产精品资源| 午夜精品久久久久久久99热| 亚洲第一精品自拍| 韩国福利视频一区| 91极品视频在线| 77777少妇光屁股久久一区| 欧美激情免费在线| 91精品国产91久久久久久| 精品久久香蕉国产线看观看gif| 777精品视频| 懂色av影视一区二区三区| 精品视频www| 亚洲女同精品视频| 欧日韩不卡在线视频| 亚洲色图综合久久| 国产精品永久免费视频| 国产亚洲精品高潮| 欧美综合一区第一页| 欧美性极品xxxx做受| 97视频人免费观看| 一区二区三区国产视频|