iT邦幫忙

2021 iThome 鐵人賽

DAY 21
0
Modern Web

在JS的世界碰碰撞撞乒乒乓乓!30天一起玩Matter.js!系列 第 21

Day21. 伸縮自如的,向量圖像砲 - SVG

昨天聊到小五郎叔叔脖子上的傷痕,今天要來聊日本的國民漫畫航海王,大家有看過航海王的話想必對我們的主角魯夫不陌生,魯夫的絕招就是橡膠果實帶給他的能力,伸縮自如的─橡膠火箭砲!不管拉多長,都維持一樣的解析度,就好像我們今天這篇的主角 - SVG!

今天的Demo
今天的Demo原始碼
https://ithelp.ithome.com.tw/upload/images/20211006/20142057NmbFaaZrLp.png

先前的例子中,物體都是我們自己定義點、從無到有建構,有一個要輸入特別多點的來建構的不知道大家是否還記得 ─ Bodies.fromVertices 這個方法?

不記得的話我們看一下 API 文件 的內容

Matter.Bodies.fromVertices(x, y, vertexSets, [options], [flagInternal=false], [removeCollinear=0.01], [minimumArea=10], [removeDuplicatePoints=0.01])

在建構的部分,我們會透過 vertexSets 來傳入點座標。

為什麼會提到這個呢?

因為我們今天的模組:Svg 會協助我們拿到這個 vertexSets,我們透過這個模組,能把外部圖形直接匯入變成物體。

先和大家簡單介紹一下什麼是 Svg ,Svg 全名為 Scalable Vector Graphic,中文叫做可縮放向量圖形,特性是用向量來建構圖形,來達成圖形可依倍率任意縮放並維持不變的解析度,泛用於 icon 或其他需要可縮放圖形的場合,更多的資料大家可以上網 Google,Svg 在網頁其實也是一門學問。

大略了解 Svg 後我們回帶模組本身,Svg 模組只有一個方法,但是如何透過 Svg 來建構我們的物體其實並不簡單。

唯一一個方法是

Matter.Svg.pathToVertices(path, [sampleLength=15])

輸入一個 path,path是一個 SVGPathElement,sampleLength 預設值為 15,這個值影響的是建構 Svg 圖形的邊的長度,在製作弧形的時候邊用得越多會越貼近弧的效果,也就是長度越短越貼近。

最後這個方法會回傳建構出傳入 path 的點陣列,再將這個點陣列傳入 fromVertices 中對應點集合的參數位置就能創造出對應的物體。

第一個問題是要怎麼匯入 path 這個參數?

筆者會推薦找到一個由 Svg 中 path 類別構成的圖形後把他裝在一個 Svg 容器中,同時為 path 加上 id,外圍容器相對不重要,只要有基本的宣告就好,配合上display : none,來讓它不要顯示,畢竟我們要的只是 targetPath 這個節點。

範例中我們拿 twitter 的 icon 來做示範,廣為人知且有弧型這個特徵。

<svg id="svgTarget" xmlns="http://www.w3.org/2000/svg" style="display: none;">
        <path id="targetPath" d="M302.973,57.388c-4.87,2.16-9.877,3.983-14.993,5.463c6.057-6.85,10.675-14.91,13.494-23.73		c0.632-1.977-0.023-4.141-1.648-5.434c-1.623-1.294-3.878-1.449-5.665-0.39c-10.865,6.444-22.587,11.075-34.878,13.783		c-12.381-12.098-29.197-18.983-46.581-18.983c-36.695,0-66.549,29.853-66.549,66.547c0,2.89,0.183,5.764,0.545,8.598		C101.163,99.244,58.83,76.863,29.76,41.204c-1.036-1.271-2.632-1.956-4.266-1.825c-1.635,0.128-3.104,1.05-3.93,2.467		c-5.896,10.117-9.013,21.688-9.013,33.461c0,16.035,5.725,31.249,15.838,43.137c-3.075-1.065-6.059-2.396-8.907-3.977		c-1.529-0.851-3.395-0.838-4.914,0.033c-1.52,0.871-2.473,2.473-2.513,4.224c-0.007,0.295-0.007,0.59-0.007,0.889		c0,23.935,12.882,45.484,32.577,57.229c-1.692-0.169-3.383-0.414-5.063-0.735c-1.732-0.331-3.513,0.276-4.681,1.597		c-1.17,1.32-1.557,3.16-1.018,4.84c7.29,22.76,26.059,39.501,48.749,44.605c-18.819,11.787-40.34,17.961-62.932,17.961		c-4.714,0-9.455-0.277-14.095-0.826c-2.305-0.274-4.509,1.087-5.294,3.279c-0.785,2.193,0.047,4.638,2.008,5.895		c29.023,18.609,62.582,28.445,97.047,28.445c67.754,0,110.139-31.95,133.764-58.753c29.46-33.421,46.356-77.658,46.356-121.367		c0-1.826-0.028-3.67-0.084-5.508c11.623-8.757,21.63-19.355,29.773-31.536c1.237-1.85,1.103-4.295-0.33-5.998		C307.394,57.037,305.009,56.486,302.973,57.388z"/>
