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/[email protected]/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/[email protected]/build/decomp.min.js"></script>

我们一样在引入 matter.js 的地方之上引入这个 lib。

这时候重看画面:
https://ithelp.ithome.com.tw/upload/images/20211006/20142057dr9sBr3kUQ.png
哇!我们的鸟儿出来了!

透过以上这些步骤,我们就能在 Svg 模组的协助下,以 path element 来组成物体,尽管精度上可能有些差距,但仍是建构物体时一个相当不错的选项。


<<:  [区块链&DAPP介绍 Day28] Dapp 实战 留言版 - 2

>>:  Rust-并行&并发(二)

CIA-资安的目标

在Wentz Wu网站上说明,CIA是美国法定目标(PUBLIC LAW 107–347—DEC. ...

Day.17 「如果基本型别是商品,那物件型别就是购物袋」 —— JavaScript 物件型别

前面有介绍了基本型别,基本型别有 string、number、boolean、null、undef...

Day20 AR抬头显示器(HUD)与一般的差异 你是5岁就抬头还是3岁才抬头的呢?

这期要介绍抬头显示器(HUD)的一些功能和种类,让我们马上开始。 抬头显示器可用於汽车上。它将讯息投...

Day 8:506. Relative Ranks

今日题目 题目连结:506. Relative Ranks 题目主题:Array, Sorting,...

久坐是门学问 - 人因工程

来到了办公桌座位,打开电脑萤幕,拿起滑鼠准备查阅未开封的信件,开始一天的早晨。这一整段过程看似简单,...