国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

程序員的小浪漫----文字粒子效果

xiaodao / 1289人閱讀

摘要:預(yù)覽完整項(xiàng)目預(yù)覽預(yù)覽地址粒子效果原理在中,可以通過(guò)方法來(lái)獲取像素?cái)?shù)據(jù)。下例是通過(guò)改變像素的數(shù)據(jù)而重新寫出來(lái)的文字。不過(guò)可能會(huì)造成文字部分地方缺失。煙花效果可以看一下我的上一篇,程序員的小浪漫煙火完整項(xiàng)目項(xiàng)目地址如果覺得還不錯(cuò),請(qǐng)一個(gè)吧。

預(yù)覽

完整項(xiàng)目預(yù)覽----預(yù)覽地址;

粒子效果原理

在canvas中,可以通過(guò)getImageData()方法來(lái)獲取像素?cái)?shù)據(jù)。

ctx.fillStyle = "#ff0000";
ctx.fillRect(0, 0, 1, 1);
const imageData = ctx.getImageData(0, 0, 1, 1);

imageData有三個(gè)屬性:

data:數(shù)組,包含了像素信息,每個(gè)像素會(huì)有四個(gè)長(zhǎng)度,如[255,0,0,255, ... ,255,127,0,255],分別代表該像素的RGBA值。

widthimageData對(duì)象的寬。

heightimageData對(duì)象的高。

首先在canvas寫上某種顏色文字,再去分析像素?cái)?shù)據(jù)(比如改像素是否有透明度等),然后自己記錄下該像素點(diǎn)的位置。

下例是通過(guò)改變像素的數(shù)據(jù)而重新寫出來(lái)的文字。

ctx.font = "bold 40px Arial";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillText("你好啊", 60, 20);

document.querySelector("#button").addEventListener("click", function(){
    const imgData = ctx.getImageData(0, 0, 120, 40);
    for(let i = 0;i < imgData.data.length; i+=4){
        if(imgData.data[i + 3] == 0) continue;
        imgData.data[i] = 255;
        imgData.data[i + 1] = 0;
        imgData.data[i + 2] = 0;
        // imgData.data[i + 3] = 255;  這個(gè)代表的是透明度 透明度不變 255最高 0最低
    }
    ctx.putImageData(imgData,120,0);
});

這段代碼只是示例說(shuō)明一下,實(shí)際上才不會(huì)有人這么腦殘去換顏色吧。

獲取點(diǎn)位置

要獲取點(diǎn)的位置,首先要將字寫在畫布上,但是字又不能讓別人看到。所以可以動(dòng)態(tài)創(chuàng)建一個(gè)畫布,這個(gè)畫布不會(huì)append到任何節(jié)點(diǎn)上,只會(huì)用于寫字。

const cache = document.createElement("canvas");

將寬高等與展示的畫布設(shè)置成一樣的。(不貼這部分的代碼了)

創(chuàng)建一個(gè)對(duì)象,用于獲取點(diǎn)的位置

const ShapeBuilder = {
    //初始化字的對(duì)齊方式等,我認(rèn)為middle 與 center比較好計(jì)算一點(diǎn)
    init(width, height){
        this.width = width;
        this.height = height;
        this.ctx = cache.getContext("2d");
        this.ctx.textBaseline = "middle";
        this.ctx.textAlign = "center";
    },
    //獲取位置之前必須先要寫入文字。 這里的size=40是默認(rèn)值
    write(words, x, y, size = 40){
        //清除之前寫的字。
        this.ctx.clearRect(0, 0, this.width, this.height);
        this.font = `bold ${size}px Arial`;
        this.ctx.fillText(words, x, y);
        //記錄當(dāng)前文字的位置,方便計(jì)算獲取像素的區(qū)域
        this.x = x;
        this.y = y;
        this.size = size;
        this.length = words.length;
    },
    getPositions(){
        //因?yàn)閕mgData數(shù)據(jù)非常的大,所以盡可能的縮小獲取數(shù)據(jù)的范圍。
        const xStart = this.x - (this.length / 2) * this.size, 
            xEnd = this.x + (this.length / 2) * this.size,
            yStart = this.y - this.size / 2, 
            yEnd = this.y + this.size / 2, 
            
            //getImageData(起點(diǎn)x, 起點(diǎn)y, 寬度, 高度);
            data = this.ctx.getImageData(xStart, yStart, this.size * this.length, this.size).data;
            
        //間隔 (下面有介紹)
        const gap = 4;
        
        let positions = [], x = xStart, y = yStart;
        
        for(var i = 0;i < data.length; i += 4 * gap){
            if(data[i+3] > 0){
                positions.push({x, y});    
            }
            
            x += gap;
            
            if(x >= xEnd){
                x = xStart;
                y += gap;
                i += (gap - 1) * 4 * (xEnd - xStart);
            }
        }
        return positions;
    }
}

ShapeBuilder.init();

