最近筆者在學習HTML5的新元素<canvas>
,會分享一些基礎知識以及小例子,最終使用<canvas>
實現一個繪製簡單圖表(條形圖、線圖或者餅圖)的js庫,會更新一到兩篇文章~
下面咱們開始吧~css
咱們首先應該指定<canvas>
標籤即畫布的寬度和高度屬性,並在開始和閉合標籤之間添加後備信息:html
<html> <head> <meta charset="utf-8"> </head> <body> <canvas id="canvas" width="500" height="500">Canvas is not supported.</canvas> </body> </html>
調用canvas
的getContext()
方法,這個方法接收一個參數,即上下文的名字:前端
var canvas = document.getElementById("canvas"); if(canvas.getContext) { var context = canvas.getContext("2d") }
上述例子中,咱們在調用getContext()
方法時,首先檢測其是否存在,這是因爲有的瀏覽器遇到HTML規範以外的標籤時,也會建立一個DOM對象,好比咱們在Chrome中嘗試如下代碼:html5
<ppp id="ppp"></ppp>
document.getElementById("ppp"); //<ppp id="ppp"></ppp>
所以即便當前瀏覽器不能兼容HTML規範中的canvas元素,一樣會建立DOM對象,可其中卻不存在getContext()
。context
上下文對象中包含了繪圖須要的一系列屬性和方法,你們在閱讀本文時,記得區分屬性和方法,改變屬性會影響到後續的繪圖效果,而調用方法每每是一次性的。git
2D上下文的座標默認開始於左上角,原點座標爲(0, 0),使用translate(x, y)
能夠更改座標原點。github
填充,就是用指定的樣式,好比顏色、漸變或圖像填充指定區域,對應的上下文屬性爲fillStyle
,默認值爲#000000
, 好比:canvas
context.fillStyle = "orange";
描邊就是在指定區域邊緣畫指定樣式的線,好比:瀏覽器
context.strokeStyle = "grey";
矩形是惟一一個能夠在2D上下文中直接話的形狀,其餘的都須要繪製路徑,可使用3個方法直接繪製矩形。ide
能夠繪製一個由fillStyle
指定填充樣式的矩形,好比:工具
context.translate(100, 100) context.fillStyle = "#99cccc"; context.fillRect(-100, -50, 200, 100); context.fillStyle="#3399cc"; context.fillRect(-60, -30, 120, 60);
能夠繪製一個由strokeStyle
lineWidth
lineCap
lineJoin
等屬性指定描邊樣式的矩形,好比:
context.strokeStyle = "#99cccc"; context.lineWidth = "50"; context.lineJoin = "bevel"; context.strokeRect(0, 0, 400, 200);
屬性名 | 含義 | 取值 |
---|---|---|
lineCap | 線條末端的形狀 | butt 平頭round 圓頭square 方頭 |
lineWidth | 線條寬度 | 整數 |
lineJoin | 線條相交的方式 | round 圓交bevel 斜交mitter 斜接 |
能夠清楚畫布上的指定區域,好比第一個例子中的兩個矩形,咱們將中間一小塊清除:
context.translate(100, 100) context.fillStyle = "#99cccc"; context.fillRect(-100, -50, 200, 100); context.fillStyle="#3399cc"; context.clearRect(-60, -30, 120, 60);
使用路徑咱們能夠繪製出比較複雜的圖形,開始繪製前,首先執行:
context.beginPath();
結束繪製時,執行:
context.closePath();
如下咱們列舉了繪製路徑的幾個方法:
lineTo(x, y)
,從當前遊標至(x, y)畫一條直線。
moveTo(x, y)
將遊標移動至(x, y),移動過程當中不畫線。好比:
context.beginPath(); context.moveTo(10, 10); context.lineTo(50, 40); context.moveTo(50, 50); context.lineTo(100, 90); context.stroke(); context.closePath();
從startAngle到endAngle繪製一條以(x, y)爲圓心,radius爲半徑的弧線,其中startAngle和endAngle用弧度表示,couterclockwise爲false時,順時針畫弧線, 反之,逆時針畫弧線。
var canvas = document.getElementById("canvas"); if(canvas.getContext) { var context = canvas.getContext("2d"); context.beginPath(); context.arc(400, 400, 50, arcUnit()*30, arcUnit()*180, false); context.stroke(); } function arcUnit() { return Math.PI/180; }
arcTo()
方法將利用當前座標、起點(startX,startY)和終點(endX,endY)這三個點所造成的夾角,繪製一段與夾角的兩邊相切而且半徑爲radius的圓上的弧線。弧線的起點就是當前座標所在邊與圓的切點,弧線的終點就是終點(endX,endY)所在邊與圓的切點,而且繪製的弧線是兩個切點之間長度最短的那個圓弧。此外,若是當前端點不是(startX,startY),arcTo()方法還將添加一條當前端點到(startX,startY)的直線線段。
若是你們還記得高中數學的話,咱們應該能夠猜到,使用這個方法畫弧線大體有三種狀況:
** 只有一種半徑可使弧線兩端正好在起點和終點
** 若是半徑過大,畫不出弧線
** 若是半徑較小,一定會有一條當前端點到起點的直線
咱們舉三個例子:
首先定義一些通用的
var context = canvas.getContext("2d"); var currentPoint = { x: 0, y: 0 }; var startPoint = { x: 50, y: 50 }; var endPoint = { x: 100, y: 0 };
而後繪製參考線
context.moveTo(currentPoint.x, currentPoint.y); context.lineTo(startPoint.x, startPoint.y); context.lineTo(endPoint.x, endPoint.y); context.strokeStyle = "red"; context.stroke();
畫第一條弧線
context.moveTo(currentPoint.x, currentPoint.y); context.arcTo(startPoint.x, startPoint.y, endPoint.x, endPoint.y, 80); context.strokeStyle = "grey"; context.stroke();
context.arcTo(startPoint.x, startPoint.y, endPoint.x, endPoint.y, 120);
context.arcTo(startPoint.x, startPoint.y, endPoint.x, endPoint.y, 40);
quadraticCurveTo(cpX, cpY, x, y)
上述方法能夠畫一條從當前位置到(x, y), 以(cpX, cpY)爲控制點的貝塞爾曲線
bezierCurveTo(cpX1, cpY1, cpX2, cpY2, x, y)
上述方法能夠畫一條從當前位置到(x, y), 以(cpX1, cpY1)和(cpX2, cpY2)爲控制點的貝塞爾曲線。
二次貝塞爾與三次貝塞爾的繪製涉及到比較複雜的數學運算,筆者在此就忽略啦...
固然,大部分前端人士可能都跟筆者同樣,只但願能畫出一條優美的曲線,並不關心實現細節,那麼通常認爲何樣的曲線纔算是優美的曲線呢:
根據以上規則,咱們寫一個工具方法:
function drawCurvePath( ctx, start, end, curveness ) { var cp = [ ( start.x + end.x ) / 2 - ( start.y - end.y ) * curveness, ( start.y + end.y ) / 2 - ( end.x - start.x ) * curveness ]; ctx.moveTo( start.x, start.y ); ctx.quadraticCurveTo( cp[ 0 ], cp[ 1 ], end.x, end.y ); ctx.stroke(); }
以上參考自用canvas繪製一個曲線動畫——深刻理解貝塞爾曲線,你們能夠前往瞭解更深刻的貝塞爾曲線畫法。
使用rect(x, y, width, height)
能夠繪製一個左上角座標爲(x, y),寬width,高height的矩形路徑。
context.rect(300, 300, 100, 200); context.stroke();
在繪製本文以前,若是有必要,咱們首先應該指定context的幾個屬性, 好比:
context.font = "bold 14px Arial"; // 格式同css中指定字體樣式 context.textAlign = "center"; // start end center left right context.textBaseline = "middle"; // top hanging middle alphabetic ideographic bottom
fillText(text, x, y, maxWidth)
使用fillStyle
屬性顯示文本,strokeText(text, x, y, maxWidth)
使用strokeStyle
屬性爲文本描邊。
使用measureText(text)
方法能夠得到文本的寬度。若是咱們並不清楚指定的寬度夠不夠顯示當前字體設置下的一段文字,可使用以下方法:
var fontSize = 50; var maxWidth = 100; context.font = "bold " + fontSize+"px Arial"; var text = "Hello World!"; while(context.measureText(text).width > maxWidth) { fontSize--; context.font = "bold " + fontSize+"px Arial"; } context.fillText(text, 50, 50, maxWidth);
rotate(angle)
context.rotate(Math.PI/4) context.fillText(text, 50, 50, maxWidth);
scale(scaleX, scaleY)
context.scale(1.2, 1.2); context.fillText(text, 50, 50, maxWidth); context.scale(0.5, 0.5); context.fillText(text, 50, 50, maxWidth);
translate(x, y)
假如咱們要繪製一個對稱圖形,移動座標原點將會大大簡化對座標的計算。
使用transform(scaleX,skewX,skewY,scaleY,transX,transY)
能夠進行矩陣變換,其實以上講的三個方法本質上都在調用矩陣變換,從參數名中能夠看出,它們分別表示X軸方向的縮放,Y軸方向的縮放,X軸方向的斜切,Y軸方向的斜切,X軸方向的偏移量,Y軸方向的偏移量。默認值分別爲1 0 0 1 0 0。
咱們如今使用transform()
從新定義一遍以前的三個方法:
rotate
function rotate (ctx, degree) { var unit = Math.PI/180; ctx.transform(Math.cos(degree*unit),Math.sin(degree*unit),-Math.sin(degree*unit),Math.cos(degree*unit),0,0) }
scale
function scale (ctx, scale) { ctx.transform(scale.x, 0, 0, scale.y, 0, 0); }
translate
function translate (ctx, translate) { ctx.transform(1, 0, 0, 1, translate.x, translate.y); }
咱們如今繪製一段文本,先平移(50, 50),而後縮放2倍,最後旋轉30度。
context.fillText(text, 50, 50, maxWidth); translate(context, {x: 50, y: 50}); scale(context, {x: 2, y: 2}); rotate(context, 30); context.fillText(text, 50, 50, maxWidth);
每次執行transform()
都是基於上一次的結果,並非初始狀態,不少時候咱們想執行的是基於初始狀態旋轉、平移或縮放,而非上一次的狀態,此時咱們可使用setTransfrom(scaleX,skewX,skewY,scaleY,transX,transY)
,此方法首先會重置變換矩陣,而後執行transform()
。
更加詳細的內容能夠參考html5 Canvas畫圖教程26:用transform來實現位移,縮放,旋轉等
使用drawImage(image, x1, y1, width1, height1, x2, y2, width2, height2)
能夠將圖像的指定部分按照指定的大小繪製到畫布指定的位置上。
參數 | 含義 |
---|---|
image | 要繪製的圖像,能夠是HTMLImageElement,也能夠是canvas |
x1 | 源圖像的x座標 |
y1 | 源圖像的y座標 |
width1 | 源圖像的寬度 |
height1 | 源圖像的高度 |
x2 | 畫布的x座標 |
y2 | 畫布的y座標 |
width2 | 圖像在畫布上顯示的寬度 |
height2 | 圖像在畫布上顯示的高度 |
若是要給形狀或路徑加上陰影,咱們要在繪製前設置context
對象的如下屬性:
屬性 | 含義 |
---|---|
shadowColor | 陰影顏色 |
shadowOffsetX | x軸偏移量 |
shadowOffsetY | y軸偏移量 |
shadowBlur | 模糊的像素數 |
context.shadowColor = "grey"; context.shadowOffsetX = "20"; context.shadowBlur = "5"; context.fillText(text, 50, 50, maxWidth);
使用createLinearGradient(startX, startY, endX, endY)
來建立線性漸變,這個方法確認了漸變的起始和方向,而後咱們經過addColorStop(position, color)
來添加漸變的顏色,position是0到1的數字。一下筆者畫一個超級喜歡的條紋漸變:
var grad = context.createLinearGradient(50, 50, 200, 200) grad.addColorStop(0, "grey"); grad.addColorStop(0.3, "grey"); grad.addColorStop(0.3, "red"); grad.addColorStop(0.5, "red"); grad.addColorStop(0.5, "orange"); grad.addColorStop(0.7, "orange"); context.fillStyle = grad; context.fillRect(50, 50, 150, 150);
使用createRadialGradient(centerX1, centerY1, radius1, centerX2, centerY2, radius2)
建立徑向漸變。
使用createPattern(image, repeatType)
能夠繪製重複的圖像,用來填充或描邊,第一個參數是要重複的HTMLImageElement或canvas或video,第二個參數表示如何重複該圖像,可取repeat
repeat-x
repeat-y
no-repeat