ホームページ > 記事 > ウェブフロントエンド > Canvas とは一体何なのかについて話しましょう
HTML5 標準が発表されてからかなりの時間が経ちますが、Canvas は現在あまり多くの場所で使用されていないようです。非常に重要な理由は、Canvas の標準が完全に決定されておらず、実稼働環境での大規模な使用には適していないことです。ただし、Canvas の利点も非常に明白です。たとえば、技術共有ミーティングの抽選セッションでは、多数の要素を含むチャートを描画する場合、SVG ではその作業ができないことがよくあります。見たところ、エフェクトは比較的眩しかったですが、パフォーマンスの問題で不可能でした。各アバターは DOM であり、アニメーションは CSS3 によって制御されているため、パフォーマンスが非常に低くなります。さらに、ハードウェアのパフォーマンスの向上により、ビデオのスクリーンショットや画像処理などの機能が Web ページに徐々に実装されるようになりました。ほとんどの Web サイトでは Flash が使用されていますが、Mac コンピューターでは Flash のパフォーマンスが高くないため、追加の学習が必要です。知識。 。 Canvas は描画に JavaScript を直接使用しており、Mac に優しいため、Flash の後継と見なすことができます。
Canvas を使用する
ここまでお話しましたが、Canvas とは一体何でしょうか?
Canvasは英語で「キャンバス」を意味しますが、ここで言うCanvasはHTML5の新しい要素であり、開発者はその上に一連のグラフィックを描画できます。 Canvas を HTML ファイルに記述する方法は非常に簡単です:
Canvas に付属する属性は、最後の 2 つ (幅と高さをそれぞれ制御) だけです。他にはありません。互換性については、CanIUseは現在、ユーザーが使用しているブラウザの90%で基本機能がサポートされており、ほとんどの場合安心して使用できると述べている。
注意: CSS を使用すると Canvas が変形してしまうため、Canvas に付属の width プロパティと height プロパティを使用しないでください。 PhptpShop と比較してみてください。後者は「画像サイズ」を変更しますが、前者は「キャンバス サイズ」を変更する正しい方法です。たとえば、下の画像は 3 つの画像を水平につなぎ合わせたものです。左端の黒いボックスはサイズが 50px * 50px の元の画像で、中央は画像サイズを 100px * 100px に変更した結果です。ぼやけますが、画像自体の座標範囲は大きくなっていないと言われています。右端が正しい 100px * 100px Canvas です。
Canvas ほとんどの描画メソッドは
最初にこの要素を取得します:
var canvas = document.getElementById('canvas');
次に、メソッドを使用して、すべての Canvas API を呼び出すことができる入り口を取得します:
var ctx = canvas.getContext('2d');
2D を見ると興奮して 3D のことを考えますか? 3D を記述する方法はありませんが、3D 世界への扉を開きたい場合は、canvas.getContext('webgl') を記述することができます。ただし、WebGL は OpenGL ES 2.0 をベースにした一連の標準であり、この記事とはまったく異なるため、ここでは説明しません。
Canvas
座標
の基本概念は、数学における一般的なデカルト座標系とは異なります。Canvasの座標系は、次のようになります。キャンバスの左隅 角度は(0,0)、xは右に、yは下に増加し、x、yともに整数(計算時は整数でなくても描画時には整数として扱われます) )、単位はピクセルです。
绘图
带大家怀旧一下。不知道有多少同学小时候玩过 logo 语言,在里面你可以控制一只小海龟在一块板子上行走、画画、提笔、落笔。Canvas 中也一样,你需要控制一只画笔的移动和绘制。然而 Canvas 更高级一些,你可以直接利用一些函数来画图,不用去控制那只画笔的位置。
Canvas 中的基本图形
通过上文定义的 ctx 变量可以干许多有意思的事情,我们先看看如何绘制一些基本图形。
线条
我们指定画笔移动到某一点,然后告诉画笔需要从当前这一点画到另一点。我们可以让画笔多次移动、绘制,最后统一输出到屏幕上。例子如下:
ctx.moveTo(10, 10); ctx.lineTo(150, 50); ctx.lineTo(10, 50); ctx.moveTo(10, 20); ctx.lineTo(40, 70); ctx.stroke();
上面的代码中,lineTo 是产生线条用的函数,执行完之后画笔就移到了线条的终点。需要注意的是,线条此时并没有显示在屏幕上,必须调用 stroke 才会显示。这样设计是有道理的,因为向屏幕上输出内容需要耗费大量的资源,我们完全可以先攒够一波 lineTo,最后用 stroke 放一个大的。
路径
绘制路径非常简单,只需要先告诉 ctx 一声“我要开始画路径了”,然后通过各种方法(例如 lineTo)绘制路径。如果需要画一个封闭路径,那就最后告诉 ctx一声:“我画完了,你把它封闭起来吧。”当然,不要忘记利用 stroke 输出到屏幕上。
一个简单的例子:
ctx.beginPath(); ctx.moveTo(10, 10); ctx.lineTo(150, 50); ctx.lineTo(10, 50); ctx.closePath(); ctx.stroke();
如果我不想只描绘路径线条,而是想填充整个路径呢?可以将最后一行的 stroke 改成 fill,这样就跟使用了画图中的油漆桶一样,封闭路径里面的内容就都被填充上颜色了:
ctx.fill();
弧 / 圆形
绘制弧的函数参数比较多:
ctx.arc(圆心 x 坐标, 圆心 y 坐标, 半径, 起始角度, 终止角度, 是否为逆时针);
注意,在 Canvas 的坐标系中,角的一边是以圆心为中心的水平向右的直线。角度单位均为弧度。例如下图,确定了圆心、起始角度(图中标明的锐角)和终止角度(图中标明的钝角),方向为逆时针,于是就有了这么一个弧。如果方向为顺时针,那么就会是一个跟它互补的、非常非常大的弧……
所以如果转了 2π 圈之后,弧就成了圆形,因此也可以使用绘制弧的方式来绘制圆形:
ctx.beginPath(); ctx.arc(圆心 x 坐标, 圆心 y 坐标, 半径, 0, Math.PI * 2, true); ctx.closePath();
最后一个参数随便填(当然也可以不填),因为不管是顺时针还是逆时针,转了 2π 圈之后都是一个圆。
矩形
如果只是想绘制一个横平竖直的矩形,可以使用下面的两个方法:
// 只描边 ctx.strokeRect(左上角 x 坐标, 左上角 y 坐标, 宽度, 高度); // 只填充 ctx.fillRect(左上角 x 坐标, 左上角 y 坐标, 宽度, 高度);
线条样式 / 填充样式
之前绘制的所有图形都是黑色的,但是 Canvas 肯定不止这么一种颜色(不然标准的制定者会被喷的很惨)。事实上,Canvas 可以单独设置线条样式和填充样式,分别使用的是 strokeStyle 和 fillStyle。可能的值有三种:纯色、渐变、图像。既然线条样式与填充样式的使用方法相同,那么下面统一以填充样式为例。如果想设置线条样式,直接将所有的 fillStyle 改成 strokeStyle 即可,里面的参数都不变。
/* 纯色填充 */ // 普通的颜色 ctx.fillStyle = '#0000ff'; // 带有透明度的颜色 ctx.fillStyle = 'rgba(64, 0, 127, 0.5)'; /* 渐变填充 */ // 设置渐变的尺寸(参数分别为起始点的 x 和 y、终止点的 x 和 y) var gradient = ctx.createLinearGradient(0, 0, 170, 0); // 设置过渡色,第一个参数是渐变的位置,第二个参数是颜色 gradient.addColorStop(0, 'magenta'); gradient.addColorStop(0.5, 'blue'); gradient.addColorStop(1.0, 'red'); // 设置填充样式 ctx.fillStyle = gradient; /* 图片填充 */ // 创建图片 var image = new Image; image.src = '/path/to/image.png'; // 创建图片笔触,可以指定图片的平铺方式,这里是横向平铺 var pattern = ctx.createPattern(image, 'repeat-x'); // 设置笔触填充 ctx.fillStyle = pattern;
关于渐变,除了代码中提到的线性渐变以外,还有 createRadialGradient,也就是径向渐变。
设置完填充样式之后,就可以使用 fill 来填充啦!如果设置的是线条样式,那么就可以使用 stroke 来描边。
当然,对于线条样式,还有个额外的方法叫 lineWidth 可以用来控制线条的宽度。
文字
要想在画布上画文字,首先需要知道所使用的字体和字号:
ctx.font = '30px Verdana';
然后就可以通过 strokeText 或者 fillText 来对字体描边或者填充字体。
ctx.strokeText("Hello Coding!", 23, 33); ctx.fillText("Hello Coding!", 23, 66);
图片
在 Canvas 中绘制图片有三种方法:
// 指定绘制位置 ctx.drawImage(image, x, y); // 指定绘制位置和图像宽高 ctx.drawImage(image, x, y, width, height); // 指定剪裁区域、绘制位置和图像宽高 ctx.drawImage(image, sx, sy, swidth, sheight, x, y, width, height);
参数的含义依次如下:
image: 要使用的 Image、Canvas 或 Video sx: 可选,开始剪切的 x 坐标 sy: 可选,开始剪切的 y 坐标 swidth: 可选,被剪切图像的宽度 sheight: 可选,被剪切图像的高度 x: 在画布上放置图像的 x 坐标 y: 在画布上放置图像的 y 坐标 width: 可选,要使用的图像的宽度 height: 可选,要使用的图像的高度
画布设置
细心的同学可能会发现,刚才有些属性是直接对 ctx 变量做设置,例如 ctx.lineWidth,只要设置了它,那么后续画出来的线条全都是这么个宽度。
其实,Canvas 的设置项还有许多,例如我们可以直接移动画布、旋转画布、设置全局的绘制透明度等等。这些设置还可以随时保存和恢复。
要注意的一点是,所有已经画在画布上的东西,是已经定死了的,不管之后再次进行任何设置都不会再改变。这个很像 Windows 下的画图程序。
废话不多说,直接上代码:
// 移动画布,其实就是移动坐标系 ctx.translate(往右移动的量, 往下移动的量); // 旋转画布,旋转中心为坐标系原点 ctx.rotate(顺时针旋转的角度); // 以坐标系原点为中心缩放画布 ctx.scale(横向放大倍数, 纵向放大倍数); // 设置绘制透明度,如果 fillStyle 等属性设置了透明度则会叠加 ctx.globalAlpha(零到一的小数); // 设置全局组合操作 ctx.globalCompositeOperation = 'lighter'; // 保存当前设置 ctx.save(); // 恢复上次保存的设置 ctx.restore();
移动、旋转、缩放其实就是在控制绘图的坐标系,如果你在调用这三个方法的时候,脑子里时刻有一个带刻度的坐标系,效果会非常好。
実際、Canvas の座標変換は、コンピューター グラフィックスの知識である変換行列に従います。簡単に言うと、座標を行列とみなすことができ、その座標に対応する行列に変換行列を乗算することで座標変換を実現できる。計算の効率を高めるために、最初にいくつかの変換を組み合わせて変換行列を計算し、その後、transform 関数を使用して現在の座標系を直接変換するか、setTransform 関数を使用して座標系を初期状態にリセットしてから実行することができます。変革。変換行列の内容については、この記事の範囲から少し外れます。
グローバル結合操作は、PhotoShop の「混合オプション」に似ています。現在、一般的なブラウザーで統一されている実装方法は、source-over、source-atop、destination です。 -over、destination-out、lighter、xor。特定の動作は Mozilla の公式ドキュメントに記載されていますが、標準がまだ完全に決定されていないため、他のブラウザではすべての動作が Mozilla の標準と一致することは保証されません。一般的に、より一般的なのはソースオーバーで軽量であり、これら 2 つの標準はブラウザ業界で議論の余地がありません。
設定の保存と復元については、まず「スタック」というものを理解する必要があります。
スタックは一方向からのみ操作できる一次元配列です。スタックは最初は空です。この方向から要素を配列にプッシュできますが、この方向からは最後の要素 (スタックの最上位の要素) のみをポップアウトできます。それ以外に追加の操作はありません。もちろん、ポップの数はプッシュの数を超えることはできません。ポップがスタックの一番下に到達すると、スタックには要素がなくなり、この時点で再度ポップしても意味がないからです。スタックには、ブラケット マッチング、式の評価、深さ優先検索など、多くの用途があり、ほとんどの言語での関数呼び出しでもスタックが使用されます。
save 関数を呼び出すたびに、実際に現在のグローバル設定を特別なスタックにプッシュし、restore 関数を呼び出すたびに、最後に保存されたコンテンツを取り出して、それを使用して現在のグローバル設定を上書きします。スタックの一番上 これは、最後に保存されたコンテンツです。保存と復元は、たとえば、曲がった図形を描画してから、直立した図形を描画し続ける必要がある場合に便利です。この方法では、最初に保存を呼び出し、次に回転し、図形を描画した後に復元して続行することができます。他の図形を描きます。
実際、Canvas には多くのメソッドがあります。たとえば、toDataURL は現在のキャンバス上のコンテンツを 16 進数のデータ URL に変換し、getImageData は画像処理アルゴリズムで使用するために画像を RGBA 配列に直接変換し、putImageData は RGBA 配列を絵はキャンバスなどに表示されます。 JavaScript の定期的な更新 (できれば setInterval の代わりに requestAnimationFrame を使用) と組み合わせると、アニメーション効果を生成できます。インターネット上には、プログラマーが Canvas に基づいて独自の特殊効果や関数をより簡単に作成できる Canvas ライブラリも多数あります。ここで私が言いたいのは、みんなの想像力がどれほど強力であるか、Canvas がどれほど強力であるかです~