0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【JavaScript】端点の太さの異なる線分を描画する【Canvas】

Posted at

はじめに

やりたいことは、以下の画像のように端点の太さが変わる線分の描画です。
始点終点を丸くするか選べます。
パスを作成する関数なので、もちろん塗りつぶせもします。
image.png

サンプルプログラム

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>line path sample</title>
<script>
/**
 * 線分のパスを作成する
 * @param {CanvasRenderingContext2D} ctx キャンバスのコンテキスト 
 * @param { x: number, y: number, width: number, arc: boolean, }} start 始点
 * @param { x: number, y: number, width: number, arc: boolean, }} end 終点 
 * @returns {void} なし
 */
function createLinePath(ctx, start, end) {
    const vec = { x: end.x - start.x, y: end.y - start.y, };  // 始点から終点へのベクトルを求める
    const len = Math.sqrt(vec.x * vec.x + vec.y * vec.y);
    const unit = { x: vec.x / len, y: vec.y / len, };  // 単位ベクトル化する
    const nrm = { x: unit.y, y: -unit.x, }; // -90度回転する
    // 角度を求める
    const angle = Math.atan2(nrm.y, nrm.x);
    // 点を求める
    const posArray = [
        {
            x: start.x + nrm.x * start.width / 2,
            y: start.y + nrm.y * start.width / 2,
        },
        {
            x: end.x + nrm.x * end.width / 2,
            y: end.y + nrm.y * end.width / 2,
        },
        {
            x: end.x - nrm.x * end.width / 2,
            y: end.y - nrm.y * end.width / 2,
        },
        {
            x: start.x - nrm.x * start.width / 2,
            y: start.y - nrm.y * start.width / 2,
        },
    ];

    ctx.beginPath();
    ctx.moveTo(posArray[0].x, posArray[0].y);
    ctx.lineTo(posArray[1].x, posArray[1].y);
    if(!end.arc) {// 終点を丸くする
        ctx.lineTo(posArray[2].x, posArray[2].y);        
    } else {
        ctx.arc(end.x, end.y, end.width / 2, angle, angle + Math.PI);
    }
    ctx.lineTo(posArray[3].x, posArray[3].y);
    if(!start.arc) {// 始点を丸くする
        ctx.lineTo(posArray[0].x, posArray[0].y);   
    } else {
        ctx.arc(start.x, start.y, start.width / 2, angle + Math.PI, angle);
    }
    ctx.closePath();
}
document.addEventListener('DOMContentLoaded', e => {
    const canvas = document.querySelector('#canvas');
    const ctx = canvas.getContext('2d');
    
    ctx.save();
    ctx.fillStyle = 'black';
    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    ctx.lineWidth = 4;
    ctx.strokeStyle = 'yellow';
    createLinePath(ctx, { x: 100, y: 100, width: 50, arc: true }, { x: 300, y: 300, width: 10, arc: true });
    ctx.stroke();
    ctx.restore();
});
</script>
</head>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
</body>
</html>

応用例

プログラムは書かないけど、応用例としては「ベジェ曲線の太さを変える」などが思いつきます。
ベジェ曲線を微小な線分に分割して、長さに比例した太さを指定すれば徐々に太さの変わるベジェ曲線が描画できると思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?