Canvas を学習したり、プロジェクト開発で Canvas を使用したりするときに、誰もがそのようなニーズに遭遇したことがあると思います。それは、書き込み可能なスケッチパッド ガジェットを実装することです。
Canvas に慣れている子供にとっては、わずか数十行のコードでこれを実行できると思います。次のデモは簡単な例です。
<!DOCTYPE html><html><head> <title>スケッチパッドのデモ</title> <style type=text/css> キャンバス { border: 1px 青単色 } </style></head><body> <canvas; id=canvas width=800 height=500></canvas> <script type=text/javascript> let isDown = false; let beginPoint = null; document.querySelector('#canvas'); const ctx = Canvas.getContext('2d'); // 線の色を設定します。 ctx.lineWidth = 'round'; .lineCap = 'round'; Canvas.addEventListener('mousedown', down, false); move, false); Canvas.addEventListener('mouseup', up, false); 関数 down(evt) { isDown = true; move(evt) { if (!isDown) return; const endPoint = getPos(evt); } up(evt) { if (!isDown) return; const endPoint = getPos(evt); beginPoint = null; } function getPos(evt) { return { x: evt.clientX, y: evt.clientY } } 関数drawLine(beginPoint, endPoint) { ctx.beginPath(); ctx.moveTo(beginPoint.x, beginPoint.y); ctx.lineTo(endPoint.x, endPoint.y); </script></body></html >
その実装ロジックも非常にシンプルです。
mousedown
、 mouseup
、 mousemove
をリッスンし、 isDown
変数も作成します。mousedown
)、 isDown
true
に設定し、ユーザーがマウスを置いたとき ( mouseup
) をfalse
に設定します。この利点は、ユーザーが現在描画状態にあるかどうかを判断できることです。 ;mousemove
イベントを通じてマウスが通過する座標点を継続的に収集します。isDown がisDown
true
場合 (つまり、書き込み状態の場合)、現在の点は、 lineTo
メソッドを通じて前の点に接続されて描画されます。キャンバス;上記の手順により、基本的な描画ボードの機能を実現できますが、注意が必要な子供の靴には非常に深刻な問題が発生する可能性があります。この方法で描画された線はぎざぎざで、十分に滑らかではありません。描くほど破線感が強くなります。性能は以下の通りです。
なぜこのようなことが起こっているのでしょうか?問題分析この現象の主な理由は次のとおりです。
Canvas のlineTo
メソッドを使用して点を接続します。隣接する 2 つの点を結ぶのは曲線ではなく直線なので、この方法で描画されるのはポリラインです。
ブラウザによるmousemove
イベントの収集頻度によって制限されるため、 mousemove
の間、ブラウザは短期間ごとに現在のマウスの座標を収集することは誰でも知っています。したがって、マウスの移動が速くなるほど、収集される 2 つの隣接する点間の距離は遠くなります。離れるほど、折り線の感覚がより明白になります。
実際には、滑らかな曲線を描画する方法があります。 lineTo
が信頼できない場合は、canvas の別の描画 API、 quadraticCurveTo
を使用できます。これは、二次ベジェ曲線を描画するために使用されます。
二次ベジェ曲線
quadraticCurveTo(cp1x, cp1y, x, y)
quadraticCurveTo
メソッドを呼び出すには、制御点を記述する 4 つのパラメーターcp1y
必要ですcp1x
とx
y
曲線の終点です。
より詳細な情報は MDN でご覧いただけます
ベジェ曲線を使用したいので、二次ベジェ曲線を完全に記述するには、データが不十分であることは明らかです。これらのデータはどこから来たのでしょうか。
この情報を取得するのに役立つ非常に賢いアルゴリズムがあります
二次ベジェ キー ポイントを取得するアルゴリズムこのアルゴリズムを理解するのは難しくありません。例を直接挙げてみましょう。
絵画内の合計 6 つのマウス座標、つまりA, B, C, D, E, F
を収集するとします。前の 3 つの点A, B, C
を取得し、 B
とC
の中点B1
を計算し、 A
を使用します。開始点、 B
は制御点、 B1
終了点です。quadraticCurveTo quadraticCurveTo
使用して 2 次ベジェ曲線セグメントを描画します。
次に、点C
とD
間の中点C1
計算し、 B1
を始点、 C
制御点、 C1
終点として曲線を描き続けます。
最後の点F
に到達すると、ベジェ曲線はD1
D
とE
の中点) を始点、 E
を制御点、 F
を終点として終了します。
OK、アルゴリズムは次のようなものです。このアルゴリズムに基づいて既存のコードをアップグレードします。
let isDown = false;let Points = [];let beginPoint = null;const Canvas = document.querySelector('#canvas');const ctx = Canvas.getContext('2d');//線の色を設定する ctx.ストロークスタイル= '赤';ctx.lineWidth = 1;ctx.lineJoin = 'ラウンド';ctx.lineCap = 'round';canvas.addEventListener('mousedown', down, false);canvas.addEventListener('mousemove', move, false);canvas.addEventListener('mouseup', up, false);canvas.addEventListener('mouseout' , up, false); 関数 down(evt) { isDown = true; const { x, y } = getPos(evt); Points.push({x, y}); beginPoint = {x, y};}function move(evt) { if (!isDown) return; x, y}); if (points.length > 3) { const lastTwoPoints = point.slice(-2); const controlPoint = lastTwoPoints [0]; x: (lastTwoPoints[0].x + lastTwoPoints[1].x) / 2, y: (lastTwoPoints[0].y + lastTwoPoints[1].y) / 2, }drawLine(beginPoint, controlPoint, endPoint); beginPoint = endPoint; }}関数 up(evt) { if (!isDown) return; Points.push({x, y}); if (points.length > 3) { const lastTwoPoints = point.slice(-2); const endPoint = lastTwoPoints[1]; , controlPoint, endPoint); } beginPoint = null; isDown = false; 関数 getPos(evt) { return { x: evt.clientX, y: evt.clientY }}関数drawLine(beginPoint, controlPoint, endPoint) { ctx.beginPath(); ctx.quadraticCurveTo(controlPoint.x, controlPoint. y、endPoint.x、endPoint.y); ctx.closePath();}
オリジナルに基づいて、前のmousemove
イベントでマウスが通過したポイントを保存する変数points
を作成しました。このアルゴリズムによれば、二次ベジェ曲線を描画するには少なくとも 3 つのポイントが必要であることがわかっているため、ポイント数が 3 より大きい場合にのみ描画が開始されますpoints
以降の処理はこのアルゴリズムと全く同じなので、ここでは詳しく説明しません。
コードの更新後、次の図に示すように、曲線ははるかに滑らかになりました。
この記事はここで終わります。皆さんもぜひキャンバスでお絵描きを楽しんでください。また次回お会いしましょう:)
子供用の靴に興味がある場合は、ここをクリックして私のブログをフォローしてください。新しくて興味深いブログ投稿はできるだけ早くここで共有されます。
以上がこの記事の全内容です。皆様の学習のお役に立てれば幸いです。また、VeVb Wulin Network をご支援いただければ幸いです。