詳細キャンバス 01 - 基本的なグラフィックの描画

キャンバス環境をセットアップしたので、キャンバス上に描画する方法を詳しく見てみましょう。この記事を読み終えるまでに、長方形、三角形、線、円弧、曲線の描き方を学び、これらの基本的な形状に慣れてきたことでしょう。Canvas にオブジェクトを描画する前に、パスをマスターする必要があります。その方法を見てみましょう。

#グリッド

描画を開始する前に、キャンバス グリッド (キャンバス グリッド) と座標空間を理解する必要があります。前のページの HTML テンプレートには、幅 150 ピクセル、高さ 150 ピクセルの Canvas 要素があります。右に示すように、キャンバス要素はデフォルトでグリッドで覆われています。一般に、グリッド内の 1 つのセルは、キャンバス要素内の 1 つのピクセルに相当します。グリッドの開始点は左上隅 (座標 (0,0)) です。すべての要素は原点を基準にして配置されます。したがって、図の青い四角の左上の座標は、左からxピクセル(X軸)、上からyピクセル(Y軸)です(座標は(x,y))。レッスンの最後に、原点を別の座標に変換し、メッシュを回転し、スケールします。現在も元の設定を使用しています。

#長方形を描く

SVG とは異なり、canvas は、長方形とパス (一連の点で接続された線分) という 2 つの形式のグラフィック描画のみをサポートします。他のタイプのグラフィックスはすべて、1 つまたは複数のパスを組み合わせて形成されます。ただし、複雑なグラフィックスの描画を可能にするパス生成方法が多数あります。

まず、長方形の描画に戻ります。Canvas には、長方形を描画するための 3 つのメソッドが用意されています。

fillRect(x, y, 幅, 高さ)

塗りつぶされた長方形を描く

ストロークRect(x, y, 幅, 高さ)

長方形の境界線を描く

ClearRect(x, y, 幅, 高さ)

指定した矩形領域を消去し、消去した部分を完全に透明にします。

上記の各メソッドには同じパラメータが含まれています。x と y は、キャンバス上に描画される長方形の左上隅の座標 (原点を基準とした座標) を指定します。幅と高さは長方形の寸法を設定します。

以下のdraw()関数は前のページから取得したものなので、上記の3つの関数を使用してみましょう。

#長方形の

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    ctx.fillRect(25, 25, 100, 100);
    ctx.clearRect(45, 45, 60, 60);
    ctx.strokeRect(50, 50, 50, 50);
  }
}

fillRect() 関数は、一辺の長さが 100 ピクセルの黒い正方形を描画します。clearRect() 関数は、正方形の中心から 60 x 60 ピクセルの正方形を消去し、ストロークRect() は、消去された領域内に50 x 50 の正方形の境界線を生成します。

次に、clearRect() の 2 つのオプションのメソッドを見て、レンダリングされたグラフィックスの塗りつぶしの色とストロークの色を変更する方法を学びます。

上記 3 つの関数は、次のセクションで紹介するパス関数とは異なり、描画直後にキャンバス上に表示され、すぐに有効になります。

#長方形

キャンバス上に直接四角形を描画するための 3 つの追加メソッドには、四角形の描画から始めたように、現在のパスに四角形のパスを追加するect() メソッドもあります。

rect(x, y, 幅, 高さ)

左上隅の座標が (x, y)、幅と高さが幅と高さである長方形を描画します。

このメソッドが実行されると、moveTo() メソッドは自動的に座標パラメーター (0,0) を設定します。つまり、現在のストロークは自動的にデフォルトの座標にリセットされます。

#パスを描画します

グラフの基本要素はパスです。パスは、さまざまな色と幅の線分または曲線で接続されたさまざまな形状の点の集合です。パス、またはサブパスさえも閉じられます。パスを使用して形状を描画するには、いくつかの追加手順が必要です。

  1. まず、パスの開始点を作成する必要があります。
  2. 次に、描画コマンドを使用してパスを描画します。
  3. その後、パスを閉じます。
  4. パスが生成されたら、パス領域をストロークするか塗りつぶすことでシェイプをレンダリングできます。