關(guān)于gap:在循環(huán)imgData數(shù)組的時(shí)候,數(shù)據(jù)量太大可能會(huì)造成卡頓,所以可以使用間隔來(lái)獲取坐標(biāo)點(diǎn)的方法。不過(guò)可能會(huì)造成文字部分地方缺失。就需要個(gè)人來(lái)權(quán)衡利弊,自己來(lái)調(diào)整了。

gap的值必須能被xEnd-xStart給整除,不然會(huì)造成獲取坐標(biāo)點(diǎn)錯(cuò)位的后果。

關(guān)于canvasmiddlecenter的規(guī)則:

this.ctx.font = "bold 40px Arial";
this.ctx.fillText("你好",40 ,20);

效果如下圖所示

fillText設(shè)置的坐標(biāo)點(diǎn)剛好會(huì)是整個(gè)字的中點(diǎn),就是圖中middlecenter的交點(diǎn)。其實(shí)以其它對(duì)齊方式也是可以的,看個(gè)人喜好。

更多的對(duì)齊規(guī)則參考HTML 5 Canvas 參考手冊(cè)的文本。

創(chuàng)建微粒類

微粒應(yīng)該隨機(jī)生成,然后移動(dòng)到指定的位置去。

微粒類的屬性:

自身當(dāng)前位置(x,y), 目標(biāo)位置:(xEnd,yEnd),自身大?。╯ize),自身顏色(color),移動(dòng)快慢(e)

方法:go():每一幀都要移動(dòng)一段距離,render():渲染出微粒(我用心形的形狀)

class Particle {
    constructor({x, y, size = 2, color, xEnd, yEnd, e = 60} = {}){
        this.x = x;
        this.y = y;
        this.size = size;
        this.color = color ||  `hsla(${Math.random() * 360}, 90%, 65%, 1)`;
        this.xEnd = xEnd;
        this.yEnd = yEnd;
        
        //經(jīng)過(guò)e幀之后到達(dá)目標(biāo)地點(diǎn)
        this.e = e;
        //計(jì)算每一幀走過(guò)的距離
        this.dx = (xEnd - x) / e;
        this.dy = (yEnd - y) / e;
    }
    go(){
        //到目的后保持不動(dòng) (其實(shí)這里也可以搞點(diǎn)事情的)
        if(--this.e <= 0) {
            this.x = this.xEnd;
            this.y = this.yEnd;
            return ;
        }
        this.x += this.dx;
        this.y += this.dy;
    }
    render(ctx){
        this.go();
        //下面是畫出心型的貝塞爾曲線
        ctx.beginPath();
        ctx.fillStyle = this.color;
        ctx.moveTo(this.x + 0.5 * this.size, this.y + 0.3 * this.size);
        ctx.bezierCurveTo(this.x + 0.1 * this.size, this.y, this.x, 
                        this.y + 0.6 * this.size, this.x + 0.5 * 
                        this.size, this.y + 0.9 * this.size);
        ctx.bezierCurveTo(this.x + 1 * this.size, this.y + 0.6 * 
                        this.size, this.x + 0.9 * this.size, this.y, 
                        this.x + 0.5 * this.size,
                        this.y + 0.3 * this.size);
        ctx.closePath();
        ctx.fill();
        return true;
    }
}

微粒類最基本的屬性與方法就是這些,如果要讓粒子更好看一點(diǎn),或者更生動(dòng)一點(diǎn),可以自己添加一些屬性與方法。

具體流程
const canvas = {
    init(){
        //設(shè)置一些屬性
        this.setProperty();
        //創(chuàng)建微粒
        this.createParticles();
        //canvas的循環(huán)
        this.loop();
    },
    setProperty(){
        this.ctx = studio.getContext("2d");
        this.width = document.body.clientWidth;
        this.height = document.body.clientHeight;
        this.particles = [];
    },
    createParticles(){
        let dots;
        //ShapeBuilder.write(words, x, y, size)
        ShapeBuilder.write("每個(gè)字都是",this.width / 2, this.height / 3, 120);
        dots = ShapeBuilder.getPositions(6);
        ShapeBuilder.write("愛你的模樣", this.width / 2, this.height * 2 / 3, 120);
        dots = dots.concat(ShapeBuilder.getPositions(6));
        //dots已經(jīng)獲取到了字的坐標(biāo)點(diǎn) 
        //每一個(gè)微粒的目標(biāo)地點(diǎn)都是dots的坐標(biāo)
        //每一個(gè)微粒都隨機(jī)出生在畫布的某個(gè)位置
        for(let i = 0; i < dots.length; i++){
            this.particles.push(new Particle({
                xEnd:dots[i].x, 
                yEnd:dots[i].y , 
                x: Math.random() * this.width, 
                y: Math.random() * this.height, 
                size:6, 
                color:"hsla(360, 90%, 65%, 1)"
            }));
        }
    },
    loop(){
        //每一幀清除畫布,然后再渲染微粒就可以了
        requestAnimationFrame(this.loop.bind(this));
        this.ctx.clearRect(0, 0, this.width, this.height);
        for(var i = 0; i < this.particles.length; i++){
            this.particles[i].render(this.ctx);
        }
    }
}

