描画を開始する前に、キャンバスグリッドまたはコーディネートスペースについて話す必要があります。前のページのHTMLテンプレートには、幅150ピクセル、高さ150ピクセルのキャンバス要素がありました。デフォルトのグリッドがオーバーレイしてこの画像を描画しました。通常、グリッド内の1ユニットは、キャンバスの1ピクセルに対応します。このグリッドの起源は、左上隅(座標(0,0))に配置されます。すべての要素は、この起源に関連して配置されます。したがって、青い正方形の左上隅の位置は、左からxピクセルになり、上部からyピクセル(座標(x、y))になります。このチュートリアルの後半では、原点を別の位置に翻訳し、グリッドを回転させ、さらにスケーリングする方法を確認します。今のところ、デフォルトに固執します。
実際に開始する前に、キャンバスのグリッドスペースまたは調整スペースを探索する必要があります。前のページには、HTMLテンプレートには幅が150ピクセル、高さは150ピクセルです。右側の写真に示されているように、画面上のデフォルトのグリッドをオーバーレイします。通常、グリッドの1つのセルは、キャンバス上の1つのピクセルに対応します。グリッドの起源は、左上隅(座標(0,0))に配置されます。写真内のすべてのオブジェクトの位置は、この起源に関連しています。このようにして、左上隅の青い正方形の位置は、左からxピクセル、上部からyピクセル(座標(x、y))です。次のチュートリアルでは、原点を移動し、グリッドを回転させてスケーリングする方法を学びます。ただし、デフォルトの状態を使用します。
SVGとは異なり、Canvasは1つの原始的な形状である長方形のみをサポートします。他のすべての形状は、1つ以上のパスを組み合わせて作成する必要があります。幸運なことに、非常に複雑な形状を構成することを可能にするパス描画関数のコレクションがあります。
SVGとは異なり、Canvasは1つの基本的な形状のみをサポートしているため、他の形状は1つ以上のパスで構成されます。幸いなことに、かなり複雑な形状を描くことができるパス描画関数のセットがあります。
まず、長方形を見てみましょう。キャンバスに長方形を描く3つの機能があります。
まず長方形を見てみましょう。長方形を描くための3つの機能があります。
fillrect (x、y、幅、高さ):塗りつぶされた長方形を描きますストラーク(x、y、幅、高さ):長方形の輪郭を描きますClearRect (x、y、幅、高さ):指定された領域をクリアし、完全に透明にしますこれらの3つの関数のそれぞれは、同じパラメーターを取ります。 xとyは、長方形の左上隅のキャンバス(原点と比較して)上の位置を指定します。幅と高さはかなり明白です。これらの機能が動作しているのを見てみましょう。
それらはすべて4つのパラメーターを受け入れ、xとyは長方形の左上隅の位置(原点に対して)を指定し、幅と高さは長方形の幅と高さです。わかりました、いくつかの実用的な戦いをしましょう。
以下は前のページのdraw()関数ですが、上記の3つの関数を追加しました。
以下は、前のページのテンプレートのdraw()関数ですが、上記の3つの関数が追加されています。
例を表示します
function draw(){var canvas = document.getElementById( 'Tutorial'); 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関数は、大きな黒い正方形100x100ピクセルを引きます。 clearRect関数は中心から60x60ピクセルの正方形を除去し、最後にストラークはクリアされた正方形の内側に長方形のアウトライン50x50ピクセルを描画します。次のページでは、ClearRect関数の2つの代替方法が表示され、レンダリングされた形状の色とストロークスタイルを変更する方法も確認します。
結果は右側の結果と同じでなければなりません。 FillRect関数は大きな黒い長方形(100x100)を引き、クリアレクト関数は中央の60x60サイズの正方形をクリアし、ストラーク関数はクリアされた空間の50x50長方形の境界の輪郭を描きます。次のページでは、clearRect関数に似た2つの他の方法と、図の塗りつぶしと境界の色を変更する方法が表示されます。
次のセクションで表示されるパス関数とは異なり、3つの長方形関数すべてがキャンバスにすぐに引き付けられます。
次のセクションのパス関数とは異なり、これらの3つの関数の効果はすぐにキャンバスに反映されます。
パスを使用して形状を作成するには、いくつかの余分なステップが必要です。
長方形を描くのとは異なり、パスを描くにはいくつかの追加のステップが必要です。
beginpath () closepath ()脳卒中()埋める()パスを作成する最初のステップは、BeginningPathメソッドを呼び出すことです。内部的には、パスは、一緒に形成されるサブパス(線、アークなど)のリストとして保存されます。この方法が呼び出されるたびに、リストがリセットされ、新しい形状の描画を開始できます。
最初のステップは、BeginPathでパスを作成することです。メモリでは、パスはサブパスのセット(線、アークなど)の形で保存され、一緒にグラフを形成します。 BeginPathが呼び出されるたびに、SubPathグループがリセットされ、新しいグラフを描画できます。
2番目のステップは、描画するパスを実際に指定する方法を呼び出すことです。すぐに表示されます。
2番目のステップは、実際にパスの一部を描くことです。これはすぐに表示されます。
3番目の、およびオプションのステップは、ClosePathメソッドを呼び出すことです。この方法は、現在のポイントから開始まで直線を描画することにより、形状を閉じようとします。形状が既に閉じられているか、リストに1つのポイントしかない場合、この関数は何もしません。
3番目のステップは、ClosePathメソッドを呼び出すことです。これは、現在のエンドポイントを開始エンドポイントに直線で接続してパスを閉じることですが、グラフが既に閉じているか、1つのポイントしかない場合、何もしません。このステップは必要ありません。
最後のステップは、ストロークおよび/または充填方法を呼び出すことです。これらのいずれかを呼び出すと、実際にキャンバスに形状が描かれます。ストロークは輪郭のある形状を描画するために使用され、塗りつぶしは固体の形状をペイントするために使用されます。
最後のステップは、ストロークまたは充填方法を呼び出すことです。この時点で、グラフは実際にキャンバスに描かれています。ストロークは姿を描く境界線であり、塗りつぶしはそれをしっかりした姿で埋めます。
注:塗りつぶしメソッドを呼び出すと、開いた形状は自動的に閉じられ、ClosePathメソッドを使用する必要はありません。注:塗りつぶしが呼び出されると、Closepathを呼び出すことなく、開いたパスが自動的に閉じられます。描画シンプルな形状(三角形)のコードは、このようなものになります。
単純な図(三角形など)を描画するためのコードは次のとおりです。
ctx.beginpath(); ctx.moveto(75,50); ctx.lineto(100,75); ctx.lineto(100,25); ctx.fill();
実際には何も描かれていないが、上記のパスリストの一部である非常に有用な機能の1つは、Moveto関数です。おそらく、これを紙の上のある場所からペンや鉛筆を持ち上げて、次の場所に置くと考えることができます。
Movetoは非常に便利な方法です。それは何も描くのに使用することはできませんが、それはパスを描くための実用的な方法の一部です。ペンを持ち上げて、あるポイントから別のポイントに移動するプロセスと考えることができます。
Moveto (x、y)Moveto関数は、新しい出発点の座標であるxとyの2つの引数を取ります。
パラメーターとしてxとy(新しい座標位置)を受け入れます。
キャンバスが初期化されるか、BeginPathメソッドが呼び出されると、開始点が座標(0,0)に設定されます。ほとんどの場合、Movetoメソッドを使用して、どこか別の場所に出発点を配置します。 Movetoメソッドを使用して、接続されていないパスを描画することもできます。右側のスマイリーフェイスを見てください。 Movetoメソッド(赤い線)を使用した場所をマークしました。
キャンバスが初期化されるか、BeginPathが呼び出されると、開始座標設定は原点(0,0)です。ほとんどの場合、Movetoメソッドを使用して、開始座標を他の場所に移動するか、不連続なパスを描画します。右側の笑顔の顔を見てください。赤い線は、Movetoを使用して移動する軌跡です。
これを自分で試すには、以下のコードスニペットを使用できます。以前に見た描画関数に貼り付けてください。
次のコードを試して、それを前に使用した抽選関数に貼り付けて、効果を確認してください。
ctx.beginpath(); ctx.arc(75,75,50,0、math.pi*2、true); // outer Circuitx.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); //左eyectx.moveto(95,65); ctx.arc(90,65,5,0、math.pi*2、true); //右eyectx.stroke();注:Movetoメソッドを削除して、接続ラインを確認します。注:ARC関数とそのパラメーターの説明については、以下を参照してください。注: Movetoメソッドにコメントして、接続された行を観察できます。注: ARCメソッドの使用を以下に示します。
直線を描くには、Linetoメソッドを使用します。
Linetoメソッドを使用して、直線を描画します。
Lineto (x、y)この方法は、ラインのエンドポイントの座標であるxとyの2つの引数を取ります。出発点は、前の描画パスに依存します。ここで、前のパスの終点は次の場合の出発点です。
Linetoメソッドは、エンドポイントの座標(x、y)をパラメーターとして受け入れます。開始座標は、前のパスに依存します。前のパスの終点は、現在のパスの開始点です。開始座標は、Movetoメソッドを介して設定することもできます。
以下の例では、2つの三角形が描画され、1つは満たされ、もう1つは概説されています。 (結果は右側の画像に表示されます)。最初に、新しい形状パスを開始するためにBeginPathメソッドが呼び出されます。次に、Movetoメソッドを使用して、開始点を目的の位置に移動します。この2本の線の下には、三角形の両側を構成する2本の線が描かれています。
例(右側の写真に示されているように)は2つの三角形で、1つは固体と描画されたエッジで満たされています。最初に、BeginPathメソッドを呼び出して新しいパスを作成し、Movetoメソッドを使用して開始座標を目的の位置に移動し、2つの直線線を描画して三角形の2つの辺を形成します。
満たされた三角形とstrokedされた三角形の違いに気付くでしょう。これは、上記のように、パスが満たされたときに形状が自動的に閉じられるためです。 strokedされた三角形のためにこれを行った場合、完全な三角形ではなく、2本の線のみが描かれていたでしょう。
塗りつぶしとストロークの描画三角形の違いに気付くことができます。上記のように、塗りつぶしを使用したパスは自動的に閉じますが、ストロークではありません。パスが閉じていない場合、2つの側のみが描画されます。
例を表示します
//トライアングル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();
アークまたは円を描くには、ARCメソッドを使用します。仕様では、Safariでサポートされているが現在のGeckoブラウザーには実装されていないARCTOメソッドについても説明しています。
ARCメソッドを使用して、アークまたは円を描画します。 ARCTOメソッドは、標準の説明にも含まれています。 Safariは現在サポートされていますが、Geckoベースのブラウザはまだ実装されていません。
arc (x、y、radius、startangle、endangle、anticlockwise)この方法では、xとyが円の中心の座標です。半径は自己説明です。 StartangleおよびEndangleパラメーターは、ラジアンのアークの開始点とエンドポイントを定義します。開始角と閉鎖角は、x軸から測定されます。 Anticockwiseパラメーターはブール値です。これは、TrueがARCをアンチコックワイズに描画すると、それ以外の場合は時計回りの方向に描画します。
このメソッドは5つのパラメーターを受け入れます:x、yは中心座標、半径は半径、startangle、およびendangleは開始および終了ラジアン(参照としてx軸に基づく)、反時計回り、および逆のことを意味します。
警告:Firefoxベータビルドでは、最後のパラメーターは時計回りです。最終リリースは、上記のように機能をサポートします。現在の形式でこの方法を使用するすべてのスクリプトは、最終バージョンがリリースされたら更新する必要があります。警告:Firefoxのベータバージョンでは、最後のパラメーターは時計回りで、最終バージョンはありません。したがって、ベータから配布にアップグレードする場合は、対応する変更を行う必要があります。
注:ARC関数の角度は、度ではなくラジアンで測定されます。学位をラジアンに変換するには、次のJavaScript式を使用できます:var radians =(math.pi/180)*degre。注:ARCメソッドで使用される角度は、度ではなくラジアンの単位です。この式では、次の式で使用できます。varradians =(math.pi/180)*degrees;。
次の例は、上記のものよりも少し複雑です。さまざまな角度と塗りつぶしで12の異なる弧を描きました。上記のスマイリーの顔のようにこの例を書いていたなら、まずこれが非常に長いステートメントのリストになり、次にアークを描くとき、私はすべての出発点を知る必要があります。ここで使用したような90、180、および270度のアークの場合、これはそれほど問題ではありませんが、より複雑なものではこれは困難になりすぎます。
この例は、以前に見たものよりも複雑です。異なる角度と充填状態を持つ12の異なるアークを描きます。スマイリーフェイスを描く上記の方法でこれらのアークを描く場合、それは大きなコードになり、各アークを描くときは、円の中心の位置を知る必要があります。たとえば、ここで90、180、270度の弧を描くことも問題です。グラフィックがより複雑な場合、それらを実装することはより困難になります。
ループ用の2つは、アークの行と列をループするためのものです。すべてのアークについて、beginpathを使用して新しいパスを開始します。この下では、すべてのパラメーターを変数として書きました。そのため、何が起こっているのかを読みやすくなります。通常、これは1つのステートメントにすぎません。 XおよびY座標は十分に明確でなければなりません。半径とStartAngleが固定されています。エンド角はAS 180度(最初の列)の始まりであり、90度のステップで増加して完全な円(最後の列)を形成します。時計回りのパラメーターのステートメントは、1列目と3列目が時計回りのアークとして描画され、2行目と4列目は反時計回りに描画されます。最後に、IFステートメントにより、上半分の角弧と下半分が満たされたアークが作成されます。
ここでは、ループに2つを使用して、複数の行と列のあるアークを描画します。各アークは、beginpathメソッドを使用して新しいパスを作成します。次に、簡単に読み、理解するために、すべてのパラメーターを可変フォームに書きました。 xとyが中心座標であることは明らかです。半径とstartangleの両方が固定されており、エンドアングルは180度の半円から90度モードで円への増分から始まります。 AntilockWiseは、奇妙な行と偶数の行の数に依存します。最後に、IFステートメントは、最初の2行がエッジとして表示され、最後の2行が効果で満たされていることを判断するために使用されます。
for(i = 0; i <4; i ++){for(j = 0; j <3; j ++){ctx.beginPath(); var x = 25+j*50; // x座標var y = 25+i*50; // y座標var radius = 20; // arc radius 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(); }}}利用可能な次のタイプのパスは、立方体および二次品種で利用可能なBézier曲線です。これらは通常、複雑な有機形状を描くために使用されます。
導入される次の道は、bezier曲線であり、これは二次形式で立方体の形であり、一般的に複雑で通常の形状を描くために使用されます。
QuadraticCurveto (CP1X、CP1Y、X、Y)// Firefox 1.5で壊れている(以下の作業を参照) Beziercurveto (Cp1x、cp1y、cp2x、cp2y、x、y)これらの違いは、右側の画像を使用して最もよく説明できます。二次ベジエ曲線にはスタートとエンドポイント(青い点)があり、1つのコントロールポイント(赤い点)のみがありますが、キュービックベジエカーブは2つのコントロールポイントを使用します。
上記の2行のコードの違いについては、右側の図を参照してください。それらはすべて出発点とエンドポイント(図の青いドット)を持っていますが、二次皮肉の曲線には1つの(赤)制御ポイントしかありません)。
これらの両方のメソッドのxおよびyパラメーターは、エンドポイントの座標です。 CP1XおよびCP1Yは最初の制御点の座標であり、CP2XとCP2Yは2番目の制御ポイントの座標です。
パラメーターxとyはエンドポイント座標、cp1xとcp1yは最初の制御ポイントの座標であり、cp2xとcp2yは2番目です。
Adobe Illustratorのようなベクトル描画ソフトウェアとは異なり、私たちが何をしているかについて直接的な視覚的フィードバックを持っていないため、2次および立方体のベジエ曲線を使用することは非常に困難です。これにより、複雑な形を描くのがかなり難しくなります。次の例では、いくつかの単純なオーガニック形状を描画しますが、時間があり、何よりも忍耐力がある場合は、はるかに複雑な形を作成できます。
ベクター描画ソフトウェアAdobe Illustratorのように即時の視覚的フィードバックがないため、2次および立方体のベジエ曲線を使用することは非常に困難です。複雑なグラフィックを描くのがもっと面倒だからです。しかし、時間があり、最も重要な場合は、複雑なグラフィックを描画できます。下にシンプルで定期的な数字を描きましょう。
これらの例には非常に難しいことはありません。どちらの場合も、一連の曲線が描画され、最終的に完全な形になります。
これらの例は比較的簡単です。私たちが描くのは完全なグラフィックです。
//四肢曲線Examplex.beginPath(); ctx.moveto(75,25); ctx.QuadraticCurveto(25,25,25,62.5); ctx.QuadraticCurveto(25,100,50,100); 120,30,125); ctx.QuadraticCurveto(60,120,65,100); ctx.QuadraticCurveto(125,100,125,62.5);
単一の二次ベジエコントロールポイントから両方のキュービックベジエコントロールポイントを正しく計算することにより、二次ベジエカーブを立方ベジエカーブに変換することができますが、逆は真実ではありません。立方体のベジエ曲線の正確な変換は、二次用語がゼロの場合にのみ可能です。より一般的には、複数の二次ベジエ曲線を使用して立方体ベジエを近似するために区画法が使用されます。
計算を通じて、対応するキュービック曲線の2つの制御ポイントは、二次曲線の単一の制御点から導出できます。したがって、二次性を立方に変えることができますが、それ以外の場合は可能です。立方体方程式の立方項がゼロの場合にのみ、二次ビジエ曲線に変換することができます。一般的に、複数の二次曲線を使用して、区画アルゴリズムを介して立方体ベジエ曲線のシミュレーションを近似できます。
// bezier curves emblyx.beginpath(); ctx.moveto(75,40); ctx.beziercurveto(75,37,70,25,50,25); ctx.beziercurveto(20,25,20,62.5,20,62.5); 、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();
Firefox 1.5 Quadatriccurveto()の実装にはバグがあります。同じキュービック曲線関数Beziercurveto()呼び出しを呼び出し、単一の二次制御ポイント(x、y)座標を2回繰り返しているため、二次曲線を描画しません。このため、QuadraticCurveto()は誤った結果をもたらします。 QuadraticCurveto()を使用する必要がある場合は、2次ベジエカーブを自分の立方ベジエカーブに変換する必要があります。これにより、作業Beziercurveto()メソッドを使用できます。
Firefox 1.5では、Quadatriccurveto()の実装はバギーです。二次曲線を直接描画するわけではありませんが、Beziercurveto()を呼び出します。ここで、両方の制御ポイントは二次曲線の単一制御点です。したがって、誤った曲線を描画します。 QuadraticCurveto()を使用する必要がある場合は、Beziercurveto()メソッドを使用できるように、二次曲線を自分で立体力に変換する必要があります。
var currentx、culerny; // last xに設定し、yにlineto/moveto/beziercurvetoまたはquadraticcurvetofixed()関数QuadraticCurvetOfixed(cpx、cpy、x、y){/*次の変動名の下のquadraticcurvetofixed(/* quadraticcurvetofixed(/*)が使用されます。 lineto()、またはbeziercurveto())。 QP1は、四次曲線制御ポイントです(これは、QuadraticCurveto()に送信されたCPX、CPYです)。 QP2は二次曲線の終了点です(これはX、Yの引数であり、QuadraticCurveto()に送信されたはずです)。これらのポイントを変換して、必要な2つの立方制御ポイントを計算します(開始/終了点は二次曲線と立方体の両方の曲線で同じです。2つの立方体制御ポイントの方程式は、CP0 = QP0およびQP2 = QP2 = QP1 = QP0 + 2/3 *(QP1-QP0)CP1 + 1/3 *(QP1-QP0)各ポイントのXとYの両方の項を個別に計算します。 QP0y)/3.0 a)QP0XおよびQP0Y変数をCurrentXとCurrenty( * You *は各Moveto/Beziercurvetoに保存する必要があります)b)QP1xおよびQP1Y変数をCPXおよびCPYに置き換えます) xとy。 */ var cp1x = currentx + 2.0/ 3.0 *(cpx -currentx); var cp1y = currenty + 2.0/3.0*(cpy -curreny); var cp2x = cp1x +(x -currentx)/3.0; var cp2y = cp1y +(y -currenty)/3.0; //そして今、Cubic Bezier Curveを呼び出してBeziercurveto(CP1X、CP1Y、CP2X、CP2Y、X、Y)を機能させます。 currentX = x; currenty = y;}上記で見た3つの方法に加えて、長方形の形状がキャンバスに直接描かれていることに加えて、パスリストに長方形のパスを追加する方法もあります。
長方形を直接描画できる上記の3つの方法に加えて、長方形のパスを描くために使用される長方形の方法もあります。
rect (x、y、幅、高さ)この方法は4つの引数を取ります。 xおよびyパラメーターは、新しい長方形パスの左上隅の座標を定義します。幅と高さは、長方形の幅と高さを定義します。
4つのパラメーターを受け入れます。xとyは左上の座標であり、幅と高さは幅と高さです。
このメソッドが実行されると、Movetoメソッドはパラメーター(0,0)で自動的に呼び出されます(つまり、開始点をデフォルトの場所にリセットします)。
呼び出されると、Movetoメソッドは自動的に呼び出されるため、開始座標は原点に復元されます。
このページのすべての例では、形状ごとに1つのタイプのパス関数のみを使用しました。ただし、形状を作成するために使用できるパスの量または種類に制限はまったくありません。そのため、この最後の例では、すべてのパス関数を組み合わせて、非常に有名なゲームキャラクターのセットを作成しようとしました。
上記で使用される例は、1つのタイプのパスのみを使用しています。もちろん、キャンバスは使用するパスタイプの数を制限しません。それでは、ホッジポッジを見てみましょう。
私はこの完全なスクリプトを実行するつもりはありませんが、注意すべき最も重要なことは、丸みを帯びた関数とFillstyleプロパティの使用です。より複雑な形状を描くためにあなた自身の関数を定義するのは非常に便利で時間を節約できます。このスクリプトでは、今のコードの2倍のコードを撮影していたでしょう。
このチュートリアルの後半で、Fillstyleプロパティをさらに詳しく見ていきます。ここでは、デフォルトのブラックから白、そして再び塗りつぶしの色を変更するためにそれを使用しています。
例全体で、最も注目すべきことは、丸みのある関数の使用とfillstyleプロパティの設定です。カスタム関数は、複雑なグラフィックスの図面をカプセル化するのに非常に役立ちます。この例でカスタム関数を使用すると、コードの約半分が保存されます。
次の例では、充填剤の属性の詳細な使用を検討します。デフォルトの黒から白、そして黒に戻るために、それを使用して使用します。
例を表示します
function draw(){var ctx = document.getElementById( '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、true); ctx.lineto(31,37); ctx.fill(); for(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.lineteto(111,116); ctx.lineteto(106.333,111.333); ctx.lineteto(101.666,116); ctx.lineteto(97,111.333); ctx.lineteto(92.333,116); ctx.lineteto(87.666,111.333); ctx.lineteto(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(); ctx.fill(); ctx.arc(89,102,2,0、math.pi*2、true); ctx.fill(); ctx.fill(); }関数Roundedderect(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+幅、y+高さ、x+幅、y+height-radius); ctx.lineto(x+幅、y+radius); ctx.QuadraticCurveto(x+幅、y、x+幅radius、y); ctx.lineto(x+radius、y); ctx.QuadraticCurveto(x、y、x、y+radius); ctx.stroke();}