使用する関数は次のとおりです。

beginPath()

新しいパスを作成します。パスが生成されると、そのパスにグラフィック描画コマンドが送られてパスが生成されます。

クローズパス()

パスを閉じた後、グラフィックス描画コマンドはコンテキストにリダイレクトされます。

脳卒中()

線を通して図形の輪郭を描きます。

塗りつぶし()

パスのコンテンツ領域を塗りつぶして立体形状を生成します。

パスを生成する最初のステップは beginPath() と呼ばれます。基本的に、パスはリスト内の多数のサブパスで構成され、すべてのサブパス (線、円弧など) がグラフを構成します。そして、このメソッドが呼び出されるたびに、リストはクリアされてリセットされ、新しいグラフィックスを再描画できるようになります。

注: 現在のパスは空です。つまり、beginPath() を呼び出した後、またはキャンバスが作成されたばかりのとき、最初のパス構築コマンドは、実際の内容に関係なく、通常は moveTo() とみなされます。このため、ほとんどの場合、パスを設定した後に開始場所を指定します。

2 番目のステップは、関数を呼び出して描画パスを指定することです。これについては、この記事で後ほど説明します。

3 番目は閉じたパス closePath() ですが、これは必須ではありません。このメソッドは、現在の点から開始点まで線を描くことによって形状を閉じます。グラフがすでに閉じている場合、つまり現在の点が開始点である場合、この関数は何も行いません。

注:  fill() 関数を呼び出すと、閉じられていないすべての図形が自動的に閉じられるため、closePath() 関数を呼び出す必要はありません。ただし、ストローク()が呼び出されたときに自動的に閉じられません。

#三角形を描く

たとえば、三角形を描画するコードは次のとおりです。

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    ctx.beginPath();
    ctx.moveTo(75, 50);
    ctx.lineTo(100, 75);
    ctx.lineTo(100, 25);
    ctx.fill();
  }
}

#ストロークの移動

実際には何も描画せず、上で説明したパス リストの一部である非常に便利な関数は moveTo() です。あるいは、ペンや鉛筆の先端をある点から別の点に動かしながら、紙の上で作業することを想像することもできます。

moveTo(x, y)

ストロークを指定された座標 x および y に移動します。

キャンバスが初期化されるか、beginPath() が呼び出された後、通常は moveTo() 関数を使用して開始点を設定します。moveTo() を使用して不連続なパスを描画することもできます。以下のスマイリーの例を見てください。moveTo() メソッドが使用されている場所 (赤線) をマークしました。

以下のコードスニペットで試してみることができます。それを前のdraw()関数にコピーするだけです。

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

    ctx.beginPath();
    ctx.arc(75, 75, 50, 0, Math.PI * 2, true); // 绘制
    ctx.moveTo(110, 75);
    ctx.arc(75, 75, 35, 0, Math.PI, false);   // 口 (顺时针)
    ctx.moveTo(65, 65);
    ctx.arc(60, 65, 5, 0, Math.PI * 2, true);  // 左眼
    ctx.moveTo(95, 65);
    ctx.arc(90, 65, 5, 0, Math.PI * 2, true);  // 右眼
    ctx.stroke();
  }
}

#行_

直線を描くには、メソッド lineTo() を使用する必要があります。

lineTo(x, y)

現在の位置から指定された x および y 位置まで線を描画します。

このメソッドには 2 つのパラメーターがあります。x と y は、線が終了する座標系の点を表します。開始点は前に描画されたパスを基準にし、前のパスの終了点は次の開始点になります。開始点は moveTo() 関数によって変更することもできます。

次の例では、塗りつぶされた三角形とストロークされた三角形の 2 つの三角形を描画します。

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){
  var ctx = canvas.getContext('2d');

  // 填充三角形
  ctx.beginPath();
  ctx.moveTo(25, 25);
  ctx.lineTo(105, 25);
  ctx.lineTo(25, 105);
  ctx.fill();

  // 描边三角形
  ctx.beginPath();
  ctx.moveTo(125, 125);
  ctx.lineTo(125, 45);
  ctx.lineTo(45, 125);
  ctx.closePath();
  ctx.stroke();
  }
}

