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

資訊專欄INFORMATION COLUMN

炫酷粒子表白,雙十一脫單靠它了!

lauren_liuling / 3051人閱讀

摘要:雙十一光棍節又要來臨了,每年這個時候都是本人最苦悶的時刻。能不能再給力一點說好的粒子系統,現在只是簡單的畫了一點。

? 雙十一光棍節又要來臨了,每年這個時候都是本人最苦悶的時刻。日漸消瘦的錢包,愈發干涸的雙手,雖然變強了,頭卻變涼了。今年一定要搞點事情!

? 最近聽女神說想談戀愛了,?(? ? ?) 嘿嘿,一定不能放過這個機會,給她來個不一樣的表白。

作為整天搞可視化的前端攻城獅,最先想到的就是常玩的各種粒子。那么咱們就一起來把這個粒子系統玩出花來吧。
演示地址

用粒子組成文字

首先,咱們想下要如何將一系列的粒子組成一句表白呢?

實現原理其實很簡單,Canvas 中有個 getImageData 的方法,可以得到一個矩形范圍所有像素點數據。那么我們就試試來獲取一個文字的形狀吧。

第一步,用 measureText 的方法來計算出文字適當的尺寸和位置。

// 創建一個跟畫布等比例的 canvas
const width = 100;
const height = ~~(width * this.height / this.width); // this.width , this.height 說整個畫布的尺寸
const offscreenCanvas = document.createElement("canvas");
const offscreenCanvasCtx = offscreenCanvas.getContext("2d");
offscreenCanvas.setAttribute("width", width);
offscreenCanvas.setAttribute("height", height);

// 在這離屏 canvas 中將我們想要的文字 textAll 繪制出來后,再計算它合適的尺寸
offscreenCanvasCtx.fillStyle = "#000";
offscreenCanvasCtx.font = "bold 10px Arial";
const measure = offscreenCanvasCtx.measureText(textAll); // 測量文字,用來獲取寬度
const size = 0.8;
// 寬高分別達到屏幕0.8時的size
const fSize = Math.min(height * size * 10 / lineHeight, width * size * 10 / measure.width);  // 10像素字體行高 lineHeight=7 magic
offscreenCanvasCtx.font = `bold ${fSize}px Arial`;

// 根據計算后的字體大小,在將文字擺放到適合的位置,文字的坐標起始位置在左下方
const measureResize = offscreenCanvasCtx.measureText(textAll);
// 文字起始位置在左下方
let left = (width - measureResize.width) / 2;
const bottom = (height + fSize / 10 * lineHeight) / 2;
offscreenCanvasCtx.fillText(textAll, left, bottom);

咱們可以 appendChild 到 body 里看眼

好的。同學們注意,我要開始變形了 [推眼鏡] 。

getImageData 獲取的像素數據是一個 Uint8ClampedArray (值是 0 - 255 的數組),4 個數一組分別對應一個像素點的 R G B A 值。我們只需要判斷 i * 4 + 3 不為 0 就可以得到需要的字體形狀數據了。

// texts 所有的單詞分別獲取 data ,上文的 textAll 是 texts 加一起
Object.values(texts).forEach(item => {
    offscreenCanvasCtx.clearRect(0, 0, width, height);
    offscreenCanvasCtx.fillText(item.text, left, bottom);
    left += offscreenCanvasCtx.measureText(item.text).width;
    const data = offscreenCanvasCtx.getImageData(0, 0, width, height);
    const points = [];
    // 判斷第 i * 4 + 3 位是否為0,獲得相對的 x,y 坐標(使用時需乘畫布的實際長寬, y 坐標也需要取反向)
    for (let i = 0, max = data.width * data.height; i < max; i++) {
        if (data.data[i * 4 + 3]) {
            points.push({
                x: (i % data.width) / data.width,
                y: (i / data.width) / data.height
            });
        }
    }
    // 保存到一個對象,用于后面的繪制
    geometry.push({
        color: item.hsla,
        points
    });
})
制定場景,繪制圖形

文字圖形的獲取方式以及搞定了,那么咱們就可以把內容整體輸出了。咱們定義一個簡單的腳本格式。

// hsla 格式方便以后做色彩變化的擴展
const color1 = {h:197,s:"100%",l:"50%",a:"80%"};
const color2 = {h:197,s:"100%",l:"50%",a:"80%"};
// lifeTime 禎數
const Actions = [
    {lifeTime:60,text:[{text:3,hsla:color1}]},
    {lifeTime:60,text:[{text:2,hsla:color1}]},
    {lifeTime:60,text:[{text:1,hsla:color1}]},
    {lifeTime:120,text:[
        {text:"I",hsla:color1},
        {text:"??",hsla:color2},
        {text:"Y",hsla:color1},
        {text:"O",hsla:color1},
        {text:"U",hsla:color1}
    ]},
];

根據預設的腳本解析出每個場景的圖形,加一個 tick 判斷是否到了 lifeTime 切換到下一個圖形重新繪制圖形。

function draw() {
    this.tick++;
    if (this.tick >= this.actions[this.actionIndex].lifeTime) {
        this.nextAction();
    }
    this.clear();
    this.renderParticles(); // 繪制點
    this.raf = requestAnimationFrame(this.draw);
}

function nextAction() {
    ....//切換場景 balabala..
    this.setParticle(); // 隨機將點設置到之前得到的 action.geometry.points 上
}

這樣咱們基本的功能已經完成了。

