嗯,相信這對canvas使用較熟的童鞋來說僅僅只是幾十行**就可以搞掂的事情,以下demo就是乙個再也簡單不過的例子了:
它的實現邏輯也很簡單:
我們在canvas畫布上主要監聽了三個事件:mousedown
、mouseup
和mousemove
,同時我們也建立了乙個isdown
變數;
當使用者按下滑鼠(mousedown
,即起筆)時將isdown
置為true
,而放下滑鼠(mouseup
)的時候將它置為false
,這樣做的好處就是可以判斷使用者當前是否處於繪畫狀態;
通過mousemove
事件不斷採集滑鼠經過的座標點,當且僅當isdown
為true
(即處於書寫狀態)時將當前的點通過canvas的lineto
方法與前面的點進行連線、繪製;
通過以上幾個步驟我們就可以實現基本的畫板功能了,然而事情並沒那麼簡單,仔細的童鞋也許會發現乙個很嚴重的問題——通過這種方式畫出來的線條存在鋸齒,不夠平滑,而且你畫得越快,折線感越強。表現如下圖所示:
為什麼會這樣呢?
出現該現象的原因主要是:
要畫出平滑的曲線,其實也是有方法的,lineto
靠不住那我們可以採用canvas的另乙個繪圖api——quadraticcurveto
,它用於繪製二次貝塞爾曲線。
二次貝塞爾曲線
quadraticcurveto(cp1x, cp1y, x, y)
呼叫quadraticcurveto
方法需要四個引數,cp1x
、cp1y
描述的是控制點,而x
、y
則是曲線的終點:
更多詳細的資訊可移步mdn
既然要使用貝塞爾曲線,很顯然我們的資料是不夠用的,要完整描述乙個二次貝塞爾曲線,我們需要:起始點、控制點和終點,這些資料怎麼來呢?
有乙個很巧妙的演算法可以幫助我們獲取這些資訊
獲取二次貝塞爾關鍵點的演算法
這個演算法並不難理解,這裡我直接舉例子吧:
假設我們在一次繪畫中共採集到6個滑鼠座標,分別是a, b, c, d, e, f
;
取前面的a, b, c
三點,計算出b
和c
的中點b1
,以a
為起點,b
為控制點,b1
為終點,利用quadraticcurveto
繪製一條二次貝塞爾曲線線段;
接下來,計算得出c
與d
點的中點c1
,以b1
為起點、c
為控制點、c1
為終點繼續繪製曲線;
依次類推不斷繪製下去,當到最後乙個點f
時,則以d
和e
的中點d1
為起點,以e
為控制點,f
為終點結束貝塞爾曲線。
ok,演算法就是這樣,那我們基於該演算法再對現有**進行一次公升級改造:
let isdown = false在原有的基礎上,我們建立了乙個變數;let points =;
let beginpoint = null
;const canvas = document.queryselector('#canvas');
const ctx = canvas.getcontext('2d');
//設定線條顏色
ctx.strokestyle = 'red';
ctx.linewidth = 1;
ctx.linejoin = 'round';
ctx.linecap = 'round';
canvas.addeventlistener('mousedown', down, false
);canvas.addeventlistener('mousemove', move, false
);canvas.addeventlistener('mouseup', up, false
);canvas.addeventlistener('mouseout', up, false
);function
down(evt) =getpos(evt);
points.push();
beginpoint =;
}function
move(evt) =getpos(evt);
points.push();
if (points.length > 3)
drawline(beginpoint, controlpoint, endpoint);
beginpoint =endpoint;
}}function
up(evt) =getpos(evt);
points.push();
if (points.length > 3)
beginpoint = null
; isdown = false
; points =;
}function
getpos(evt)
}function
drawline(beginpoint, controlpoint, endpoint)
points
用於儲存之前mousemove
事件中滑鼠經過的點,根據該演算法可知要繪製二次貝塞爾曲線起碼需要3個點以上,因此我們只有在points
中的點數大於3時才開始繪製。接下來的處理就跟該演算法一毛一樣了,這裡不再贅述。
**更新後我們的曲線也變得平滑了許多,如下圖所示:
使用一組點畫出平滑的曲線
今天在專案中需要人臉上的點來勾勒出人臉的輪廓,我的想法是將要畫的點存入乙個陣列,使用了uibezierpath來連線每乙個點。但是這樣畫出來的圖是折線,顯得過於生硬。查了若干資料,後來終於在stackoverflow上找到了乙個很好的解決辦法。這個做法的原理其實是在每兩個點之間加入一些點,來使得兩個...
櫻花的季節,教大家用CANVAS畫出飛舞的櫻花樹
又到了櫻花的季節,教大家使用canvas畫出飛舞的櫻花樹效果。廢話少說,先看效果。檢視演示效果 第一步,我們先畫出一棵樹的主體。我畫樹的使用的原理是,定義乙個起始點,從這個點開始,向乙個角度移動一段距離。得到另乙個點。畫出一條線連線兩個點。以新得到的點,依舊向這個角度,移動一段距離。得到第三個點,連...
櫻花的季節,教大家用CANVAS畫出飛舞的櫻花樹
又到了櫻花的季節,教大家使用canvas畫出飛舞的櫻花樹效果。廢話少說,先看效果。檢視演示效果 第一步,我們先畫出一棵樹的主體。我畫樹的使用的原理是,定義乙個起始點,從這個點開始,向乙個角度移動一段距離。得到另乙個點。畫出一條線連線兩個點。以新得到的點,依舊向這個角度,移動一段距離。得到第三個點,連...