これは、beginPath() 関数を呼び出して、新しいシェイプ パスを描画する準備をすることから始まります。次に、moveTo()関数を使用して、目的の位置に移動します。次に、以下では、三角形の 2 つの辺を形成する 2 つの線分が描かれています。

#アーク_

円弧または円を描画するには、arc() メソッドを使用します。もちろん arcTo() を使用することもできますが、これは実装があまり信頼できないため、ここでは紹介しません。

arc(x, y, 半径, startAngle, endAngle, 反時計回り)

startAngleからendAngleまで(x,y)を中心、radiusを半径とする円弧(円)を描き、反時計回り(デフォルトは時計回り)で生成します。

arcTo(x1, y1, x2, y2, 半径)

指定された制御点と半径に従って円弧を描き、2 つの制御点を直線で接続します。

ここでは、円弧メソッドの詳細を説明します。このメソッドには 6 つのパラメーターがあります。x、y は、円弧が描かれる円の中心の座標です。radiusは半径です。startAngle パラメータと endAngle パラメータは、開始円弧と終了円弧をラジアンで定義します。これらはすべて X 軸を基準としています。パラメータ反時計回りはブール値です。true の場合は反時計回り、それ以外の場合は時計回りです。

備考:  arc() 関数の角度の単位は度ではなくラジアンです。角度とラジアンのjs式:

ラジアン = (Math.PI/180)*角度。

次の例は上記よりも少し複雑で、12 個の異なる角度と塗りつぶされた円弧が以下に描かれています。

次の 2 つの for ループは、円弧の行と列 (x, y) 座標を生成します。BeginPath() は各アークの開始時に呼び出されます。コードでは各円弧のパラメータを変数にしていますが、実際のプログラミングではその必要はありません。

X、Y 座標は可変です。半径 (radius) と開始角度 (startAngle) は両方とも固定です。終了角度 (endAngle) は、最初の列 (半円) で 180 度から始まり、列ごとに 90 度ずつ増加します。最後の列は完全な円を形成します。

時計回りのステートメントは 1 行目と 3 行目に時計回りの円弧として作用し、反時計回りのステートメントは 2 行目と 4 行目に反時計回りの円弧として作用します。if ステートメントは、1 行目と 2 行目で円弧を描き、次の 2 行でパスを塗りつぶします。

注: この例に必要なキャンバス サイズは、このページの他の例よりわずかに大きく、150 x 200 ピクセルです。

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

    for(var i = 0; i < 4; i++){
      for(var j = 0; j < 3; j++){
        ctx.beginPath();
        var x = 25 + j * 50; // x 坐标值
        var y = 25 + i * 50; // y 坐标值
        var radius = 20; // 圆弧半径
        var startAngle = 0; // 开始点
        var endAngle = Math.PI + (Math.PI * j) / 2; // 结束点
        var anticlockwise = i % 2 == 0 ? false : true; // 顺时针或逆时针

        ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

        if (i>1){
          ctx.fill();
        } else {
          ctx.stroke();
        }
      }
    }
  }
}

#arcTo メソッドを使用する

以下は、円弧を描くための簡単なコード スニペットです。基点は青、2 つの制御点は赤です。

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

ctx.setLineDash([])
ctx.beginPath();
ctx.moveTo(150, 20);
ctx.arcTo(150,100,50,20,30);
ctx.stroke();

ctx.fillStyle = 'blue';
// base point
ctx.fillRect(150, 20, 10, 10);

ctx.fillStyle = 'red';
// control point one
ctx.fillRect(150, 100, 10, 10);
// control point two
ctx.fillRect(50, 20, 10, 10);
//
ctx.setLineDash([5,5])
ctx.moveTo(150, 20);
ctx.lineTo(150,100);
ctx.lineTo(50, 20);
ctx.stroke();
ctx.beginPath();
ctx.arc(120,38,30,0,2*Math.PI);
ctx.stroke();

#二次ベジェ曲線と三次ベジェ曲線