能不能再給力一點

說好的粒子系統,現在只是 context.arc 簡單的畫了一點。那咱們就來加個粒子系統吧。

class PARTICLE {
    // x,y,z 為當前的坐標,vx,vy,vz 則是3個方向的速度
    constructor(center) {
        this.center = center;
        this.x = 0;
        this.y = 0;
        this.z = 0;
        this.vx = 0;
        this.vy = 0;
        this.vz = 0;
    }
    // 設置這些粒子需要運動到的終點(下一個位置)
    setAxis(axis) {
        this.nextX = axis.x;
        this.nextY = axis.y;
        this.nextZ = axis.z;
        this.color = axis.color;
    }
    step() {
        // 彈力模型 距離目標越遠速度越快
        this.vx += (this.nextX - this.x) * SPRING;
        this.vy += (this.nextY - this.y) * SPRING;
        this.vz += (this.nextZ - this.z) * SPRING;
        // 摩擦系數 讓粒子可以趨向穩定
        this.vx *= FRICTION;
        this.vy *= FRICTION;
        this.vz *= FRICTION;
        
        this.x += this.vx;
        this.y += this.vy;
        this.z += this.vz;
    }
    getAxis2D() {
        this.step();
        // 3D 坐標下的 2D 偏移,暫且只考慮位置,不考慮大小變化
        const scale = FOCUS_POSITION / (FOCUS_POSITION + this.z);
        return {
            x: this.center.x + (this.x * scale),
            y: this.center.y - (this.y * scale),
        };
    }
}

大功告成!

既然是 3D 的粒子,其實這上面還有不是文章可做,同學們可以發揮想象力來點更酷炫的。

還有什么好玩的

上面是將粒子擺成文字。那咱們當然也可以直接寫公式擺出個造型。

// Actions 中用 func 代替 texts
{
    lifeTime: 100,
    func: (radius) => {
        const i = Math.random() * 1200;
        let x = (i - 1200 / 2) / 300;
        let y = Math.sqrt(Math.abs(x)) - Math.sqrt(Math.cos(x)) * Math.cos(30 * x);
        return {
            x: x * radius / 2,
            y: y * radius / 2,
            z: ~~(Math.random() * 30),
            color: color3
        };
    }
}

再把剛才文字轉換形狀的方法用一下

{
    lifeTime: Infinity,
        func: (width, height) => {
            if(!points.length){
                const img = document.getElementById("tulip");
                const offscreenCanvas = document.createElement("canvas");
                const offscreenCanvasCtx = offscreenCanvas.getContext("2d");
                const imgWidth = 200;
                const imgHeight = 200;
                offscreenCanvas.setAttribute("width", imgWidth);
                offscreenCanvas.setAttribute("height", imgHeight);
                offscreenCanvasCtx.drawImage(img, 0, 0, imgWidth, imgHeight);
                let imgData = offscreenCanvasCtx.getImageData(0, 0, imgWidth, imgHeight);
                for (let i = 0, max = imgData.width * imgData.height; i < max; i++) {
                    if (imgData.data[i * 4 + 3]) {
                        points.push({
                            x: (i % imgData.width) / imgData.width,
                            y: (i / imgData.width) / imgData.height
                        });
                    }
                }
            }

            const p = points[~~(Math.random() * points.length)]
            const radius = Math.min(width * 0.8, height * 0.8);
            return {
                x: p.x * radius - radius / 2,
                y: (1 - p.y) * radius - radius / 2,
                z: ~~(Math.random() * 30),
                color: color3
            };
        }
}

?完美

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98999.html

相關文章

  • 炫酷粒子表白 | 聽說女神都想談戀愛了!

    摘要:最近聽女神說想談戀愛了,嘿嘿,一定不能放過這個機會,給她來個不一樣的表白。我們只需要判斷不為就可以得到需要的字體形狀數據了。能不能再給力一點說好的粒子系統,現在只是簡單的畫了一點。還有什么好玩的上面是將粒子擺成文字。 showImg(https://segmentfault.com/img/bVbkTGb?w=900&h=383); 最近聽女神說想談戀愛了,?(? ? ?) 嘿嘿,一定...

    venmos 評論0 收藏0
  • [ JS基礎 ] JS基礎不好!只能靠它了! (1)

    摘要:長度則輸出原始值。好,我很菜,這是我寫的雖然能夠實現,但怎么看都覺得菜成狗當然這也是一種方案。附上一些鏈接上面的奇葩問題和回答一上面的奇葩問題和回答二 Duang!Duang!Duang! 我不是干貨,我是干糧! 推薦個好東西給大家,一個網站:codewars 這網站是干什么的呢? 1.賺錢的(當然不是我們的)! 2.通過做一些編程題可以大大提高你的 Javascript...

    macg0406 評論0 收藏0
  • JParticles 2.0 發布,打造炫酷粒子特效

    摘要:我們一貫的理念我們我笑哭一貫的理念是信仰和。第一點視差粒子幾行代碼為了看起來更簡潔,定義視差粒子層數的屬性就省略了,因為本身它就是層,也挺好的。演示四層,為了讓大家能更了解屬性的使用方法。又高大上,又可以緩解加載的等待心情。 JParticles 2.0 發布,打造炫酷的粒子特效。不好意思哈,在這么繁花似錦的世界里,標題不得不取得吸引眼球一點哈,不然...還是不啰嗦了,我們進入正題吧s...

    tinna 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<