この記事の内容は、Canvas を使って滑らかな曲線を描く方法に関するものです。必要な方は参考にしていただければ幸いです。
背景の概要
Canvas を学習したり、プロジェクト開発で Canvas を使用したりするときに、誰もがこのようなニーズに遭遇したことがあると思います。それは、書き込み可能な小さな描画ボードを実装することです。道具。
まあ、Canvas に慣れている子供にとっては、ほんの数十行のコードでこれを実行できると思います。次のデモは簡単な例です。
nbsp;html> <title>Sketchpad demo</title> <style> canvas { border: 1px blue solid; } </style> <canvas></canvas> <script> let isDown = false; let beginPoint = null; const canvas = document.querySelector('#canvas'); const ctx = canvas.getContext('2d'); // 设置线条颜色 ctx.strokeStyle = 'red'; ctx.lineWidth = 1; ctx.lineJoin = 'round'; ctx.lineCap = 'round'; canvas.addEventListener('mousedown', down, false); canvas.addEventListener('mousemove', move, false); canvas.addEventListener('mouseup', up, false); canvas.addEventListener('mouseout', up, false); function down(evt) { isDown = true; beginPoint = getPos(evt); } function move(evt) { if (!isDown) return; const endPoint = getPos(evt); drawLine(beginPoint, endPoint); beginPoint = endPoint; } function up(evt) { if (!isDown) return; const endPoint = getPos(evt); drawLine(beginPoint, endPoint); beginPoint = null; isDown = false; } function getPos(evt) { return { x: evt.clientX, y: evt.clientY } } function drawLine(beginPoint, endPoint) { ctx.beginPath(); ctx.moveTo(beginPoint.x, beginPoint.y); ctx.lineTo(endPoint.x, endPoint.y); ctx.stroke(); ctx.closePath(); } </script>
その実装。ロジックも非常に単純です。
主にキャンバス上の 3 つのイベント (mousedown、mouseup、mousemove) をリッスンし、isDown 変数も作成します。
# なぜこのようなことが起こるのでしょうか?
問題分析
この現象の主な理由は次のとおりです:
実際には、滑らかな曲線を描画する方法があります。 lineTo が信頼できない場合は、canvas の別の描画 API、quadraticCurveTo を使用して、二次ベジェ曲線を描画することができます。
二次ベジェ曲線quadraticCurveTo(cp1x, cp1y, x, y)quadraticCurveTo メソッドを呼び出すには、cp1x と cp1y が制御点 、x、および を記述する必要があります。 y は曲線の終点です:詳細については、MDN をご覧ください。
ベジェを使用したいので、曲線、明らかに私たちのデータは十分ではありません。二次ベジェ曲線を完全に記述するには、開始点、制御点、および終了点が必要です。
、これらのデータはどのようにして得られるのでしょうか?この情報を取得するのに役立つ非常に賢いアルゴリズムがあります
二次ベジェのキー ポイントを取得するためのアルゴリズムこのアルゴリズムを理解するのは難しくありません。ここで直接説明します。例を挙げてみましょう: 絵画内の合計 6 つのマウス座標、つまり A、B、C、D、E、F を収集するとします。##次に、点の中心を計算します。 C と D 点 C1、B1 を始点、C を制御点、C1 を終点として曲線を描き続けます。
OK,算法就是这样,那我们基于该算法再对现有代码进行一次升级改造:
let isDown = false; let points = []; let beginPoint = null; const canvas = document.querySelector('#canvas'); const ctx = canvas.getContext('2d'); // 设置线条颜色 ctx.strokeStyle = 'red'; ctx.lineWidth = 1; ctx.lineJoin = 'round'; ctx.lineCap = 'round'; canvas.addEventListener('mousedown', down, false); canvas.addEventListener('mousemove', move, false); canvas.addEventListener('mouseup', up, false); canvas.addEventListener('mouseout', up, false); function down(evt) { isDown = true; const { x, y } = getPos(evt); points.push({x, y}); beginPoint = {x, y}; } function move(evt) { if (!isDown) return; const { x, y } = getPos(evt); points.push({x, y}); if (points.length > 3) { const lastTwoPoints = points.slice(-2); const controlPoint = lastTwoPoints[0]; const endPoint = { x: (lastTwoPoints[0].x + lastTwoPoints[1].x) / 2, y: (lastTwoPoints[0].y + lastTwoPoints[1].y) / 2, } drawLine(beginPoint, controlPoint, endPoint); beginPoint = endPoint; } } function up(evt) { if (!isDown) return; const { x, y } = getPos(evt); points.push({x, y}); if (points.length > 3) { const lastTwoPoints = points.slice(-2); const controlPoint = lastTwoPoints[0]; const endPoint = lastTwoPoints[1]; drawLine(beginPoint, controlPoint, endPoint); } beginPoint = null; isDown = false; points = []; } function getPos(evt) { return { x: evt.clientX, y: evt.clientY } } function drawLine(beginPoint, controlPoint, endPoint) { ctx.beginPath(); ctx.moveTo(beginPoint.x, beginPoint.y); ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, endPoint.x, endPoint.y); ctx.stroke(); ctx.closePath(); }
在原有的基础上,我们创建了一个变量points用于保存之前mousemove事件中鼠标经过的点,根据该算法可知要绘制二次贝塞尔曲线起码需要3个点以上,因此我们只有在points中的点数大于3时才开始绘制。接下来的处理就跟该算法一毛一样了,这里不再赘述。
代码更新后我们的曲线也变得平滑了许多,如下图所示:
本文到这里就结束了,希望大家在canvas画板中“画”得愉快~我们下次再见:)
以上がCanvas (コード) を使用して滑らかな曲線を描くにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。