WrapperPlant 植栽包裝器設計文件
概述
使用 SVG Path 渲染植物,L-System 文法生成分支結構,遞迴分支展開做生長動畫。首個植物種類為長草(Grass)。
技術選型
| 面向 | 選擇 | 原因 |
|---|---|---|
| 渲染 | SVG Path | 向量清晰、CSS transform 擺動動畫天然契合、z-index 易控制 |
| 生成演算法 | L-System | 換規則即可切換植物種類,生長動畫天然適合逐代展開 |
| 生長動畫 | 遞迴分支展開 | stroke-dashoffset 逐段描繪,按深度依序觸發 |
| 擺動動畫 | CSS keyframes + rotate | transform-origin 固定根部,不同分支差異化 delay |
元件結構
wrapper-plant/
├── wrapper-plant.vue # 主元件:容器、slot、SVG 層、Intersection Observer
├── use-l-system.ts # L-System 文法解析與迭代
├── use-plant-renderer.ts # 將 L-System 結果轉為 SVG path 資料
├── use-plant-growth.ts # 生長動畫控制(逐段展開 + 時序)
├── plant-presets.ts # 預設植物規則(grass、未來的 ivy、sprout)
├── index.ts # 型別匯出
└── examples/
└── basic-usage.vueL-System 設計
typescript
interface LSystemRule {
axiom: string
ruleMap: Map<string, string>
angle: number
iterations: number
lengthFactor: number
}符號語義:F 前進畫線、+ 左轉、- 右轉、[ 壓入狀態、] 彈出狀態。
SVG 渲染
- L-System 指令轉為一系列 SVG
<path>元素,每段分支一個 path - 每個 path 記錄深度(generation)與繪製順序,用於控制生長動畫先後
- 莖用較粗的 stroke-width,隨深度遞減變細
- 葉片用簡單的橢圓或弧線 path,附加在末端分支
生長動畫
stroke-dasharray+stroke-dashoffset做每段 path 的描繪動畫- 按深度排序:主莖 → 一級分支 → 二級分支 → 葉片,依序觸發
- 每段之間微小延遲,產生遞迴展開視覺效果
- CSS transition 或 anime.js 控制 easing
隨風擺動
- 每個分支 path 設定
transform-origin在根部 - CSS
@keyframes+rotate()正弦波擺動 - 不同分支不同
animation-delay和animation-duration(隨機偏移) - 深層分支擺動幅度略大於主莖
觸發機制
- 預設使用 Intersection Observer,進入視窗後觸發
delayprop 控制進入視窗後延遲多少 ms 才開始生長immediateprop 可切換為掛載即觸發
API 設計
Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
position | 'top' | 'bottom' | 'left' | 'right' | 'bottom' | 植物長出的方位 |
preset | 'grass' | 'grass' | 預設植物種類 |
density | number | 5 | 植物叢數量 |
zIndex | number | -1 | 植物在內容上方或下方 |
delay | number | 0 | 進入視窗後延遲觸發(ms) |
immediate | boolean | false | 掛載即觸發 |
swaying | boolean | true | 啟用隨風擺動 |
growthDuration | number | 2000 | 生長動畫時長(ms) |
Emits
| Event | Payload | 說明 |
|---|---|---|
growth-start | — | 生長動畫開始 |
growth-end | — | 生長動畫結束 |
Expose Methods
| Method | 說明 |
|---|---|
grow() | 手動觸發生長 |
reset() | 重置為未生長狀態 |
Slots
| Slot | 說明 |
|---|---|
default | 被包裝的內容物 |
位置與自動適應
- 元件用
position: relative包裹 slot 內容 - SVG 層用
position: absolute+overflow: visible覆蓋在容器上 - 根據
positionprop 決定 SVG 定位與植物生長方向 useElementBounding()監聽容器大小,動態調整植物分佈範圍