永磁無刷電機(jī)及其驅(qū)動(dòng)技術(shù)
這篇教程將帶您從基礎(chǔ)知識(shí)(在畫布上繪制原始鼠標(biāo)跟隨線),一直到那些和諧畫筆,以及復(fù)雜的曲線和筆觸,從邊緣跨越并卷曲成奇怪美麗的結(jié)構(gòu)。
下面我將介紹不同的刷子代碼實(shí)現(xiàn),以便您可以自己了解如何在畫布上實(shí)現(xiàn)自由繪圖。
當(dāng)然,在繼續(xù)之前,對(duì)HTML5畫布有一定的了解是必要的。
基本
所以讓我們從一個(gè)非?;镜姆椒ㄩ_始。
簡單的鉛筆
我們在畫布上觀察“mousedown”,“mousemove”和“mouseup”事件。
在“mousedown”上,我們將指針移動(dòng)到單擊的坐標(biāo)(ctx.moveTo)。在“mousemove”上,我們畫一條線到鼠標(biāo)的新坐標(biāo)(ctx.lineTo)。最后,在“mouseup”上,我們通過將isDrawingflag 設(shè)置為false來結(jié)束繪圖。
此標(biāo)志用于防止在畫布上移動(dòng)鼠標(biāo)時(shí)進(jìn)行繪制(沒有單擊畫布的情況)。您可以通過在“onmousedown”中分配“onmousemove”事件處理程序(然后在“onmouseup”中刪除它)來避免標(biāo)記,但flag是一個(gè)簡單的解決方案,也可以正常工作。
設(shè)置光滑連接
現(xiàn)在,我們可以通過改變值來控制線的厚度ctx.lineWidth。但是,粗線造成鋸齒狀的邊緣。
這通常發(fā)生在“急轉(zhuǎn)彎”的位置,并且可以通過設(shè)置ctx.lineJoin和ctx.lineCap成"round" 來解決(有關(guān)這些如何影響渲染的示例,請參閱MDN )。
借助陰影使邊緣平滑
現(xiàn)在線條沒有在拐角周圍出現(xiàn)鋸齒。但它們的邊緣也不是很光滑。這是因?yàn)檫@里沒有抗鋸齒化(在canvas上控制抗鋸齒從未如此簡單)。那么我們?nèi)绾涡Х履?
有種方法就是借助陰影使邊緣平滑。
我們添加的內(nèi)容都是ctx.shadowBlur和ctx.shadowColor。邊緣現(xiàn)在肯定更平滑,因?yàn)榫€條被陰影包圍。但還是有一點(diǎn)問題:你會(huì)注意到線條在開始時(shí)比較薄和模糊,但是隨著繪制的內(nèi)容增加逐漸變得更厚更堅(jiān)固。
這是一個(gè)有趣的效果,但也許完全不是我們想要的。那么為什么會(huì)這樣呢?
原來這是由于陰影相互重疊,每增加一個(gè)點(diǎn)都重新stroke了,這樣當(dāng)前筆劃的陰影與前一筆劃的陰影重疊,后者與前一筆劃的陰影重疊,依此類推。陰影越重疊,模糊越少,線越粗。那么我們?nèi)绾谓鉀Q這個(gè)問題呢?
基于點(diǎn)的方法
避免這類問題的一種方法是始終stroke一次。我們可以在一個(gè)數(shù)組中引入一個(gè)容器存儲(chǔ)鼠標(biāo)點(diǎn),并且一次性stroke它們。而不是盲目地在每一次接收到鼠標(biāo)mousemove的時(shí)候都去stroke。
如您所見,它看起來與第一個(gè)示例效果相同?,F(xiàn)在我們可以嘗試在此基礎(chǔ)上添加陰影。注意它在整個(gè)路徑中是如何保持均勻的。
基于點(diǎn)的陰影
邊緣平滑與徑向漸變
另一種平滑的途徑是使用徑向漸變。漸變允許更均勻的顏色分布,不像陰影通常比“平滑”更模糊。
但是,正如您所看到的,stroke使用漸變還有其他問題。請注意我們?nèi)绾卧诿總€(gè)鼠標(biāo)移動(dòng)點(diǎn)上使用圓形漸變填充區(qū)域的。當(dāng)快速移動(dòng)鼠標(biāo)時(shí),我們得到一系列斷開連接的圓,而不是具有光滑邊緣的直線。
解決此問題的一種方法是在兩點(diǎn)間隔距離大時(shí)生成額外的點(diǎn)來填補(bǔ)斷開的空間。
最后這是一條相當(dāng)平滑的曲線!
您可能會(huì)注意到上面示例中的一個(gè)小變化。我們只存儲(chǔ)上一個(gè)點(diǎn),而不是存儲(chǔ)路徑的所有點(diǎn)。我們總是stroke從上一個(gè)點(diǎn)到當(dāng)前的一個(gè)點(diǎn)。
有了上一個(gè)點(diǎn)那我們需要計(jì)算它與當(dāng)前點(diǎn)之間的距離。如果距離太大,我們就在其中填充更多。這種方法的好處是我們不用存儲(chǔ)整個(gè)points陣列,這樣就減少了內(nèi)存的使用!
貝塞爾曲線
我遇到的一個(gè)有趣的概念是使用bezier線而不是直線。這允許自由繪制路徑的曲線更自然更平滑。
這個(gè)想法的實(shí)現(xiàn)是使用quadraticCurveTo來替換straight-line,用兩個(gè)連續(xù)點(diǎn)之間的中間點(diǎn)作為二次貝塞爾曲線控制點(diǎn)。來試試吧:
到現(xiàn)在你已經(jīng)知道:繪圖和平滑曲線的一些基本知識(shí)。從簡單的連線到更復(fù)雜的基于貝塞爾的曲線。讓我們繼續(xù)前進(jìn)發(fā)現(xiàn)更有趣的事情吧。
刷子,毛皮,筆
刷子
現(xiàn)實(shí)的畫筆工具箱中的一個(gè)技巧是簡單地用圖像stroke。我在 blog post by Andrew Trice.遇到了這種技巧。這種想法是使用一小部分圖像作為畫筆去stroke。這開啟了很多可能性。
根據(jù)圖像,我們可以實(shí)現(xiàn)不同的畫筆樣式。在這種情況下,它類似于厚刷。
毛皮(旋轉(zhuǎn)畫布)
跟前面一樣用繪制圖片方式填充路徑,但每次繪制時(shí)生成隨機(jī)的角度值旋轉(zhuǎn)一下畫布。
如果我們這樣做,我們可以得到類似毛皮(或花環(huán))一樣的東西。
筆(變化寬度)
當(dāng)談到模擬鋼筆寫字時(shí),一個(gè)很好的解決方案是簡單地隨機(jī)變化路徑的線寬!我們?nèi)匀皇墙Y(jié)合moveTo+ lineTo的方式,但每次去更改“l(fā)ineWidth”繪制出來的線是什么樣子呢?這是它的外觀:
要記住的一件事是,為了使繪圖看起來真實(shí),隨機(jī)值差別不應(yīng)該太大。
筆2(多線條)
另一模擬鋼筆的實(shí)現(xiàn)是通過多筆觸完成的。我們在點(diǎn)與點(diǎn)之間連線stroke多次,而不是僅僅一次。
但是我們并不是在同一個(gè)坐標(biāo)位置重復(fù)畫線,因?yàn)檫@不會(huì)改變?nèi)魏问虑椤?
相反,我們在原始(圖片上的綠點(diǎn))位置旁邊取幾個(gè)隨機(jī)點(diǎn)(圖片上的藍(lán)點(diǎn)),然后從那里開始。因此,不是一行,而是在原始線旁邊增加了兩天“凌亂”的線條。完美的鋼筆模擬!
厚刷
你可以用這種“多筆觸”技術(shù)做很多事情。我鼓勵(lì)大家嘗試自己的想法。
這里有一個(gè)例子,如果我們增加線條寬度并稍加修正第條線的偏移量,我們可以模擬一個(gè)厚刷子。邊緣上的那些空白點(diǎn)使其看起來很逼真。
“切片”筆觸
多筆觸的方法中如果使用均勻的小點(diǎn)的偏移量,我們可以得到類似于切片的東西。
這一次,不使用圖像。
簡單的方法讓路徑呈現(xiàn)偏斜效果。
帶有透明度的“切片”筆觸
如果我們使用與前面示例中相同的畫筆,并給每次筆觸依次變小的透明度,我們會(huì)得到一個(gè)像這樣的有趣效果。
多行線條
筆直線條用夠了。我們是否可以將相同的技術(shù)應(yīng)用于基于貝塞爾曲線的路徑呢?當(dāng)然。我們只需要在偏離原始點(diǎn)一定距離的位置繪制每條曲線。這就是它的樣子:
帶有透明度的多行線條
我們也可以使用相同的“褪色”技術(shù),讓其中每條線的不透明度依次降低。這使得這些線條看起來更加簡潔優(yōu)雅。
與直筆觸一樣,使用貝塞爾曲線的可能性是無盡的。
印記樣
基本概念
在我們學(xué)會(huì)了如何劃線和曲線后,實(shí)現(xiàn)印章刷不是更簡單!我們所需要的只是在每次鼠標(biāo)移動(dòng)時(shí),在鼠標(biāo)的位置繪制某種形狀。而已。這是一個(gè)用紅色圓圈標(biāo)記的例子。
追蹤效果
您可以看到中間點(diǎn)的相同問題,我們可以使用相同的預(yù)填充技術(shù)解決這些問題。郵票的預(yù)填充往往會(huì)產(chǎn)生非常有趣的線索或管狀效果。您可以通過在最后一個(gè)點(diǎn)和當(dāng)前點(diǎn)之間預(yù)先填充每個(gè)點(diǎn)的間隔來控制管的密度。
隨機(jī)半徑,不透明度
當(dāng)然,我們總是可以調(diào)情,以某種方式改變每個(gè)郵票。例如,第一個(gè)例子中隨機(jī)變化的半徑和不透明度就是這個(gè)。
形狀
當(dāng)涉及到那種郵票時(shí),你可以盡可能地去 - 從我們剛看到的基本形狀(例如圓圈)到由數(shù)百或數(shù)千條曲線組成的更復(fù)雜的路徑。這里唯一的限制因素是性能。這是一個(gè)用簡單的五角星沖壓的例子。
旋轉(zhuǎn)形狀
這是同一顆星,但每次移動(dòng)都會(huì)隨機(jī)旋轉(zhuǎn),以獲得更自然的感覺。
隨機(jī)化一切!
哎呀,讓我們放大一點(diǎn) - 尺寸,角度,不透明度,顏色,厚度!現(xiàn)在不是那么有趣。
彩色像素
我們也不僅限于形狀。一種選擇是直接操縱鼠標(biāo)點(diǎn)周圍的像素。一個(gè)簡單的例子就是隨機(jī)化它們的顏色和位置。
基于圖案的畫筆
現(xiàn)在我們已經(jīng)過了撫摸和沖壓,讓我們來看看一個(gè)完全不同的野獸模式。我們可以使用canvas’隨時(shí)createPattern填充路徑。這會(huì)產(chǎn)生一些非常有趣的效果。我們來看一個(gè)簡單的點(diǎn)圖案。
圓點(diǎn)圖案
注意這里是如何創(chuàng)建模式的。我們將實(shí)例化迷你畫布,在其上繪制圓圈,然后將該畫布用作主畫布上的圖案!我們可能也習(xí)慣使用普通圖像,但使用canvas的美妙之處在于我們可以通過編程方式訪問它,并且無論如何我都可以更改它。這意味著我們可以創(chuàng)建動(dòng)態(tài)模式,例如改變模式中圓的顏色,半徑等。這也意味著我們可以更快更容易地嘗試模式。
線條圖案
根據(jù)前面的示例,您應(yīng)該能夠創(chuàng)建類似的東西。讓我們說一個(gè)水平線條圖案。
雙色線條圖案
…或垂直線條,具有互換的顏色。
彩虹
…甚至是多條不同顏色的線條。一切皆有可能。想想一些模式,并嘗試在迷你畫布上創(chuàng)建它。剩下的就是照顧createPattern和填充路徑。
圖片
最后,這是一個(gè)使用基于圖像的模式與貝塞爾曲線路徑一起使用的示例。這里改變的是我們將圖像對(duì)象傳遞給createPattern(然后將結(jié)果模式分配給strokeStyle)。
噴霧
現(xiàn)在goold-old噴刷怎么樣?我們可以通過幾種方式實(shí)現(xiàn)它。其中之一是用顏色簡單地填充鼠標(biāo)點(diǎn)周圍的區(qū)域(像素)。面積(半徑)越大,噴霧越厚。我們填充的像素越多,它就越密集。
基于時(shí)間的噴霧
您可能會(huì)注意到,之前的方法并不像真正的噴霧那樣。一個(gè)真正的噴漆面積不斷,不只是當(dāng)我們移動(dòng)鼠標(biāo)/刷。為了實(shí)現(xiàn)這一點(diǎn),我們需要在按下鼠標(biāo)時(shí)以恒定間隔繪制區(qū)域。這樣,某些區(qū)域可以通過更長時(shí)間“保持噴霧”而變得更暗。
基于時(shí)間的噴霧,圓形分布
前面的例子更現(xiàn)實(shí),但并不完全如此。真正的噴涂油漆在圓形區(qū)域上,而不是矩形。所以讓我們嘗試在圓形區(qū)域上分布像素。
好多了。
隨機(jī)點(diǎn)
最后,我們還能做些什么來使噴霧更逼真嗎?當(dāng)然,除了使用圖像作為印章。我們當(dāng)然可以使涂料偶爾散布,就像在現(xiàn)實(shí)生活中一樣。如果我們改變每個(gè)繪制像素的不透明度,我們會(huì)得到非常相似的效果。
鄰居點(diǎn)連接
連接鄰居點(diǎn)的概念由zefrank的Scribbler和doob先生的Harmony推廣。如果你還記得Harmony畫筆,如粗略,陰影,鉻色 - 這就是我所說的效果。
這個(gè)想法是:在已經(jīng)繪制的路徑的附近點(diǎn)之間添加額外的筆劃。這通常會(huì)產(chǎn)生草圖,網(wǎng)頁或某種陰影的效果; 額外的筆劃在小的“彎曲”區(qū)域增加了較暗點(diǎn)的錯(cuò)覺。
全點(diǎn)連接
一個(gè)天真的方法是采用我們的第一個(gè)簡單的基于點(diǎn)的畫筆的例子,并添加額外的撫摸。對(duì)于沿路徑的每個(gè)點(diǎn),我們將朝著路徑上的前一個(gè)點(diǎn)沖程:
你可以開始看到類似Harmony畫筆的東西,但它并不完全相同。通過降低額外筆畫的不透明度(即對(duì)比度)可以使其更加逼真和陰影。但要完全重建效果,我們需要遵循不同的算法。
鄰居點(diǎn)
負(fù)責(zé)“附近”撫摸的部分是這樣的:
復(fù)制代碼
1 var lastPoint = points[points.length-1];
2
3 for (var i = 0, len = points.length; i < len; i++) {
4 dx = points[i].x - lastPoint.x;
5 dy = points[i].y - lastPoint.y;
6 d = dx * dx + dy * dy;
7
8 if (d < 1000) {
9 ctx.beginPath();
10 ctx.strokeStyle = ‘rgba(0,0,0,0.3)’;
11 ctx.moveTo(lastPoint.x + (dx * 0.2), lastPoint.y + (dy * 0.2));
12 ctx.lineTo(points[i].x - (dx * 0.2), points[i].y - (dy * 0.2));
13 ctx.stroke();
14 }
15 }
復(fù)制代碼
這里發(fā)生了什么?看起來很瘋狂 我花了一些時(shí)間來理解,但這個(gè)概念非常簡單!
繪制線時(shí),我們檢查已經(jīng)繪制的路徑的整個(gè)距離,將所有點(diǎn)與當(dāng)前(最后一個(gè))點(diǎn)進(jìn)行比較。如果該點(diǎn)在d < 1000最后一個(gè)點(diǎn)的某個(gè)接近度()中,我們移動(dòng)指向它的指針并從那里劃線到當(dāng)前點(diǎn)。dx * 0.2并dy * 0.2給那些額外的筆畫稍微偏移。
而已。簡單的想法,強(qiáng)大的效果。
毛皮通過鄰居點(diǎn)
這種技術(shù)的一個(gè)有趣的轉(zhuǎn)折 - 在和諧中看到 - 是創(chuàng)造皮毛效果。不是向附近點(diǎn)(從最后一點(diǎn))劃動(dòng),而是向相反方向行程。稍微偏移,它會(huì)在某些(近距離)區(qū)域產(chǎn)生毛茸茸的筆觸。
調(diào)查Harmony畫筆后不久,我偶然發(fā)現(xiàn)了Luká?Tvrdy的精彩博客文章,很好地解釋了鄰居點(diǎn)技術(shù)的一些變化。他描述了不同參數(shù)如何影響筆畫及其產(chǎn)生的效果類型。絕對(duì)值得一試。
所以你有它 - 一些基本的以及更有趣的繪圖技術(shù)。我們這里只是劃了一個(gè)表面。有無限的可能性來定制任何一個(gè)畫筆,創(chuàng)造更多令人興奮的效果。改變不透明度或顏色,寬度或偏移,引入隨機(jī)因素,并產(chǎn)生全新的效果。