一個有趣的例子帶你入門canvas

今天,我們前端群問了一個這樣的問題,然后就開始了激烈的討論。
那么下面咱們一起來看看這個問題,這個問題問了兩個小問題:
1.如何在 canvas 上繪制多邊形?
2.鼠標(biāo)怎么選中繪制的某一個圖形?
那么咱們就來分為兩個問題解答。
繪制多邊形
????要繪制一個多邊形,多邊形圖形的基本元素是路徑。路徑是通過不同顏色和寬度的線段或曲線相連形成的不同形狀的點的集合。一個路徑,甚至一個子路徑,都是閉合的。使用路徑繪制圖形需要一些額外的步驟。
首先,你需要創(chuàng)建路徑起始點
然后你使用畫圖命令去畫出路徑。
之后你把路徑封閉
一旦路徑生成,你就能通過描邊或填充路徑區(qū)域來渲染圖形。以上這些步驟會用到一些 API:
beginPath()
新建一條路徑,生成之后,圖形繪制命令被指向到路徑上生成路徑。
closePath()
閉合路徑之后圖形繪制命令又重新指向到上下文中。
stroke()
通過線條來繪制圖形輪廓。
fill()
通過填充路徑的內(nèi)容區(qū)域生成實心的圖形。
詳解繪制過程
這里詳細(xì)解答一下繪制的過程:
第一步,生成路徑,調(diào)用 beginPath,本質(zhì)上路徑是有很多子路徑所構(gòu)成的,這些子路徑全部在一個列表里面,所有的子路徑(線、弧)構(gòu)成圖形。而每次調(diào)用這個方法之后,列表都會被重置,然后就可以繪制新的圖形。(你需要在設(shè)置路徑之后指定你的起始位置);
第二步,調(diào)用指定函數(shù)繪制路徑;
第三步,閉合路徑 closePath(不是必須的);
筆式繪圖儀模型
繪制一個三角形例子:
var ctx = canvas.getContext("2d");
ctx.beginPath(); //開始路徑
ctx.moveTo(75, 50); //指定起始位置
ctx.lineTo(100, 75); //繪制到這個位置的一條線
ctx.lineTo(100, 25); //繪制到這個位置的一條線
ctx.fill(); //填充圖形,默認(rèn)就制動結(jié)束路徑了
????在這個過程中,有一個比較有用的函數(shù),moveTo,這個函數(shù)實際上畫不出來任何東西,它是屬于上面描述的路徑列表的一部分。
????看下這個函數(shù)的作用:
moveTo()
將筆觸移動到指定的坐標(biāo) x 以及 y 上。
????當(dāng) canvas 初始化或者 beginPath()調(diào)用后,你通常會使用 moveTo()函數(shù)設(shè)置起點。我們也能夠使用 moveTo()繪制一些不連續(xù)的路徑。
????這個時候你可以想象一下在紙上畫東西,筆尖從一個點到另一個點的移動過程。這個過程的模式叫做筆式繪圖儀模式。所以 canvas 2d 繪圖的模式也就是這種模式。
????現(xiàn)在繪制多邊形就沒有什么問題了。
canvas 上找出指定的圖形
????首先,完成描述一下這個問題:按下鼠標(biāo),如何判斷出選中了某一個圖形?
比如下圖:?

????鼠標(biāo)點擊了這個不規(guī)則多邊形的內(nèi)部,怎么判斷?
????第一反應(yīng)就是 isPointInPath,或者是迭代所有圖形,拿鼠標(biāo)的點去與圖形的點碰撞檢測,這個方法可以用,但是適用場景比較少,還有就是性能開銷比較大,如果圖形太多,每一個都需要經(jīng)過計算,那么這個交互會變得非常的不友好。
????有沒有其他方案了,在游戲界有一個普遍使用的方案——包圍盒,什么是包圍盒呢?我們以上面的圖形舉例,外面畫的紅線框就是這個多邊形的包圍盒。
????很形象的一個例,就是公司發(fā)的月餅盒子,就是里面圓圓的月餅 ? 的包圍盒。
????包圍盒的方案有個缺點,選取的范圍比較粗。比如上圖的紅框,框選了不是多邊形部分的內(nèi)容。如果你想用包圍盒的方案來做,那就要分的足夠細(xì),比如下圖:?

????分出來了多個包圍盒,這種情況在圖形特別復(fù)雜的時候,包圍盒這個方案就有點粗糙了。
????還有下圖這種,實心和空心圓,用包圍盒也就非常的不友好。?

?那怎么辦?
方案
????如果想要快速選中某一個圖形,我們能不能對我們的每一個圖形有一個對應(yīng)的 hash,而在鼠標(biāo)點擊的時候,又能夠取到這個 hash。用 hash 的值,去找這個圖形,這個過程的時間復(fù)雜度是 O(1)。
比如在畫布的這些圖形:?

在另一張一模一樣的畫布上,畫了這些圖形?

上層畫布(顯示出來的)是正常的圖形,但是每個圖形分配一個 rgb 色值。
下層畫布(隱藏)用這個 rgb 色值做填充或者 stroke。
當(dāng)鼠標(biāo)點擊的時候,在隱藏畫布相同的位置,取一個像素點。
而這個像素點的rgb值就是我們要找的 hash。
至此,兩個問題已經(jīng)解答了。
近期,我發(fā)現(xiàn)我的前端群里有不少人開始研究前端圖形學(xué)方向,前端圖形學(xué)和前端架構(gòu)師是現(xiàn)在前端兩大重點方向,而前端圖形學(xué)就是一個很獨特的前端方向,要求的技能跟其他方向都不一樣,動畫、數(shù)據(jù)可視化、游戲都是它的領(lǐng)域。市場有很大的需求,在各大招聘網(wǎng)站也可以看出來薪資非常高,而當(dāng)前市場人才緊缺。
之前京程一燈推出了業(yè)內(nèi)唯一的前端圖形學(xué)教程(第一季),由淺入深,從基礎(chǔ)數(shù)學(xué)知識開始,涉及2D和3D的方方面面,幫助大家快速掌握圖形學(xué)的關(guān)鍵知識點和編程技巧。
現(xiàn)在他們新上線第二季圖形學(xué)教程,特別新增H5游戲開發(fā)實戰(zhàn),全面升級,目標(biāo)是用最短的時間帶你走進前端圖形學(xué)工程師的世界。
關(guān)注【前端宇宙】的你有特別福利:報名第二季贈送第一季教程。
掃描下圖中的二維碼,
領(lǐng)取免單卡,僅需0.02元。
???