次に非常に便利なタイプのパスはベジェ曲線です。二次ベジェ曲線と三次ベジェ曲線はどちらも非常に便利で、通常、複雑で規則的なグラフィックを描画するために使用されます。

二次曲線To(cp1x, cp1y, x, y)

二次ベジェ曲線を描きます。cp1x、cp1y は制御点、x、y は終点です。

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

3 次ベジェ曲線を描きます。cp1x、cp1y は制御点 1、cp2x、cp2y は制御点 2、x、y は終点です。

右の図は、この 2 つの関係をよく示しています。2 次ベジェ曲線には始点 (青)、終点 (青)、制御点 (赤) があり、3 次ベジェ曲線には 2 つの制御点があります。

パラメータ x、y は、両方のメソッドの終点座標です。cp1x、cp1y は座標の最初の制御点、cp2x、cp2y は座標の 2 番目の制御点です。

Adobe Illustrator などのベクター ソフトウェアとは異なり、描画した曲線から直接視覚的なフィードバックが得られないため、2 次および 3 次のベジェ曲線を扱うのはやや困難です。このため、複雑なグラフィックを描画することが非常に困難になります。次の例では、いくつかの単純で通常のグラフィックを描画しますが、時間と忍耐力があれば、多くの複雑なグラフィックを描画することもできます。

次の例はそれほど難しいことではありません。これら 2 つの例では、ベジェ曲線を連続的に描き、最終的に複雑なグラフィックスを形成します。

#二次ベジェ曲線

この例では、複数のベジェ曲線を使用して吹き出しをレンダリングします。

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    // 二次贝塞尔曲线
    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();
   }
}

# 3次ベジェ曲線

この例では、ベジェ曲線を使用してハートの形を描画します。

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

     //三次贝塞尔曲线
    ctx.beginPath();
    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();
  }
}

#

#併用

これまでの各例の各シェイプでは、1 種類のパスのみを使用しました。ただし、グラフを描画しても、使用回数や種類が制限されるわけではありません。最後の例では、すべてのパス関数を組み合わせて、有名なゲームを再現してみましょう。

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

    roundedRect(ctx, 12, 12, 150, 150, 15);
    roundedRect(ctx, 19, 19, 150, 150, 9);
    roundedRect(ctx, 53, 53, 49, 33, 10);
    roundedRect(ctx, 53, 119, 49, 16, 6);
    roundedRect(ctx, 135, 53, 49, 33, 10);
    roundedRect(ctx, 135, 119, 25, 49, 10);

    ctx.beginPath();
    ctx.arc(37, 37, 13, Math.PI / 7, -Math.PI / 7, false);
    ctx.lineTo(31, 37);
    ctx.fill();

    for(var i = 0; i < 8; i++){
      ctx.fillRect(51 + i * 16, 35, 4, 4);
    }

    for(i = 0; i < 6; i++){
      ctx.fillRect(115, 51 + i * 16, 4, 4);
    }

    for(i = 0; i < 8; i++){
      ctx.fillRect(51 + i * 16, 99, 4, 4);
    }

    ctx.beginPath();
    ctx.moveTo(83, 116);
    ctx.lineTo(83, 102);
    ctx.bezierCurveTo(83, 94, 89, 88, 97, 88);
    ctx.bezierCurveTo(105, 88, 111, 94, 111, 102);
    ctx.lineTo(111, 116);
    ctx.lineTo(106.333, 111.333);
    ctx.lineTo(101.666, 116);
    ctx.lineTo(97, 111.333);
    ctx.lineTo(92.333, 116);
    ctx.lineTo(87.666, 111.333);
    ctx.lineTo(83, 116);
    ctx.fill();

    ctx.fillStyle = "white";
    ctx.beginPath();
    ctx.moveTo(91, 96);
    ctx.bezierCurveTo(88, 96, 87, 99, 87, 101);
    ctx.bezierCurveTo(87, 103, 88, 106, 91, 106);
    ctx.bezierCurveTo(94, 106, 95, 103, 95, 101);
    ctx.bezierCurveTo(95, 99, 94, 96, 91, 96);
    ctx.moveTo(103, 96);
    ctx.bezierCurveTo(100, 96, 99, 99, 99, 101);
    ctx.bezierCurveTo(99, 103, 100, 106, 103, 106);
    ctx.bezierCurveTo(106, 106, 107, 103, 107, 101);
    ctx.bezierCurveTo(107, 99, 106, 96, 103, 96);
    ctx.fill();

    ctx.fillStyle = "black";
    ctx.beginPath();
    ctx.arc(101, 102, 2, 0, Math.PI * 2, true);
    ctx.fill();

    ctx.beginPath();
    ctx.arc(89, 102, 2, 0, Math.PI * 2, true);
    ctx.fill();
  }
}

