ひとりでのアプリ開発 - fineの備忘録 -

ひとりでアプリ開発をするなかで起こったことや学んだことを書き溜めていきます

Web開発 - キャンバスAPIを使って簡単なお絵描きアプリを作ってみた

初めに

 簡単なお絵描きアプリを作成するなかで、キャンバスAPIの使い方を簡単にまとめます。

キャンバスAPIとは

キャンバスAPI (Canvas API) は JavaScript と HTML の <canvas> 要素によってグラフィックを描く方法を提供します。他にも、アニメーション、ゲームのグラフィック、データの可視化、写真加工、リアルタイム動画処理などに使用することができます。

機能

  • ドラッグで線を引くことができる
  • ブラシのサイズをスライダーで変更できる
  • ブラシの色をカラーピッカーで変更することができる
  • 全消去するためのボタンがある
  • 消しゴムはブラシの色を白にして対応する

完成図


コード全文

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>お絵描きアプリ</title>
    <style>
        canvas {
            border: 1px solid black;
        }

        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }

        canvas {
            border: 1px solid black;
            margin-bottom: 20px;
        }

        label {
            margin-right: 10px;
        }

        input[type="range"],
        input[type="color"] {
            margin-right: 10px;
        }  

        button {
            margin-top: 10px;
            padding: 5px 10px;
            background-color: #007bff;
            color: #fff;
            border: none;
            border-radius: 3px;
            cursor: pointer;
        }

        button:hover {
            background-color: #0056b3;
        }
    </style>
</head>
<body>
    <header><h1>お絵描きアプリ</h1></header>
    <canvas id="myCanvas" width="800" height="600"></canvas>
    <div>
        <label for="canvasWidth">キャンバスの幅:</label>
        <input type="number" id="canvasWidth" min="100" max="2000" value="800">
        <label for="canvasHeight">高さ:</label>
        <input type="number" id="canvasHeight" min="100" max="2000" value="600">
        <button onclick="resizeCanvas()">キャンバスのサイズを変更</button>
    </div>
    <div>
        <label for="brushSize">筆の太さ:</label>
        <input type="range" id="brushSize" min="1" max="20" value="5" onchange="changeBrushSize(this.value)">
    </div>
    <div>
        <label for="brushColor">筆の色:</label>
        <input type="color" id="brushColor" value="#000000" onchange="changeBrushColor(this.value)">
        <p>消しゴムは筆の色を白にして対応してください。</p>
    </div>
    <button onclick="clearCanvas()">全消去</button>
    <script src="script.js"></script>
</body>
</html>
script.js
// script.js

// Canvas要素の取得
const canvas = document.getElementById('myCanvas');
const context = canvas.getContext('2d');

// マウスが押された状態を表す変数
let isDrawing = false;

// 筆の初期設定
let brushSize = 5;
let brushColor = 'black';

// 描画開始時の処理
function startDrawing(event) {
    isDrawing = true;
    // ペンの色や太さなどの設定
    context.lineWidth = brushSize;
    context.lineCap = 'round';
    context.strokeStyle = brushColor;
    // 描画の開始点を設定
    context.beginPath();
    context.moveTo(event.clientX - canvas.offsetLeft, event.clientY - canvas.offsetTop);
}

// 描画中の処理
function draw(event) {
    if (isDrawing) {
        // 現在のマウスの位置に線を引く
        context.lineTo(event.clientX - canvas.offsetLeft, event.clientY - canvas.offsetTop);
        context.stroke();
    }
}

// 描画終了時の処理
function stopDrawing() {
    isDrawing = false;
}

// マウスがキャンバス上で動いたときのイベントリスナーを登録
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);

// 筆の太さと色を変更するための関数
function changeBrushSize(size) {
    brushSize = size;
}

function changeBrushColor(color) {
    brushColor = color;
}

