前回の記事ではキャンバス1の基本的な使い方をご覧ください。
1. 変換
変換する
- キャンバスでは、css のような css2D 変換に似たいくつかの効果を適用することもできます。
- 変位
- 文法:
ctx.translate(x, y)
- 注: 描画(ストロークまたは塗りつぶし)前に必ずディスプレイスメントを実行してください。
- 文法:
- ズーム
- 文法:
ctx.scale(x, y)
- 注: 描画する前に必ず拡大縮小してください (ストロークまたは塗りつぶし)。
- 文法:
- 回転する
- 文法:
ctx.rotate(弧度值)
- 角度からラジアンへの変換式:
弧度 = Math.PI/180*角度
- 角度からラジアンへの変換式:
- 注: 描画(ストロークまたは塗りつぶし)前に必ず回転してください。
- 回転の中心はキャンバスの 0,0 点であり、回転の中心はディスプレイスメントで変更できます。
- 文法:
- 知らせ:
- キャンバスのすべての変形操作は、特定の形状を操作するだけではなく、キャンバス全体を変形します。
- 複数のシェイプに対して異なる変換を実行する必要がある場合は、各描画前にブラシの状態を保存し、描画後にブラシの状態をリセットする必要があります。
- ブラシの状態を保存:
ctx.save();
- 一般的な存在と変換の前に
- ブラシの状態をリセット:
ctx.restore();
- 通常、変換後に存在します
- ブラシの状態を保存:
// 绘制两个矩形
ctx.strokeRect(100, 100, 100, 100);
ctx.strokeRect(300, 100, 100, 100);
// 对画布进行旋转
ctx.rotate(0.5);
ctx.strokeRect(100, 100, 100, 100);
ctx.strokeRect(300, 100, 100, 100);
// 将 旋转和其中一个矩形绘制 存储为一次记录
ctx.save();
ctx.rotate(0.5);
ctx.strokeRect(100, 100, 100, 100);
ctx.restore();
ctx.strokeRect(300, 100, 100, 100);
2. グラデーションカラー
- キャンバスのグラデーションカラーは、事前にグラデーション配色(カラー1からカラー2への遷移)を設定し、そのグラデーション配色を塗りつぶしスタイルに設定します。
- グラデーションフォーム
- 線形勾配
- グラデーションを作成します。
const lg = ctx.createLinearGradient(起点x坐标, 起点y坐标, 终点x坐标, 终点y坐标)
- グラデーションの範囲を指定する
- グラデーションカラーを追加します。
lg.addColorStop(0, 'red')
- 指定した位置に色を追加します。0 は開始座標を意味し、1 は終了座標を意味します。中央部分は自動的にグラデーション色で塗りつぶされます。
- グラデーションを作成します。
- 線形勾配
const canvas = document.querySelector(".mycanvas");
canvas.width = 800;
canvas.height = 400;
const ctx = canvas.getContext("2d");
const lg = ctx.createLinearGradient(0, 0, 800, 400);
lg.addColorStop(0, 'red');
lg.addColorStop(1, 'green');
ctx.fillStyle = lg;
ctx.fillRect(0, 0, 800, 400);
- 放射状グラデーション
- グラデーションを作成します。
const lg = ctx.createRadialGradient(x1, y1, r1, x2, y2, r2);
- x1: 開始円の中心の x 軸座標
- y1: 開始円の中心の y 軸座標
- r1: 開始円半径
- x2: 端円中心の x 軸座標
- y2: 端円の中心のy軸座標
- r2: 終端円半径
- グラデーションカラーを追加します。
lg.addColorStop(0, 'red')
- 同期勾配
- グラデーションを作成します。
const canvas = document.querySelector(".mycanvas");
canvas.width = 800;
canvas.height = 400;
const ctx = canvas.getContext("2d");
const lg = ctx.createRadialGradient(200, 200, 50, 200, 200, 200);
lg.addColorStop(0, 'red');
lg.addColorStop(1, 'green');
ctx.fillStyle = lg;
ctx.fillRect(0, 0, 800, 400);
- 複数の領域で異なるグラデーション
- 本質は、複数のグラデーション スキームのセットを構成し、それらをさまざまな形状に描画することです。
const canvas = document.querySelector(".mycanvas");
canvas.width = 800;
canvas.height = 400;
const ctx = canvas.getContext("2d");
const rg = ctx.createRadialGradient(200, 200, 50, 200, 200, 200);
rg.addColorStop(0, 'red');
rg.addColorStop(1, 'green');
ctx.fillStyle = rg;
ctx.fillRect(0, 0, 400, 400);
const lg = ctx.createLinearGradient(400, 0, 800, 0);
lg.addColorStop(0, 'blue');
lg.addColorStop(1, 'yellow');
ctx.fillStyle = lg;
ctx.fillRect(400, 0, 400, 400);
3. ベジェ曲線
- ベジェ曲線 (ベジェ曲線) は、コンピュータ グラフィックスにおいて非常に重要なパラメトリック曲線です。方程式によって曲線を記述します。方程式の最高次数に従って、線形ベジェ曲線と二次ベジェ曲線、三次ベジェ曲線、に分けられます。そして高次のベジェ曲線。
- ベジェ曲線はいくつかの点のパラメータを提供する必要があります。最初の点は曲線の開始点と終了点です。
- 制御点の数が 0 の場合、それを線形ベジェと呼びます。
- 制御点の数が 1 の場合、それは 2 次ベジェ曲線です。
- 制御点の数が 2 の場合、3 次ベジェ曲線などとなります。
- 2次ベジェ曲線
- 実際には、3 つの点から 2 本の直線が引かれます。
- 次に、各行の先頭から同時に開始し、最後に向かって移動し、比例してポイントを獲得します。これらの点が再接続されて、n - 1 本の直線が生成されます。
- このようにして、直線になるまで同じ操作を続け、曲線が通過する点である点を比例的に取得します。
- スケールを少し (0 から 1) 大きくすると、曲線の中央にあるすべての点が得られ、最終的に完全な曲線が描画されます。
- 3次ベジェ曲線を見てみましょう
- 2次ベジェ曲線と同じですが、制御点の数が2つになります。
- Canvas では、多くのポイントを手動で計算する必要はありません。Canvas は関連する API を直接提供します。
- 2 次ベジェ曲線:
ctx.quadraticCurveTo(p1x, p1y, p2x, p2y)
- 3 次ベジェ曲線:
ctx.bezierCurveTo(p1x, p1y, p2x, p2y, p3x, p3y)
- その前に、moveTo を使用して p0 の位置を決定する必要があります
- 2 次ベジェ曲線:
二次注文
const cvs = document.querySelector(".cvs");
cvs.width = 400;
cvs.height = 400;
const ctx = cvs.getContext("2d");
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.quadraticCurveTo(300, 200, 200, 300);
ctx.stroke();
三次
const cvs = document.querySelector(".cvs");
cvs.width = 400;
cvs.height = 400;
const ctx = cvs.getContext("2d");
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.bezierCurveTo(60, 80, 150, 30, 170, 150);
ctx.stroke();
多段式
ctx.beginPath();
ctx.moveTo(75, 25);
ctx.quadraticCurveTo(25, 25, 25, 62.5);
ctx.quadraticCurveTo(25, 100, 50, 100);
ctx.quadraticCurveTo(50, 120, 30, 125);
ctx.quadraticCurveTo(60, 120, 65, 100);
ctx.quadraticCurveTo(125, 100, 125, 62.5);
ctx.quadraticCurveTo(125, 25, 75, 25);
ctx.stroke();
ctx.moveTo(75, 40);
ctx.bezierCurveTo(75, 37, 70, 25, 50, 25);
ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5);
ctx.bezierCurveTo(20, 80, 40, 102, 75, 120);
ctx.bezierCurveTo(110, 102, 130, 80, 130, 62.5);
ctx.bezierCurveTo(130, 62.5, 130, 25, 100, 25);
ctx.bezierCurveTo(85, 25, 75, 37, 75, 40);
ctx.fill();
4.絵を描く
- 画像の作成 (非キャンバス操作)
- 画像オブジェクトを作成します。
const img = new Image();
- リソースアドレスを設定します。
img.src = "图片地址"
- リソースの読み込みが完了しました:
img.onload = function(){ / * 图片加载完成 */ }
- 画像オブジェクトを作成します。
- キャンバスに絵を描く
- 3 つのパラメータ:
gd.drawImage(图片对象, x, y)
- キャンバスの X、Y 座標から描画を開始します
- 3 つのパラメータ:
const canvas = document.querySelector(".mycanvas");
canvas.width = 800;
canvas.height = 400;
const ctx = canvas.getContext("2d");
const img = new Image();
img.src = "../1.png";
img.onload = function(){
ctx.drawImage(this, 0, 100);
}
- 5 つのパラメータ:
gd.drawImage(图片对象, x, y, w, h)
- キャンバスのx、y座標から描画を開始し、幅w、高さhの領域まで描画します
const canvas = document.querySelector(".mycanvas");
canvas.width = 800;
canvas.height = 400;
const ctx = canvas.getContext("2d");
const img = new Image();
img.src = "../1.png";
img.onload = function(){
ctx.drawImage(this, 0, 100, 200, 200);
}
- 9 つのパラメータ:
gd.drawImage(图片对象, sx, sy, sw, sh, dx, dy, dw, dh)
- s = ソース元の画像の位置の幅と高さ
- d = 目的地 ターゲット (キャンバス) がどこに描かれ、その大きさがどれくらいであるか
const canvas = document.querySelector(".mycanvas");
canvas.width = 800;
canvas.height = 400;
const ctx = canvas.getContext("2d");
const img = new Image();
img.src = "../1.png";
// 图片资源宽高
const imgW = 128;
const imgH = 194;
img.width = 128;
img.height = 194;
img.onload = function(){
ctx.drawImage(this, 0, 0, imgW/4, imgH/4, 0, 100, imgW/4, imgH/4);
}
5. イベント
- キャンバスにはイベント システムはありません。キャンバス要素にイベントを追加し、イベント オブジェクトと連携することによって、イベント領域を手動で検出することしかできません。
- 長方形の検出式:
点击x > 矩形x && 点击x < 矩形x + 矩形w && 点击y > 矩形y && 点击y < 矩形y + 矩形h
- 円検出式:
- ピタゴラスの定理の使用: a^2 + b^2 = c^2
- a = 中心 x - x をクリック
- b = y の中心 - y をクリックします
- c = Math.sqrt( a * a + b * b )
- c < r の場合、円形領域内
- 自動検出
ctx.isPointInPath(x, y)
- 戻り値: 指定された座標がパス範囲内にあるかどうかを示すブール値
六、輸出(理解)
download.onclick = function(){
// 将canvas数据转成base64数据
const base64 = canvas.toDataURL("image/png");
// 将base64数据解码
const strBase64 = atob( base64.split(",")[1] );
// 创建utf-8原始数据(长度为base64解码后的字符长度)
const utf_8 = new Uint8Array(strBase64.length);
// 将base64解码后的数据转成Unicode编码后,存入utf-8数组
for(let n=0;n<strBase64.length;n++){
utf_8[n] = strBase64.charCodeAt(n)
}
// 根据utf-8数据,创建文件对象
const file = new File([utf_8], "测试图片", {
type:"image/png"});
// 根据文件对象创建url字符
const href = URL.createObjectURL(file);
// 准备a标签,用于下载文件
const a = document.createElement("a");
a.href = href;
a.download = "测试图片";
document.body.appendChild(a);
a.click();
// 删除a标签
a.remove();
// 释放指向文件资源的url字符
URL.revokeObjectURL(href);
}
7. まとめ
- 変位:
ctx.translate(x, y)
- 回転:
ctx.rotate(弧度值)
- ズーム:
ctx.scale(x, y)
- ブラシの状態を保存:
ctx.save()
- ブラシの状態をリセット:
ctx.restore()
- 線形グラデーションを作成します。
ctx.createLinearGradient(起点x坐标, 起点y坐标, 终点x坐标, 终点y坐标)
- 放射状のグラデーションを作成します。
const lg = ctx.createRadialGradient(x1, y1, r1, x2, y2, r2);
- グラデーションカラーを追加します。
lg.addColorStop(0, 'red')
- 絵を描きます:
gd.drawImage(图片对象, x, y)
- 指定された座標が特定のパス範囲内にあるかどうかを確認します。
ctx.isPointInPath(x, y)
八、練習する
- 機械式時計
- スポーティな小男
- 飛行機戦争
- 折れ線グラフ