你有沒有想過,讓你心愛的品牌 logo 或圖片不只是乖乖躺在頁面上,而是像魔法一樣,飛散、組合,最後化身為獨一無二的動態文字呢?🤩
今天我們來玩點不一樣的,用 Vue.js 搭配 p5.js,打造一個屬於你自己的個性化視覺效果,讓你的網站不再是單純的圖片展示,而是充滿創意、互動和樂趣!
而且不會與別人類似!
這不僅僅是一次技術挑戰,還是一次讓你的設計充滿創意的過程。
準備好展開這趟動態視覺之旅了嗎?
Let's go!🚀
在設計中,我們不再滿足於靜態的圖像展示,互動感和個性化成為提升使用者體驗的關鍵。
品牌設計也是如此,透過動畫和視覺動效,品牌的形象不僅變得更加生動,還能傳達更多情感和信息。
這裡我們的核心概念有三個:
這次我們的目標是使用 Vue.js 和 p5.js,將一張圖片轉換成點陣粒子,並實現點擊畫布後,粒子飛散再重新組合成文字的效果。
接下來,我們會逐步剖析這個實作的每個核心部分,並解釋其設計原因和技術細節。
npm install p5
p5.js
TypeScript 型別定義
npm install @types/p5 --save-dev
這次我們的目標是使用 Vue.js 和 p5.js,將一張圖片轉換成點陣粒子,並實現點擊畫布後,粒子飛散再重新組合成文字的效果。接下來,我們會逐步剖析這個實作的每個核心部分,並解釋其設計原因和技術細節。
在 Vue 的 onMounted
階段,我們利用 p5.js 來初始化畫布並載入圖片,這是整個粒子效果的基礎。
const canvasContainer = ref<HTMLDivElement | null>(null);
onMounted(() => {
const initP5 = () => {
const sketch = (p: p5) => {
p.preload = () => {
img = p.loadImage('https://i.imgur.com/rGmeexe.png');
};
p.setup = () => {
const canvas = p.createCanvas(window.innerWidth, window.innerHeight);
canvas.parent(canvasContainer.value as HTMLDivElement);
img.loadPixels(); // 載入圖片的像素數據
p.noStroke(); // 去除粒子的邊框
const scaleFactor = 0.65;
createParticleDotGrid(p, scaleFactor); // 建立粒子點陣
createTextParticles(p, "Sunny.Cat", 100, p.height / 2); // 建立文字粒子
};
};
new p5(sketch);
};
initP5();
});
canvasContainer
:這個是用來放置 p5.js 畫布的容器。我們使用 Vue 的 ref
來存取 DOM 元素。onMounted
:在 Vue 元件掛載後,我們初始化 p5.js 畫布。使用 p5.js 的 createCanvas
方法來設定畫布大小,並將其掛載到 canvasContainer
中。img.loadPixels()
:這個方法是關鍵,它會讀取圖片的像素數據,使我們能夠操作圖片中的每個像素,並將它們轉換成粒子。我們首先載入圖片並設定畫布,之後將圖片轉換為粒子點陣,並準備生成文字粒子。
我們使用 Particle 類別來表示圖片中的每一個像素粒子。
這些粒子可以在畫布上顯示、隨機飛散,並移動到指定的文字位置。
class Particle {
pos: p5.Vector; // 粒子當前位置
originalPos: p5.Vector; // 粒子原始位置
col: p5.Color; // 粒子的顏色
vel: p5.Vector; // 粒子的速度向量
targetPos: p5.Vector | null = null; // 粒子的目標位置
constructor(x: number, y: number, col: p5.Color) {
this.pos = new p5.Vector().set(x, y); // 粒子位置
this.originalPos = this.pos.copy(); // 保存原始位置
this.col = col; // 粒子的顏色
this.vel = p5.Vector.random2D().mult(5); // 隨機速度,讓粒子可以隨機飛散
}
// 顯示粒子
display(p: p5) {
p.fill(this.col);
p.noStroke();
p.ellipse(this.pos.x, this.pos.y, particleSize, particleSize); // 使用圓形表示粒子
}
// 粒子飛散效果
scatter(p: p5) {
this.pos.add(this.vel); // 根據速度向量更新位置
this.display(p); // 顯示粒子
}
// 移動粒子到目標位置(文字組合)
moveToText(p: p5) {
if (!this.targetPos) {
let randomTarget = p.random(textParticles);
this.targetPos = p.createVector(randomTarget.x, randomTarget.y); // 隨機選擇一個文字粒子的位置作為目標
}
let direction = p5.Vector.sub(this.targetPos, this.pos); // 計算目標位置與當前位置的向量差
this.pos.add(direction.mult(0.2)); // 更新粒子位置,逐漸移向目標
this.display(p);
}
}
Particle
類別:每個粒子都是一個獨立的物件,它擁有位置、顏色、速度等屬性。
這樣的設計方便我們管理和控制每個粒子的行為。
scatter
方法:當使用者點擊畫布時,粒子會根據隨機速度飛散開來,產生隨機運動效果。
moveToText
方法:這是粒子在飛散後的動作,會逐步移動到指定的目標位置(文字的某個字母像素點)。
這個函數將圖片的像素轉換為粒子,每個粒子代表圖片中的一個像素點。
const createParticlesFromImage = (p: p5, offsetX: number, scaleFactor: number, flipHorizontal: boolean) => {
for (let y = 0; y < img.height; y += particleSize * 1.5) {
for (let x = 0; x < img.width; x += particleSize * 1.5) {
const index = (x + y * img.width) * 4;
const r = img.pixels[index];
const g = img.pixels[index + 1];
const b = img.pixels[index + 2];
let posX = flipHorizontal ? img.width - x : x;
posX = posX * scaleFactor + offsetX; // 調整水平位置
const posY = y * scaleFactor; // 調整垂直位置
const particle = new Particle(posX, posY, p.color(r, g, b));
particles.push(particle); // 將粒子存入 particles 數組
}
}
};
scaleFactor
對圖片進行縮放,並根據 flipHorizontal
決定是否翻轉粒子的水平位置,使粒子排列更加豐富。particles
數組,這些粒子將在畫布上展示。這裡我們創建文字粒子,將它們作為粒子飛散後重新排列的目標位置。
const createTextParticles = (p: p5, text: string, _x: number, y: number) => {
const textCanvas = p.createGraphics(p.width, p.height); // 使用 p5.js 創建一個隱藏的畫布來生成文字
textCanvas.pixelDensity(1);
textCanvas.background(255);
textCanvas.textAlign(p.CENTER, p.CENTER);
textCanvas.fill(0);
textCanvas.textSize(100);
textCanvas.text(text, p.width / 2, y); // 在隱藏的畫布上繪製文字
textCanvas.loadPixels();
for (let i = 0; i < textCanvas.width; i += particleSize) {
for (let j = 0; j < textCanvas.height; j += particleSize) {
const index = (i + j * textCanvas.width) * 4;
const r = textCanvas.pixels[index];
if (r < 128) { // 找出黑色部分(即文字部分)的像素點
textParticles.push({ x: i, y: j }); // 將文字的像素點記錄為粒子的目標位置
}
}
}
};
createGraphics
:我們使用隱藏的 p5.Graphics
來繪製文字,不會在實際畫布上顯示,只用來捕捉文字的像素點。loadPixels
:這個方法會讀取文字圖像的像素數據,我們只保留文字的黑色部分,並將其作為粒子的目標位置。當使用者點擊畫布時,粒子會先飛散,隨後逐漸移動並組成文字。
p.mousePressed = () => {
if (!
isScattered && !isFormingText) {
isScattered = true;
setTimeout(() => {
isScattered = false;
isFormingText = true;
}, 2000);
}
};
mousePressed
:當使用者點擊畫布時,觸發粒子飛散效果,並在 2 秒後開始組成文字。isScattered
與 isFormingText
:這兩個變數控制著粒子的狀態,確保粒子在不同階段有不同的動作。如何將圖片轉換為粒子效果:學會使用 p5.js 的 loadPixels
方法將圖片的像素轉化為粒子,並以點陣形式呈現在畫布上,實現圖像粒子化的效果。
粒子飛散與重新組合的動畫:通過使用隨機速度讓粒子隨機飛散,並且在飛散後逐漸移動到指定的文字位置,實現動畫效果,提升網頁的互動性和趣味性。
結合 Vue.js 與 p5.js 進行互動設計:透過 Vue.js 的元件化設計與 p5.js 的動畫功能,學會如何將畫布動畫與網頁結合,並且實現點擊觸發的互動動畫設計。
這三個重點可以幫助讀者掌握粒子動畫的製作流程,並靈活運用於不同的網頁設計中。
通過這次的實作,我們成功讓靜態圖片「活」了起來,變成了會飛散、會組合的點陣粒子動畫!
這不僅讓網站變得更有趣、更有吸引力,也為個性化展示打開了一扇創意的大門。
是不是覺得自己也能做出一個酷炫的專屬動畫呢?😉
無論是要為自己的作品加點魔法,還是想讓網頁充滿驚喜,只要勇敢嘗試,創意無限!
相信你在不斷挑戰自我的過程中,也會發現更多靈感和可能性!
加油吧,讓你的技術和創意一起翱翔!🚀🌟