// キャンバスを全消去する関数
function clearCanvas() {
    context.clearRect(0, 0, canvas.width, canvas.height); // キャンバスをクリア
}

// キャンバスのサイズを変更する関数
function resizeCanvas() {
    const canvasWidth = parseInt(document.getElementById('canvasWidth').value);
    const canvasHeight = parseInt(document.getElementById('canvasHeight').value);
    canvas.width = canvasWidth;
    canvas.height = canvasHeight;
}
キャンバスAPIの基本的な使い方

 HTMLにcanvas要素を記述することで、キャンバスを追加できます。

<canvas id="myCanvas" width="800" height="600"></canvas>

 width, height は省略できます。

 JavaScriptでキャンバスを取得するには、getElementByID()を使います。getContext() メソッドを使用して描画コンテキストにアクセスすることができます。今回はお絵描きアプリを作成するため、"2d"を引数にします。

HTMLCanvasElement: getContext() 関数の引数 説明
"2d" 2 次元の描画コンテキストを表す CanvasRenderingContext2D オブジェクトが作成される
"webgl"(または "experimental-webgl" 3 次元レンダリングコンテキストを表す WebGLRenderingContext オブジェクトを作成する
"webgl2" 3 次元レンダリングコンテキストを表す WebGL2RenderingContext (en-US) オブジェクトを作成する
"webgpu" WebGPU レンダーパイプライン用の 3 次元レンダリングコンテキストを表す GPUCanvasContext (en-US) オブジェクトを作成する
"bitmaprenderer" 指定されたImageBitmapRenderingContext (en-US)でキャンバスのコンテンツを置き換える機能のみを提供する

// Canvas要素の取得
const canvas = document.getElementById('myCanvas');
const context = canvas.getContext('2d');

 "2d"コンテキストでは、次の関数を用いて図形やパスを描画していきます。

関数 説明
beginPath() 新しいパスを開始します。これは、新しい図形を描画するために使用されます。パスは、線、曲線、矩形、円などの図形の輪郭を定義するために使用されます。
moveTo() パスの開始点を指定します。これは、パスの始点を設定するために使用されます。moveTo()を呼び出すと、パスの新しい始点が設定され、それに続く描画命令はこの始点から開始されます。
lineTo() 直線を描画します。現在のパスの最後の点から指定された座標まで直線を引きます。
closePath() パスを閉じます。最後の lineTo() 命令で指定された点からパスの開始点までの直線を引き、パスを閉じます。
stroke() パスを描画します。現在のパスを線で描画します。stroke() を呼び出すことで、パスの輪郭線が実際に描画されます。この際に、事前に設定された線のスタイルが適用されます(例: 線の幅、線の色など)。

 マウスのドラッグで描画できるように、イベントと上記の関数を組み合わせています。

(イベントの登録)

// マウスがキャンバス上で動いたときのイベントリスナーを登録
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);

(描画用関数)

// 描画開始時の処理
function startDrawing(event) {
    isDrawing = true;
    // ペンの色や太さなどの設定
    context.lineWidth = brushSize;
    context.lineCap = 'round';
    context.strokeStyle = brushColor;
    // 描画の開始点を設定
    context.beginPath();
    context.moveTo(event.clientX - canvas.offsetLeft, event.clientY - canvas.offsetTop);
}

// 描画中の処理
function draw(event) {
    if (isDrawing) {
        // 現在のマウスの位置に線を引く
        context.lineTo(event.clientX - canvas.offsetLeft, event.clientY - canvas.offsetTop);
        context.stroke();
    }
}

// 描画終了時の処理
function stopDrawing() {
    isDrawing = false;
}

終わりに

 キャンバスAPIのドキュメントにチュートリアルがあります。その内容を見ると、文字の描画や画像の使用、座標変換、合成とクリッピング、アニメーションなど様々な機能があることが分かります。今回、使った機能は最低限な描画機能だけなので、ドキュメントをご覧いただくことをお勧めします。