用Canvas制作简单的画图工具
今天用Canvas制作了一個畫圖工具,非常簡單,功能也不是很多,主要有背景網格,畫線,畫圓,畫矩形和畫圓角矩形,也用到了canvas的一些基本知識,在這里一一列舉。
線段的繪制
如何繪制真正的1像素的線段?
如果在像素邊界處繪制一條1像素寬的垂直線段,那么canvas的繪圖環境對象會試著將半個像素畫在邊界中線的右邊,將另外半個像素畫在邊界中線的左邊。然而,在一個整像素的范圍內繪制半個像素寬的線段是不可能的,,所以左右兩個方向上的半像素都被擴展為1像素。如圖所示
本來我們想要將線段繪制在深灰色的區域內,但實際上瀏覽器卻將其延伸繪制到整個灰色的范圍內。
如果我們將線段繪制在兩個像素之間的那個像素中,這時出現的效果便成了下面圖片展示的效果:
這是因為當線段繪制在兩個像素之間,中間左右兩端的那半個像素就不會再延伸了,它們合起來恰好占據了一個像素的寬度。
所以,如果要繪制一條真正的1像素寬的線段,必須將該線段繪制在某兩個像素之間的那個像素中。
在繪制背景網格中,繪制的線段寬度為0.5像素的,這是因為所有瀏覽器的Canvas都實現了“抗鋸齒”技術,能呈現出“亞像素”線段的繪制效果來。
背景網格的繪制代碼如下:
1 function drawGrid(color,stepx,stepy){
2 context.save();
3 context.strokeStyle = color;
4 context.lineWidth = 0.5;
5
6 for(var i = stepx + 0.5; i<context.canvas.width; i += stepx){
7 context.beginPath();
8 context.moveTo(i,0);
9 context.lineTo(i,context.canvas.height);
10 context.stroke();
11 }
12 for(var i = stepy + 0.5;i<context.canvas.height; i += stepy){
13 context.beginPath();
14 context.moveTo(0,i);
15 context.lineTo(context.canvas.width,i);
16 context.stroke();
17 }
18 context.restore();
19 }
drawGrid
坐標轉換
畫圖的一個基本轉換為將鼠標坐標轉換為Canvas坐標。因為瀏覽器通過事件對象傳遞給監聽器的鼠標坐標是窗口坐標,而不是相對于canvas的自身坐標,所以需要轉換。
轉換的代碼如下:
1 function windowToCanvas(x,y){
2 var bbox = canvas.getBoundingClientRect();
3 return {
4 x:x-bbox.left*(canvas.width / bbox.width),
5 y:y-bbox.top*(canvas.height / bbox.height)
6 };
7 }
windowToCanvas
監聽事件
因為繪制圖畫是通過監聽鼠標事件進行的,該程序用了canvas.onmousedown,canvas.onmousemove和canvas.onmouseup事件進行繪制的。
當mousedown時,記錄x坐標和y坐標,設置畫圖標簽dragging為True,并保存當前畫布上所繪制的內容。
保存當前畫布上的內容的函數如下:
1 function saveDrawingSurface(){
2 // getImageData() 復制畫布上指定矩形的像素數據
3 drawingSurfaceImageData = context.getImageData(0,0,canvas.width,canvas.height);
4 }
saveDrawingSurface
當mousemove時,記錄x坐標和y坐標,恢復在mousedown時保存的畫布內容,并在此基礎上繪制新的圖案。
恢復畫布上的內容的函數如下:
1 function restoreDrawingSurface(){
2 //通過 putImageData() 將圖像數據放回畫布
3 context.putImageData(drawingSurfaceImageData,0,0);
4 }
restoreDrawingSurface
當mouseup時,記錄x坐標和y坐標,恢復在mousedown時保存的畫布內容,并在此基礎上繪制新的圖案,最后將畫圖標簽dragging設置為False。
畫圖
下面重點講解一下畫圓和畫圓形矩形的方法。
先說畫圓,畫圓需要知道圓心和半徑。首先利用反三角函數圓心和當前鼠標位置之間連線與X軸的夾角,然后用輔助矩陣的高度除以這個夾角的正弦值,來得出最終所畫圓形的半徑。
代碼如下:
1 function drawRubberbandShapeCircle(loc){
2 var angle,
3 radius;
4 if(mousedown.y === loc.y){
5 radius = Math.abs(loc.x - mousedown.x);
6 }else{
7 angle = Math.atan(rubberbandRect.height/rubberbandRect.width);
8 radius = rubberbandRect.height / Math.sin(angle);
9 }
10 context.beginPath();
11 context.arc(mousedown.x,mousedown.y,radius,0,Math.PI*2,false);
12 context.stroke();
13 }
drawRubberbandShapeCircle
畫圓形矩形用的方法是arcTo(x1,y1,x2,y2.radius),arcTo方法的參數分別代表兩個點以及圓形的半徑該方法以指定的半徑來繪制一條圓弧,此圓弧與當前點到第一個點(x1,y1)的連線相切,而且與第一個點到第二個點(x2,y2)的連線也相切。
那么如何通過arcTo繪制出矩形呢?因為arcTo()方法繪制的可能不僅僅是一段圓弧,如果在當前路徑中有子路徑的話,那么瀏覽器會將子路徑的終點與圓弧的起點用線段連起來。
在某一時刻,canvas之中只能有一條路徑存在,Canvas規范將其稱為“當前路徑”。然而這條路徑卻包含許多子路徑,而子路徑,又是由兩個或更多的點組成的。beginPath()方法會將當前路徑中的所有子路徑都清楚掉。
圓形矩陣的代碼如下:
1 function roundedRect(cornerX,cornerY,width,height,cornerRadius){
2 context.moveTo(cornerX + cornerRadius, cornerY);
3 context.arcTo(cornerX + width, cornerY,cornerX + width,cornerY + height,cornerRadius);
4 context.arcTo(cornerX + width, cornerY + height,cornerX,cornerY + height,cornerRadius);
5 context.arcTo(cornerX, cornerY + height,cornerX,cornerY,cornerRadius);
6 context.arcTo(cornerX, cornerY,cornerX + cornerRadius,cornerY,cornerRadius);
7 context.stroke();
8 }
roundedRect
至此,畫圖工具就已經可以用了。
源碼地址:git@github.com:weiruifeng/paint.git
總結
以上是生活随笔為你收集整理的用Canvas制作简单的画图工具的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Vue中实现菜单下拉、收起的动画效果
- 下一篇: 5 个常用的软件质量指标