1. 概要
Canvas API (キャンバス) は、Web ページ上でリアルタイムに画像を生成するために使用され、基本的には JavaScript で操作できるビットマップ (ビットマップ) です。使用する前に、まず新しい
<canvas id="myCanvas" width="400" height="200"> 您的浏览器不支持canvas!</canvas>
上記のコードでは、ブラウザがこの API をサポートしていない場合、
各 Canvas ノードには対応するコンテキスト オブジェクト (context オブジェクト) があり、Canvas API はこのコンテキスト オブジェクトに定義されているため、getContext メソッドを使用してこのオブジェクトを取得する必要があります。
var canvas = document.getElementById('myCanvas'); if (canvas.getContext) { var ctx = canvas.getContext('2d'); }
上記のコードでは、getContext メソッドでパラメーター 2d を指定しています。これは、キャンバス ノードを使用して 2D パターン (つまり、フラット パターン) を生成することを意味します。パラメータが webgl の場合は、3D 画像 (つまり、3 次元パターン) を生成するために使用されることを意味します。この部分は、実際には WebGL API と呼ばれます。
2. 描画方法
キャンバス キャンバスは、描画のための平らな空間を提供します。空間内の各点は独自の座標を持ち、x は横座標を表し、y は垂直座標を表します。原点 (0, 0) は画像の左上隅にあり、x 軸の正の方向は原点の右側、y 軸の正の方向は原点から下になります。
(1)パスの描画
beginPathメソッドはパスの描画開始を示し、moveTo(x,y)メソッドは線分の始点を設定、lineTo(x,y)メソッドは線分の終点を設定します、透明な線分に色を付けるにはストロークメソッドが使用されます。
ctx.beginPath(); // 开始路径绘制 ctx.moveTo(20, 20); // 设置路径起点,坐标为(20,20) ctx.lineTo(200, 20); // 绘制一条到(200,20)的直线 ctx.lineWidth = 1.0; // 设置线宽 ctx.strokeStyle = '#CC0000'; // 设置线的颜色 ctx.stroke(); // 进行线的着色,这时整条线才变得可见
moveto メソッドと lineto メソッドは複数回使用できます。最後に、closePath メソッドを使用して、現在の点から開始点まで自動的に直線を引いて閉じた図形を形成することもできるため、lineto メソッドを一度使用する必要がなくなります。
(2) 長方形の描画 fillRect(x, y, width, height) メソッドは、長方形の左上隅の頂点の x 座標と y 座標、および 4 つのパラメータを使用します。長方形の幅と高さ。 fillStyle プロパティは、四角形の塗りつぶしの色を設定するために使用されます。
ctx.fillStyle = 'yellow'; ctx.fillRect(50, 50, 200, 100);
ストロークRectメソッドはfillRectに似ており、中空の長方形を描画するために使用されます。
ctx.strokeRect(10,10,200,100);
clearRect メソッドは、長方形領域の内容をクリアするために使用されます。
ctx.clearRect(100,50,50,50);
(3) テキストの描画
fillText(string, x, y) は、テキストの内容、開始点の x 座標、y 座標の 3 つのパラメーターを使用します。使用する前に、fontを使用してフォント、サイズ、スタイルを設定する必要があります(記述方法はCSSのfont属性に似ています)。これと同様に、空虚な単語を追加するために使用される、ストロークテキスト メソッドがあります。
ctx.font = "Bold 20px Arial"; // 设置字体 ctx.textAlign = "left";// 设置对齐方式 ctx.fillStyle = "#008600"; // 设置填充颜色 ctx.fillText("Hello!", 10, 50); // 设置字体内容,以及在画布上的位置 ctx.strokeText("Hello!", 10, 100); // 绘制空心字
fillText メソッドはテキストの改行をサポートしていません。つまり、すべてのテキストが 1 行に表示されます。したがって、複数行のテキストを生成する場合は、fillText メソッドを複数回呼び出すことしかできません。
(4)円と扇形を描く
arcメソッドを使って扇形を描画します。
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
arc メソッドの x パラメーターと y パラメーターは円の中心の座標、radius は半径、startAngle と endAngle はセクターの開始角度と終了角度 (ラジアンで表現)、反時計回りは、描画は反時計回りに描画するか (true)、時計回りに描画しません (false)。
実線の円の描き方はこちら:
ctx.beginPath(); ctx.arc(60, 60, 50, 0, Math.PI*2, true); ctx.fillStyle = "#000000"; ctx.fill();
中空の円の描画例:
ctx.beginPath(); ctx.arc(60, 60, 50, 0, Math.PI*2, true); ctx.lineWidth = 1.0; ctx.strokeStyle = "#000"; ctx.stroke();
(5) グラデーションカラーの設定
グラデーションカラーの設定にはcreateLinearGradientメソッドを使用します。
var myGradient = ctx.createLinearGradient(0, 0, 0, 160); myGradient.addColorStop(0, "#BABABA"); myGradient.addColorStop(1, "#636363");
createLinearGradient メソッドのパラメータは (x1, y1, x2, y2) です。x1 と y1 は始点の座標、x2 と y2 は終点の座標です。さまざまな座標値を使用して、上から下、左から右などのグラデーションを生成できます。使用方法は以下の通りです。
ctx.fillStyle = myGradient; ctx.fillRect(10,10,200,100);
(6) 影を設定する
影に関する一連のメソッドを使用して影を設定できます。
ctx.shadowOffsetX = 10; // 设置水平位移 ctx.shadowOffsetY = 10; // 设置垂直位移 ctx.shadowBlur = 5; // 设置模糊度 ctx.shadowColor = "rgba(0,0,0,0.5)"; // 设置阴影颜色 ctx.fillStyle = "#CC0000"; ctx.fillRect(10,10,200,100);
3. 画像処理メソッド
drawImageメソッド
Canvas APIでは、画像を読み込んだ後にdrawImageメソッドを使ってキャンバス内に再描画する方法です。
var img = new Image(); img.src = 'image.png'; ctx.drawImage(img, 0, 0); // 设置对应的图像对象,以及它在画布上的位置
上記のコードは、PNG 画像をキャンバスに読み込みます。 drawImage() メソッドは 3 つのパラメータを受け取ります。最初のパラメータは画像ファイルの DOM 要素 (つまり、 ノード) です。2 番目と 3 番目のパラメータは、キャンバス内の画像の左上隅の座標です。上記の例 (0, 0) は、画像の左上隅をキャンバスの左上隅に配置することを意味します。
画像の読み込みには時間がかかるため、画像の読み込みが完了してからでないとdrawImageメソッドを呼び出すことができないため、上記のコードを書き直す必要があります。
var image = new Image(); image.onload = function() { var canvas = document.createElement('canvas'); canvas.width = image.width; canvas.height = image.height; canvas.getContext('2d').drawImage(image, 0, 0); // 插入页面底部 document.body.appendChild(image); return canvas; } image.src = 'image.png';
getImageDataメソッド、putImageDataメソッド
getImageDataメソッドを使用すると、Canvasの内容を読み取り、各ピクセルの情報を含むオブジェクトを返すことができます。
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
imageData オブジェクトは data 属性を持ち、その値は 1 次元配列です。この配列の値は、順番に各ピクセルの赤、緑、青、アルファ チャネルの値であるため、配列の長さは画像のピクセル幅 x 画像のピクセル高さ x 4 に等しくなります。各値の範囲は 0 ~ 255 です。この配列は読み取りだけでなく書き込みも可能であるため、この配列の値を操作することで、画像を操作する目的を達成できます。この配列を変更した後、putImageData メソッドを使用して、キャンバス上に配列の内容を再描画します。
context.putImageData(imageData, 0, 0);
toDataURLメソッド
画像データを変更した後、toDataURLメソッドを使用してCanvasデータを一般的な画像ファイル形式に再変換できます。
function convertCanvasToImage(canvas) { var image = new Image(); image.src = canvas.toDataURL('image/png'); return image; }
上記のコードは、Canvas データを PNG データ URI に変換します。
saveメソッド、restoreメソッド
saveメソッドはコンテキストを保存するために使用され、restoreメソッドは最後に保存されたコンテキストに復元するために使用されます
ctx.save(); ctx.shadowOffsetX = 10; ctx.shadowOffsetY = 10; ctx.shadowBlur = 5; ctx.shadowColor = 'rgba(0,0,0,0.5)'; ctx.fillStyle = '#CC0000'; ctx.fillRect(10,10,150,100); ctx.restore(); ctx.fillStyle = '#000000'; ctx.fillRect(180,10,150,100);
上面代码先用save方法,保存了当前设置,然后绘制了一个有阴影的矩形。接着,使用restore方法,恢复了保存前的设置,绘制了一个没有阴影的矩形。
4.动画
利用JavaScript,可以在canvas元素上很容易地产生动画效果。
var posX = 20, posY = 100; setInterval(function() { context.fillStyle = "black"; context.fillRect(0,0,canvas.width, canvas.height); posX += 1; posY += 0.25; context.beginPath(); context.fillStyle = "white"; context.arc(posX, posY, 10, 0, Math.PI*2, true); context.closePath(); context.fill(); }, 30);
上面代码会产生一个小圆点,每隔30毫秒就向右下方移动的效果。setInterval函数的一开始,之所以要将画布重新渲染黑色底色,是为了抹去上一步的小圆点。
通过设置圆心坐标,可以产生各种运动轨迹。
先上升后下降。
var vx = 10, vy = -10, gravity = 1; setInterval(function() { posX += vx; posY += vy; vy += gravity; // ... });
上面代码中,x坐标始终增大,表示持续向右运动。y坐标先变小,然后在重力作用下,不断增大,表示先上升后下降。小球不断反弹后,逐步趋于静止。
var vx = 10, vy = -10, gravity = 1; setInterval(function() { posX += vx; posY += vy; if (posY > canvas.height * 0.75) { vy *= -0.6; vx *= 0.75; posY = canvas.height * 0.75; } vy += gravity; // ... });
上面代码表示,一旦小球的y坐标处于屏幕下方75%的位置,向x轴移动的速度变为原来的75%,而向y轴反弹上一次反弹高度的40%。
5.像素处理
通过getImageData方法和putImageData方法,可以处理每个像素,进而操作图像内容。假定filter是一个处理像素的函数,那么整个对Canvas的处理流程,可以用下面的代码表示。
if (canvas.width > 0 && canvas.height > 0) { var imageData = context.getImageData(0, 0, canvas.width, canvas.height); filter(imageData); context.putImageData(imageData, 0, 0); }
以下是几种常见的处理方法:
灰度效果
灰度图(grayscale)就是取红、绿、蓝三个像素值的算术平均值,这实际上将图像转成了黑白形式。假定d[i]是像素数组中一个象素的红色值,则d[i+1]为绿色值,d[i+2]为蓝色值,d[i+3]就是alpha通道值。转成灰度的算法,就是将红、绿、蓝三个值相加后除以3,再将结果写回数组。
grayscale = function (pixels) { var d = pixels.data; for (var i = 0; i < d.length; i += 4) { var r = d[i]; var g = d[i + 1]; var b = d[i + 2]; d[i] = d[i + 1] = d[i + 2] = (r+g+b)/3; } return pixels; };
复古效果
复古效果(sepia)则是将红、绿、蓝三个像素,分别取这三个值的某种加权平均值,使得图像有一种古旧的效果。
sepia = function (pixels) { var d = pixels.data; for (var i = 0; i < d.length; i += 4) { var r = d[i]; var g = d[i + 1]; var b = d[i + 2]; d[i] = (r * 0.393)+(g * 0.769)+(b * 0.189); // red d[i + 1] = (r * 0.349)+(g * 0.686)+(b * 0.168); // green d[i + 2] = (r * 0.272)+(g * 0.534)+(b * 0.131); // blue } return pixels; };
红色蒙版效果
红色蒙版指的是,让图像呈现一种偏红的效果。算法是将红色通道设为红、绿、蓝三个值的平均值,而将绿色通道和蓝色通道都设为0。
red = function (pixels) { var d = pixels.data; for (var i = 0; i < d.length; i += 4) { var r = d[i]; var g = d[i + 1]; var b = d[i + 2]; d[i] = (r+g+b)/3; // 红色通道取平均值 d[i + 1] = d[i + 2] = 0; // 绿色通道和蓝色通道都设为0 } return pixels; };
亮度效果
亮度效果(brightness)是指让图像变得更亮或更暗。算法将红色通道、绿色通道、蓝色通道,同时加上一个正值或负值。
brightness = function (pixels, delta) { var d = pixels.data; for (var i = 0; i < d.length; i += 4) { d[i] += delta; // red d[i + 1] += delta; // green d[i + 2] += delta; // blue } return pixels; };
反转效果
反转效果(invert)是指图片呈现一种色彩颠倒的效果。算法为红、绿、蓝通道都取各自的相反值(255-原值)。
invert = function (pixels) { var d = pixels.data; for (var i = 0; i < d.length; i += 4) { d[i] = 255 - d[i]; d[i+1] = 255 - d[i + 1]; d[i+2] = 255 - d[i + 2]; } return pixels; };