</svg>

再來就是呼叫 Svg 模組的方法,使用 document.getElementById 配合 Id 來拿到 path 節點,並依照精細度需求來給予 sampleLength的值。

因為照顧到弧型顯示, sampleLength 值可以給小一點,可以比對一下範例中左右的圖,左邊的圖 sampleLength 值為 5,右邊的圖 sampleLength 值為 100,會明顯看到弧型的顯示左邊效果好得多。

var vertexSetsA = Svg.pathToVertices(document.getElementById("targetPath"), sampleLength=5);
var vertexsA = Bodies.fromVertices(200, 300, vertexSetsA);

這時候如果什麼都不做,只呼叫這個方法來嘗試建構物體,你會發現,瀏覽器報錯了。
https://ithelp.ithome.com.tw/upload/images/20211006/20142057h5Mu3wFfcu.png
難道我們哪裡做錯了嗎?

不,我們只是少做了一些事情,仔細看 API 文件可以發現他有提醒我們, pathseg.js 對這個方法是必須的。
https://ithelp.ithome.com.tw/upload/images/20211006/20142057HJRmpMXVt3.png
我們用 cdn 來引入這個 library,主要協助我們對 path 上各個節點做段落(segment)式管理,詳細內容我們不走,我們就先引入它。

<script src="https://cdn.jsdelivr.net/npm/pathseg@1.2.0/pathseg.js"></script>

位置要放在引入 matter.js 的地方之上,因為 matter.js 會相依這個 lib。

引入後我們的 twitter icon 就能顯現出來了!
https://ithelp.ithome.com.tw/upload/images/20211006/201420576sLMsjwgV8.png
騙人!這不是肯德基,喔不是,這跟 twitter icon 一點也不像!

沒錯,因為我們還缺了最後一個碎片!

在 Bodies 模組中 fromVertices 的方法裡,下面有提到,當點集合是要表示為一個凹圖形,做圖形分解的時候如果有引入 poly-decomp 的話會讓做圖形分解的時候能處理得更為細緻。
https://ithelp.ithome.com.tw/upload/images/20211006/20142057lmFt3EloQA.png

<script src="https://cdn.jsdelivr.net/npm/poly-decomp@0.2.1/build/decomp.min.js"></script>

我們一樣在引入 matter.js 的地方之上引入這個 lib。

這時候重看畫面:
https://ithelp.ithome.com.tw/upload/images/20211006/20142057dr9sBr3kUQ.png
哇!我們的鳥兒出來了!

透過以上這些步驟,我們就能在 Svg 模組的協助下,以 path element 來組成物體,儘管精度上可能有些差距,但仍是建構物體時一個相當不錯的選項。


上一篇
Day20. 麻痺手錶,小五郎叔叔的噩夢 - Sleeping
下一篇
Day22. 當蘋果掉到牛頓頭上,牛頓被敲醒了 - Gravity
系列文
在JS的世界碰碰撞撞乒乒乓乓!30天一起玩Matter.js!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言