canvas.init();

如果想要給每個(gè)粒子加上小尾巴的話,那么在每一幀的時(shí)候,就不要清除畫布,而且覆蓋一層有透明度的底色。

//修改loop方法
//this.ctx.clearRect(0, 0, this.width, this.height);
this.ctx.fillStyle = "rgba(0,0,0,0.2)";
this.ctx.fillRect(0, 0, this.width, this.height);

這樣的話會(huì)變成如下效果

最后

在這這篇文章的時(shí)候,并沒有注意太多細(xì)節(jié),比如gap應(yīng)該是可以被設(shè)置的,或者是一個(gè)被特殊標(biāo)注的常量,而不應(yīng)該隨便寫在方法中。對(duì)于本例的代碼,切勿生搬硬套,重要的是要理解原理,以及自己親自動(dòng)手嘗試。

我也是在寫這篇文章的過(guò)程中,才發(fā)現(xiàn)了之前獲取position一個(gè)不精準(zhǔn)的地方。

這里只講了粒子效果最基礎(chǔ)的用法,實(shí)際上還可以做出很多非常炫酷的效果

比如在粒子到達(dá)目的地后還可以抖動(dòng)什么的

粒子形狀、顏色的變化等等。

這個(gè)項(xiàng)目還可以搞很多事情的,大家也可以自己多來(lái)嘗試弄些更加炫酷的效果。

煙花效果可以看一下我的上一篇,程序員的小浪漫----煙火

完整項(xiàng)目

github項(xiàng)目地址

如果覺得還不錯(cuò),請(qǐng)star一個(gè)吧。

參考項(xiàng)目

github上的一個(gè)項(xiàng)目---- shape-shifter

這個(gè)項(xiàng)目我覺得非常不錯(cuò),可惜作者都消失好多年了。

codepen.io 上的一個(gè)作品 ---- Love In Hearts

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/92920.html

相關(guān)文章

  • 序員小浪----煙火

    摘要:多代碼,慎讀預(yù)覽完整項(xiàng)目預(yù)覽預(yù)覽地址屬性設(shè)計(jì)煙花狀態(tài)煙花應(yīng)有三個(gè)狀態(tài)升空等待炸裂炸裂后煙花發(fā)射點(diǎn),爆炸點(diǎn),升空后等待炸裂時(shí)間,炸裂后微粒個(gè)數(shù),煙花半徑煙花炸裂后微粒自身位置,自身大小,自身速度,最大煙花半徑。 多代碼,慎讀!!! 預(yù)覽 showImg(https://segmentfault.com/img/remote/1460000013324854?w=349&h=423); 完...

    roundstones 評(píng)論0 收藏0
  • Canvas 實(shí)現(xiàn)炫麗粒子運(yùn)動(dòng)效果粒子生成文字

    摘要:代碼實(shí)現(xiàn)炫麗的粒子運(yùn)動(dòng)效果云庫(kù)前端散開類型歸位隨機(jī)散開效果對(duì)歸位有效輸入漢字后回車代碼不多,只要是幾個(gè)操作元素??雌饋?lái)運(yùn)行順暢的代碼也或多或少有一些瑕疵,日前這個(gè)效果還只支持中文。 沒有最好,只有更好,如題所示,這篇文章只要是分享一個(gè)用 Canvas 來(lái)實(shí)現(xiàn)的粒子運(yùn)動(dòng)效果。感覺有點(diǎn)標(biāo)題黨了,但換個(gè)角度,勉勉強(qiáng)強(qiáng)算是炫麗吧,雖然色彩上與炫麗無(wú)關(guān),但運(yùn)動(dòng)效果上還是算得上有點(diǎn)點(diǎn)炫的。不管怎么...

    icattlecoder 評(píng)論0 收藏0
  • 《每周一點(diǎn)canvas動(dòng)畫》—— 文字粒子

    摘要:代碼文件每周一點(diǎn)動(dòng)畫系列文章目前已經(jīng)更新了篇,今天給大家發(fā)個(gè)福利。粒子的位置為,我們作為參數(shù)傳入。粒子切換粒子切換的代碼在中,很簡(jiǎn)單,就是綁定了兩個(gè)事件。 代碼文件 每周一點(diǎn)canvas動(dòng)畫系列文章目前已經(jīng)更新了12篇,今天給大家發(fā)個(gè)福利。我們使用canvas來(lái)制作一個(gè)小的效果。這個(gè)小效果是我從codePen上看到的,我對(duì)其做了些修改增強(qiáng),添加了一些新的功能。UI界面就如下圖中看到的樣...

    Riddler 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

xiaodao

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<