// 封装的一个用于绘制圆角矩形的函数。

function roundedRect(ctx, x, y, width, height, radius){
  ctx.beginPath();
  ctx.moveTo(x, y + radius);
  ctx.lineTo(x, y + height - radius);
  ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
  ctx.lineTo(x + width - radius, y + height);
  ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
  ctx.lineTo(x + width, y + radius);
  ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
  ctx.lineTo(x + radius, y);
  ctx.quadraticCurveTo(x, y, x, y + radius);
  ctx.stroke();
}

上記のコードは実際には非常に簡単に理解できるため、詳しくは説明しません。重要な点は、fillStyle プロパティとカプセル化関数 (この例ではroundedRect()) が描画コンテキストで使用されることです。ラッパー関数の使用は、コードのサイズと複雑さを軽減するのに非常に役立ちます。

fillStyle については、このレッスンの後半で詳しく説明します。この章では、fillStyle スタイルで行ったのは、塗りつぶしの色をデフォルトの黒から白に変更し、その後再び黒に変更することだけでした。

# Path2D オブジェクト

前の例で見たように、一連のパスおよび描画コマンドを使用して、キャンバス上のオブジェクトを「ペイント」できます。コードを簡素化しパフォーマンスを向上させるために、新しいブラウザでは Path2D オブジェクトを使用して描画コマンドをキャッシュまたは記録できるため、パスをすばやく確認できます。

Path2D オブジェクトを生成するにはどうすればよいですか?

パス2D()

Path2D() は、新しく初期化された Path2D オブジェクトを返します (パスを変数として使用して、パスのコピーを作成するか、変数として SVG パス データを含む文字列を使用して)。

前に見たように、moveTo、rect、arc、quadraticCurveTo などのすべてのパス メソッドを Path2D で使用できます。

Path2D API は、パスを結合するメソッドとして addPath を追加します。これは、複数の要素からオブジェクトを作成する場合に便利です。例えば:

Path2D.addPath(パス [, 変換])

現在のパスにパスを追加します (場合によっては変換行列を追加します)。

# Path2D の例

この例では、長方形と円を作成しました。これらはすべて、後で使用するために Path2D オブジェクトとして保存されます。新しい Path2D API では、現在のパスの代わりに Path2D オブジェクトを使用するようにいくつかのメソッドが更新されました。ここでは、パス パラメーターを使用してストロークと塗りつぶしを使用して、キャンバス上にオブジェクトを描画できます。

function draw() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

    var rectangle = new Path2D();
    rectangle.rect(10, 10, 50, 50);

    var circle = new Path2D();
    circle.moveTo(125, 35);
    circle.arc(100, 35, 25, 0, 2 * Math.PI);

    ctx.stroke(rectangle);
    ctx.fill(circle);
  }
}

#SVG パスを使用する

新しい Path2D API のもう 1 つの強力な機能は、SVG パス データを使用してキャンバス上のパスを初期化することです。これにより、パスを取得し、SVG またはキャンバスとして再利用できるようになります。

このパスは、まず点 (M10 10) に移動し、次に水平に 80 単位 (h 80)、次に下に 80 単位 (v 80)、次に左に 80 単位 (h -80) 移動し、開始点 (z) に戻ります。 。

var p = new Path2D("M10 10 h 80 v 80 h -80 Z");

おすすめ

転載: blog.csdn.net/qq_59747594/article/details/131350748