前言:
制作靈感來源於 http://species-in-pieces.com/ 這個網站,此網站作者是來自阿姆斯特丹的設計師 Bryan James,其借用純CSS技術表現出30種瀕危動物的碎片拼圖形象,用轉瞬即逝的動畫來暗示這些動物目前的處境。
首先,所有動物形象都是借助 clip-path 這一 css3 屬性通過各 三角拼接而成,這一屬性不僅可以畫 三角 還可以畫出任意形狀。
為了實現一個這樣的動畫編輯器,工具方面使用了瀏覽器的 Canvas2d 和 localStorage,代碼風格上 大量使用了 fp 風格的代碼。
代碼風格:
一個比較典型的設計如下:
這里 $ 是實現的一個簡易原型,並未引入 jQuery,可以使代碼精簡。
使用這些自定義 getter 函數的目的是來代替所有 純函數 不純的部分,這樣即便整個純函數鏈有不純的部分,也不影響各種功能鏈的正常運行,因為這些 getter 的引用變更不會引發任何錯誤。
實現步驟:
第一步新建一個 html 文件來完成編輯器的功能。
作為一個編輯器,首先要能手動畫三角形,可用一個 canvas 來記錄鼠標點擊處的位置,起到一個提示三角形大概輪廓的效果:
數據方面分別區分兩種單元,圖案 和 三角形,三角形組成圖案,圖案之間可以切換,用 函數+組合 的方式生成一個實例,使其具備功能:
顯然生成的 點數組 getter 都會具備相同的數據結構,因此可以像一個相同類型的變量一樣穿梭於各種外部函數之間。
然后設計下編輯器的 ui 部分,是可拖動可隱藏的還有之前停留位置的記錄功能,可拖動和可隱藏的設計隨便拿一個編輯器比如 ps,unity-editor 這種對功能框都有這種設計,為了更方便使用,我還設計了一個右鍵點擊編輯器空白處可以隱藏編輯器的功能,這樣不用去點一般在右上角很小的關閉按鈕,實際使用起來我個人感覺很流暢。
上面這個函數會讓一個 div 變成可被拖動並在某些時機觸發相應的鈎子;
動畫部分全部是借助 css 實現的,也就是瀏覽器默認的繪圖功能,那作為一個編輯器就要有隨時能准確更新 css 的功能,具體點就是更新 style 標簽里的內容,使它變成 freeStyle:(ps:用來實現 數據 => css代碼 功能函數也必不可少)
代碼層 狀態模式 這種設計也是必須的,因為用戶在使用鼠標點擊的時候 最基本的就可能處在三種情形: 三角形形狀編輯,三角形位置編輯,繪制三角形。
事件綁定方面有經驗的開發會選擇事件派發,簡而言之就是綁在父元素,性能理論上也會好些。
回到 html 部分,為了用最簡潔的方式實現三角形的動畫過渡,這里我使用了 div 復用的設計,說白了一個舞台兩場戲,都是原來那群龍套。
這里就還需要設計一個所有 div 如何按順序開始變換到自己在下一副圖案中位置的問題,這個對最終效果的展示至關重要,后面會展示對比效果。
這里的封裝是為了將這個群演 div 的戲份儲存起來,這樣后面總導演就能安排他們的出場時機。
萬事具備,實現功能就順理成章了,不過肯定有很多細節可以完善和優化的地方。
鑒於我的藝術素養有限,就從臨摹開始來完成動畫圖形,這里開個 nodejs 服務用來將網站截圖存儲本地,去掉跨域限制后畫到瀏覽器里面,然后就可以仿照着臨摹了,臨摹這里有兩個要注意的地方,第一個是疊加的兩個三角形后面的三角形要靠想象力先畫出來,因為暫時沒有新增調整三角間層級的功能,先繪制的三角形層級會比后繪制的高;第二是默認臨摹出的三角形是無法自動獲取被臨摹三角的顏色的,需要點擊 臨摹取色 進入取色狀態,填充點擊在畫板上此位置取到的像素顏色。
特點設計:
局部的編輯器也做了區分,比如雙擊一個三角就可以調出僅 針對 三角形形狀編輯功能和三角形位置編輯功能的 編輯器,而其余的兩個 圖案編輯器 和 臨摹圖案編輯器是顯示出來可以讓用戶點擊的,流程設計大概如下:
臨摹圖案編輯器顯示圖案 => 單擊連點臨摹繪制三角形 => 雙擊三角形可編輯位置和形狀 => 打開圖案編輯器保存圖案
(雙擊三角形調出編輯器即可以用按鈕切換編輯位置和形狀的功能,也可以直接右鍵鼠標實現功能的快速切換)
三角本身的動畫也是在雙擊三角彈出編輯器上通過增減關鍵幀實現(具體就是變更 css 樣式里 keyframe 的幀設置):
最后就是圖案間動畫的切換了,因為前面已經實現了 freeStyle,因而一旦一幅圖的 freeStyle 被切到了另一幅圖的 freeStyle,此時瀏覽器的繪圖引擎在 transition 的影響下就開始自動工作了:
但是由於所有群演是同時開始動作的,就會讓人眼花繚亂看不過來,之前提到封裝每個群演的行為這時候就起作用了,我們可以安排他們一個一個按順序執行,這里其實可以用各種緩動函數來 控制,比如開場緩慢,中場熱烈,收尾迅速,就像原來網站里的動物間切換的律動效果一樣。
這里用一個固定間隔 200 ms 來展示效果,當然這個固定間隔不僅可以提前配置也可以實時更改:
其實到這里除了出場間隔還有一個問題,就是三角形的繪制順序問題。舉個例子,群演 小黑 在劇本A(圖案A)中是在西北角位置,在劇本B(圖案B)中卻被安排到了東南角位置,那么轉場過程中,小黑 就不得不從西北角跑到東南角,這給觀眾帶來的觀影體驗請參照(周星馳在喜劇之王中演死人龍套的場景),小黑 明顯搶戲了。
因此在圖案繪制過程中我都是遵循從右下到左上的繪圖順序,這樣圖案間的過渡就會流暢很多。但顯然這是治標不治本的解決方案,小黑應該遵循就近原則自動補位。
這也是我還沒實現的功能,不過思路也比較清晰,因為所有三角位置都清楚的情況下通過計算調整兩場群演間的映射關系就可以了。還有的問題包括兩個圖案所用三角(群演)數量不匹配的問題,上圖結尾可以發現新的群演是通過天外飛仙的方式登場的,可能需要調整下出場效果。
最后和原網站對比,可以發現編輯器還缺少的一些功能,比如應該可以配置背景圖,可以配置圖案的整體動畫,動物身體下的陰影動畫配置,這些都是可以列計划完成的。