目次 [1] HTML 属性 [2] CSS スタイル [3] API 座標 塗りつぶしとストローク シャドウの描画 四角形の描画 パスの描画 テキストの描画 画像変換を使用した画像合成 [4] デモ
Canvas 要素はHTML5 の最も人気のある機能ですが、IE8 ブラウザではサポートされていないことに注意してください。 Canvas は純粋な HTML を使用し、高さと幅の 2 つの属性のみを持ちます。その真の力は、JavaScript を介して要素を操作することにあります。 Canvas はビットマップ キャンバスです。つまり、本質的には空白の画像であり、描画コマンドを使用してピクセルを操作できます。
Web ページ上で Canvas 要素を使用すると、長方形の領域が作成されます。デフォルトでは、キャンバスの幅は 300px、高さは 150px です
[注]幅と高さが CSS スタイルを通じて設定されている場合、幅 300px と高さ 150px を設定された CSS スタイル値にスケーリングすることと同等です。デフォルトでは
height 高度width 宽度
はい フォールバック コンテンツを提供するために、開始タグと終了タグの間に HTML を追加します
<canvas width="600" height="300"> <p>The canvas element is not supported!</p></canvas>
ほとんどの HTML 要素と同様に、canvas 要素でも境界線を追加したり、内側と外側を設定したりできますCSS スタイルを適用して余白などを設定します。また、一部の CSS プロパティは、キャンバス内の要素に継承することもできます。たとえば、キャンバスに追加されるフォント スタイルとテキストは、デフォルトではキャンバス要素自体と同じです。さらに、キャンバス内の描画コンテキストのプロパティの設定も CSS 構文に従います。
キャンバス上に描画するには、まず描画コンテキストを取得する必要があります。このとき、getContext() メソッドを呼び出してコンテキストの名前を渡す必要があります。 2D コンテキスト オブジェクトを取得するには「2d」を渡します。3D コンテキストを取得するには「webgl」を使用します。
getContext('2d'):取得2D上下文对象
<canvas id="drawing" width="200" height="200"></canvas><script>var drawing = document.getElementById('drawing');//确定浏览器支持<canvas>元素if(drawing.getContext){ var context = drawing.getContext('2d');}</script>
2D コンテキストによって提供されるメソッドを使用して、長方形、円弧、パスなどの単純な 2D グラフィックスを描画します。 2D コンテキストの座標は
2Dコンテキストにおける2つの基本的な描画操作はfillとstrokeです。塗りつぶしとは、指定されたスタイル (色、グラデーション、イメージ) でグラフィックスを塗りつぶすことを指します。つまり、グラフィックスの端にのみ線を描画することを意味します。ほとんどの 2D コンテキスト操作は塗りつぶし操作とストローク操作に細分され、操作の結果は 2 つのプロパティ (fillStyle とストロークスタイル) によって決まります。これら 2 つのプロパティの値は、文字列で表される色、グラデーション オブジェクト、またはパターン オブジェクトにすることができ、それらのデフォルト値は #000
var context = drawing.getContext('2d');
context.bloodStyle= " red";
context.fillStyle="#00f";
<1>Color
色を表す文字列値で表され、色名、16 進数、rgb、rgba、hsl、hsla を使用できます。
var context = drawing.getContext('2d');context.strokeStyle="red";context.fillStyle="#00f";
<2>Gradient
Gradient は CanvasGradient インスタンスによって表されます
(1.2) createRadialGradient() メソッドを呼び出して、放射状のグラデーションを作成します。 このメソッドは、2 つの円の中心と円の半径に対応する 6 つのパラメーターを受け取ります。最初の 3 つのパラメータは、開始円の中心 (x と y) と半径を指定します。最後の 3 つのパラメーターは、終点円の中心 (x および y) と半径を指定します。放射状のグラデーションは長いバレルと考えることができ、これら 6 つのパラメータは、このバレルの 2 つの円形の開口部の位置を定義します [注] シェイプの中心点から始まる外向きの拡散を作成したい場合放射状のグラデーション効果、2 つの円は同心円として定義する必要があります
(2) 次に、addColorStop() メソッドを使用してカラー スケールを指定します。このメソッドは、カラー停止位置と CSS カラー値の 2 つのパラメーターを受け取ります。カラースケールの位置は、0(開始色)と1(終了色)の間の数値です
(3)fillStyleかストロークStyleにグラデーションオブジェクトのインスタンスを代入します
//线性渐变var linearGradient = context.createLinearGradient(0,0,0,100); linearGradient.addColorStop(0,'red');linearGradient.addColorStop(0.5,'green');linearGradient.addColorStop(1,'blue');context.fillStyle = linearGradient;context.fillRect(0,0,100,100);//径向渐变var radialGradient = context.createRadialGradient(50,50,0,50,50,50); radialGradient.addColorStop(0,'red');radialGradient.addColorStop(0.5,'green');radialGradient.addColorStop(1,'blue');context.fillStyle = radialGradient;context.fillRect(0,0,100,100);
//渐变描边var linearGradient = context.createLinearGradient(0,0,0,100); linearGradient.addColorStop(0,'red');linearGradient.addColorStop(0.5,'green');linearGradient.addColorStop(1,'blue');context.strokeStyle = linearGradient;context.lineWidth = 5;context.strokeRect(0,0,100,100);//渐变文字var linearGradient = context.createLinearGradient(0,0,150,50); linearGradient.addColorStop(0,'red');linearGradient.addColorStop(0.5,'green');linearGradient.addColorStop(1,'blue');context.strokeStyle = linearGradient;context.font="30px/50px arial";context.strokeText("little Match",0,30);
把一幅图像绘制到画布上可以使用drawImage()方法,根据期望的最终结果的不同,调用这个方法时,可以使用三种不同的参数组合
[1]最简单的调用方式是传入一个元素,以及绘制该图像的起点的x和y坐标
context.drawImage(img,10,10);
[2]若想要改变绘制的图像的大小,可以多传入两个参数,分别表示目标宽度和目标高度
context.drawImage(img,50,10,20,30);
[3]还可以选择把图像中的某个区域绘制到上下文中。drawImage()方法的这种调用方式总共需要传入9个参数:要绘制的图像、源图像的x坐标、源图像的y坐标、源图像的宽度、源图像的高度、目标图像的x坐标、目标图像的y坐标、目标图像的宽度、目标图像的高度
context.drawImage(img,0,10,50,50,0,100,40,60);
[注意]除了给drawImage()方法传入元素外,还可以传入另一个
使用toDataURL()方法可以导出在canvas元素上绘制的图像。这个方法接受一个参数,即图像的MIME类型格式,而且适合用于创建图像的任何上下文
[注意]toDataURL()方法只可以在服务器端使用,在本地无效,且不可跨域
var imgURI = drawing.toDataURL('image/png');var image = document.createElement('img');image.src=imgURI;
<演示框>点击下列相应属性值可进行演示
<1>获取
2D上下文可以通过getImageData()取得原始图像数据。这个方法接收4个参数:画面区域的x和y坐标以及该区域的像素宽度和高度
例如,要取得左上角坐标为(10,5)、大小为50*50像素的区域的图像数据,可以使用以下代码:
var imageData = context.getImageData(10,5,50,50);
返回的对象是ImageData的实例,每个ImageData对象有3个属性:width\height\data
[1]data是一个数组,保存着图像中每一个像素的数据。在data数组中,每一个像素用4个元素来保存,分别表示red\green\blue\透明度
[注意]图像中有多少像素,data的长度就等于像素个数乘以4
//第一个像素如下var data = imageData.data;var red = data[0];var green = data[1]; var blue = data[2];var alpha = data[3];
数组中每个元素的值是在0-255之间,能够直接访问到原始图像数据,就能够以各种方式来操作这些数据
[2]width:表示imageData对角的宽度
[3]height:表示imageData对象的高度
<2>创建
createImageData(width,height)方法创建新的空白ImageData对象。新对象的默认像素值 transparent black,相当于rgba(0,0,0,0);
var imgData = context.createImageData(100,100);
<3>修改
putImageData()方法将图像数据从指定的ImageData对象放回画布上,该方法共有以下参数
[1]imgData:要放回画布的ImageData对象(必须)
[2]x:imageData对象的左上角的x坐标(必须)
[3]y:imageData对象的左上角的y坐标(必须)
[4]dirtyX:在画布上放置图像的水平位置(可选)
[5]dirtyY:在画布上放置图像的垂直位置(可选)
[6]dirtyWidth:在画布上绘制图像所使用的宽度(可选)
[7]dirtyHeight:在画布上绘制图像所使用的高度(可选)
[注意]参数3到7要么都没有,要么都存在
context.putImageData(imgData,0,0); context.putImageData(imgData,0,0,50,50,200,200);
通过上下文的变换,可以把处理后的图像绘制到画布上。可以通过如下方法来修改变换矩阵
rotate(angle):围绕原点旋转图像angle弧度scale(scaleX,scaleY):缩放图像,在x方向上乘以scaleX,在Y方向上乘以scaleY。scaleX和scaleY的默认值都是1translate(x,y):将坐标原点移动到(x,y)。执行这个变换之后,坐标(0,0)会变成之前由(x,y)表示的点transform(m1_1,m1_2,m2_1,m2_2,dx,dy):直接修改变换矩阵,方式是乘以如下矩阵。m1_1 m1_2 dxm2_1 m2_2 dy0 0 1 [注意]transform()方法的行为相对于由rotate()、scale()、translate()、transform() 完成的其他变换。例如:如果已经将绘图设置为放到两倍,则transform() 方法会把绘图放大两倍,绘图最终将放大四倍setTransform(m1_1,m1_2,m2_1,m2_2,dx,dy):将变换矩阵重置为默认状态,然后再调用transform()
有两个方法可以跟踪上下文的状态变化:
save()方法可以保存当前环境的状态,并返回某组属性与变换的组合。所有设置都会进入一个栈结构,得以妥善保管
restore()方法可以在保存设置的栈结构中向前返回一级,恢复之前保存过的路径状态和属性
连续调用save()方法可以把更多设置保存到栈结构中,之后再连续调用restore()方法可以一级一级返回
[注意]save()方法只保存对绘图上下文的设置和变换,不会保存绘图上下文的内容
<演示框>点击下列相应属性值可进行演示
globalAlpha是一个介于0和1之间的属性值(包括0和1),用于指定所有绘制的透明度(默认值为0)。如果后续所有操作都要基于相同的透明度,就可以先把globalAlpha设置为适当值,然后绘制,最后再把设置回默认值0
var context = drawing.getContext('2d');context.globalAlpha = 0.5;context.fillStyle = "#f00";context.fillRect(10,10,50,50);context.globalAlpha = 1;context.fillStyle = "rgb(0,0,255)";context.fillRect(30,30,50,50);context.globalAlpha = 0;
globalCompositeOperation表示后绘制的图形怎样与先绘制的图形结合,属性值是字符串,可能值如下:
source-over(默认):后绘制的图形位于先绘制的图形上方source-in:后绘制的图形与先绘制的图形重叠的部分可见,两者其他部分完全透明source-out:后绘制的图形与先绘制的图形不重叠的部分可见,先绘制的图形完全透明source-atop:后绘制的图形与先绘制的图形重叠的部分可见,先绘制的图形不受影响destination-over:后绘制的图形位于先绘制的图形下方,只有之前透明像素下的部分才可见destination-in:后绘制的图形位于先绘制的图形下方,两者不重叠的部分完全透明destination-out:后绘制的图形擦除与先绘制的图形重叠的部分destination-atop:后绘制的图形位于先绘制的图形下方,在两者不重叠的地方,先绘制的图形会变透明lighter:后绘制的图形与先绘制的图形重叠部分的值相加,使该部分变亮copy:后绘制的图形完全替代与之重叠的先绘制图形 xor:后绘制的图形与先绘制的图形重叠的部分执行"异或"操作
[注意]合成操作只能写在两个图形之间
<演示框>点击下列相应属性值可进行演示
<canvas id="drawing" width="100" height="100"></canvas> <script>var drawing = document.getElementById('drawing');var img = document.createElement('img');img.src="data:image/gif;base64,R0lGODlhIAAgAPcAAP91AafK42iOqf+9RP/Kkv/x5P+TPP/Ah5C20P+NIv/ss/+6e+Du9/+ZAP/qyv/iv32ivP+bSP+8X//eqP/8+bW4uf+LAP+lIv/x2LrV6P/chP+0Of+bEP+nWqfE2f++Wf/Udf99EIOrxv/gtP+LEP/Xhf+oP//ll//sz/+sIf+eJ/+2S/+/Uv/MZmuUsf+CAP/17Z3A2e34///Pc7PG1P/dlf+lEP+UAP+iAP+xUf+sJ//x3v/di//LhP/npXOcuP/Ga//VeYGow/+tSMfa54uwyv+hF//WiqrN5f/tvf+uO//Me/+YQv+3Qv/Jcf/Nav/pv/+kB7jL2P+TIf96AP/00//GXP/js/+ZM//env+sVP///3GXsf+UB//orv/GVP/69v+zJ/+DDP/45v/GY/+OCf+EDpy93v/bff/14P+fCYquyP/erf/moLO8wf+aFf+JGf/Mjv+7SP+nKv+1If/xxf/pwv+2XMTW4/+4M//WlP/Ubv+wXP+BGP/Jff+dNv+sG/+PJ7nN2wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAHAP8ALAAAAAAgACAAAAj/ALcIHEiwoMGDCBMqXJjQwYwNgHAA2jDDAcOEGFhE2Yijo0cWGC4WvJJiQxM5cvKECZPCRkcbV0QKnKCDxYwjR4I8+TJgQJ6WDRpMEIkiBYsjV+zY8VIjSAsrPMPYaKAGxcUmSpxcwTAmjQOmaPa0iDpVCcMHHJocsTNmC4wqSdrwQIPmiZUmOrp0GbFQAocVR6CkgTEGro8TGjQ4ZbHByI0PC990adKDjQMMGOooaHOCx9w9dy/ceKNwjIUuSoDU8JIkiYLDnnloAEFGzpwuFmBgtFBmzoclNXwI7xx7NpkVc8pYCImwAO85K1oEiU1dNm3kynUjpPDihYohVmaU/qjuucQMK0NUWHixEMuLKSY+AAmigXwQIB9MTHmBZeGBFyT8sQIZ4o0Xm3nH/UHCCwssVIAYVMAn3xIlGFjCEvjpR8ULBTB0ABVmYDGEBE6UkMWJeiwhwRBYmEFFgwxR0AEAcPyRgx9ZXKFjFj3c8QccAERAgUgUMAFAAlrEMYIDTI4QBx+BBAmGTFuAYUAIHRDwwA4w7PAAAR30wcSUVLrlwg9CIBAAEjGsAQEXApBZ5hYVoKkmm25y4cacA7kQQwYMyMAAER4UIYIAfAokhZ1rtvkmDYlu4SegghJqKKKJLppmo3lCGukPlA5aKBeRCiTIpnhCIEWpAxHRKB6sA7IaEAA7";if(drawing.getContext){ var context = drawing.getContext('2d'); context.drawImage(img,0,0); var imageData = context.getImageData(0,0,img.width,img.height); var data = imageData.data; for(var i = 0, len = data.length; i < len; i+=4){ var red = data[i]; var green = data[i+1]; var blue = data[i+2]; var alpha = data[i+3]; var average = Math.floor((red+green+blue)/3); data[i] = data[i+1] = data[i+2] = average; } imageData.data = data; context.putImageData(imageData,32,0);}</script>
<canvas id="drawing" width="100" height="100"></canvas><script>var drawing = document.getElementById('drawing');if(drawing.getContext){ var context = drawing.getContext('2d'); var img = document.createElement('img'); img.src="data:image/gif;base64,R0lGODlhIAAgAPcAAP91AafK42iOqf+9RP/Kkv/x5P+TPP/Ah5C20P+NIv/ss/+6e+Du9/+ZAP/qyv/iv32ivP+bSP+8X//eqP/8+bW4uf+LAP+lIv/x2LrV6P/chP+0Of+bEP+nWqfE2f++Wf/Udf99EIOrxv/gtP+LEP/Xhf+oP//ll//sz/+sIf+eJ/+2S/+/Uv/MZmuUsf+CAP/17Z3A2e34///Pc7PG1P/dlf+lEP+UAP+iAP+xUf+sJ//x3v/di//LhP/npXOcuP/Ga//VeYGow/+tSMfa54uwyv+hF//WiqrN5f/tvf+uO//Me/+YQv+3Qv/Jcf/Nav/pv/+kB7jL2P+TIf96AP/00//GXP/js/+ZM//env+sVP///3GXsf+UB//orv/GVP/69v+zJ/+DDP/45v/GY/+OCf+EDpy93v/bff/14P+fCYquyP/erf/moLO8wf+aFf+JGf/Mjv+7SP+nKv+1If/xxf/pwv+2XMTW4/+4M//WlP/Ubv+wXP+BGP/Jff+dNv+sG/+PJ7nN2wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAHAP8ALAAAAAAgACAAAAj/ALcIHEiwoMGDCBMqXJjQwYwNgHAA2jDDAcOEGFhE2Yijo0cWGC4WvJJiQxM5cvKECZPCRkcbV0QKnKCDxYwjR4I8+TJgQJ6WDRpMEIkiBYsjV+zY8VIjSAsrPMPYaKAGxcUmSpxcwTAmjQOmaPa0iDpVCcMHHJocsTNmC4wqSdrwQIPmiZUmOrp0GbFQAocVR6CkgTEGro8TGjQ4ZbHByI0PC990adKDjQMMGOooaHOCx9w9dy/ceKNwjIUuSoDU8JIkiYLDnnloAEFGzpwuFmBgtFBmzoclNXwI7xx7NpkVc8pYCImwAO85K1oEiU1dNm3kynUjpPDihYohVmaU/qjuucQMK0NUWHixEMuLKSY+AAmigXwQIB9MTHmBZeGBFyT8sQIZ4o0Xm3nH/UHCCwssVIAYVMAn3xIlGFjCEvjpR8ULBTB0ABVmYDGEBE6UkMWJeiwhwRBYmEFFgwxR0AEAcPyRgx9ZXKFjFj3c8QccAERAgUgUMAFAAlrEMYIDTI4QBx+BBAmGTFuAYUAIHRDwwA4w7PAAAR30wcSUVLrlwg9CIBAAEjGsAQEXApBZ5hYVoKkmm25y4cacA7kQQwYMyMAAER4UIYIAfAokhZ1rtvkmDYlu4SegghJqKKKJLppmo3lCGukPlA5aKBeRCiTIpnhCIEWpAxHRKB6sA7IaEAA7"; context.drawImage(img,0,0); var imgData = context.getImageData(0,0,32,32); var data = imgData.data; var len = data.length; for(var i = 0; i < len; i++){ if((i+1)%4==0){ data[i] = 255; }else{ data[i] = 255- data[i]; } } context.putImageData(imgData,32,0);}</script>
<canvas id="drawing" width="500" height="500"></canvas><script>var drawing = document.getElementById('drawing');if(drawing.getContext){ var context = drawing.getContext('2d');context.beginPath();context.arc(100,100,99,0,2*Math.PI,false);context.moveTo(194,100);context.arc(100,100,94,0,2*Math.PI,false);context.moveTo(100,100);context.lineTo(100,15);context.moveTo(100,100);context.lineTo(35,100);context.strokeStyle = '#f00';context.stroke();}</script>
<canvas id="drawing" width="100" height="100"></canvas><script>var drawing = document.getElementById('drawing');if(drawing.getContext){ var context = drawing.getContext('2d'); var x = drawing.width/2; var y = drawing.height/2; var deg = 0; var r = 1; context.strokeStyle = 'red'; context.lineWidth = 2; context.moveTo(x,y); for(var i = 0; i < 4800; i++){ deg++; r+=0.01; context.lineTo(x+Math.cos(deg * Math.PI/180)*r,y+Math.sin(deg * Math.PI/180)*r); } context.stroke();}</script>