画像にグリッド線を入れるツールをHTMLを作りました

今回HTMLとJavascriptを使用して作成したのは、画像をアップロードすると、自分の好きな幅のグリッド線を追加することができるツールです。

## はじめに
このツールは、学校等の美術で模写をする際に簡単に画像にグリッド線を追加したいという場合等に使用していただけると嬉しいです！

## 作成方法
見た目を自分で作成し、JavaScriptの部分等の動作のコードは、ChatGPTに手伝ってもらいコーディングをしました。いくつか試作品を作成いたしましたので。どこが違うか考えてみてください！

# 試作品１
```html:test1.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-container {
        position: relative;
      }

      #grid-canvas {
        position: absolute;
        top: 0;
        left: 0;
      }

    </style>
  </head>

  <body>
    <h1>画像にグリッド線を追加</h1> <input type="file" id="image-upload" accept="image/*"><br> 行数: <input type="number" id="rows" min="1" value="5"><br> 列数: <input type="number" id="cols" min="1" value="5"><br> <button onclick="drawGrid()">グリッドを描く</button>
    <div id="canvas-container"> <img id="image" style="display: none;"> <canvas id="grid-canvas"></canvas> </div>
    <script>
      const imageUpload = document.getElementById('image-upload');
      const image = document.getElementById('image');
      const gridCanvas = document.getElementById('grid-canvas');
      const canvasContainer = document.getElementById('canvas-container');
      imageUpload.addEventListener('change', function(event) {
        const file = event.target.files[0];
        const reader = new FileReader();
        reader.onload = function(e) {
          image.src = e.target.result;
          image.onload = function() {
            gridCanvas.width = image.width;
            gridCanvas.height = image.height;
            gridCanvas.style.display = 'block';
            image.style.display = 'block';
          }
        }
        reader.readAsDataURL(file);
      });

      function drawGrid() {
        const rows = parseInt(document.getElementById('rows').value);
        const cols = parseInt(document.getElementById('cols').value);
        const ctx = gridCanvas.getContext('2d');
        ctx.clearRect(0, 0, gridCanvas.width, gridCanvas.height);
        const rowHeight = gridCanvas.height / rows;
        const colWidth = gridCanvas.width / cols;
        ctx.strokeStyle = 'red';
        ctx.lineWidth = 1;
        for (let i = 1; i < rows; i++) {
          ctx.beginPath();
          ctx.moveTo(0, i * rowHeight);
          ctx.lineTo(gridCanvas.width, i * rowHeight);
          ctx.stroke();
        }
        for (let j = 1; j < cols; j++) {
          ctx.beginPath();
          ctx.moveTo(j * colWidth, 0);
          ctx.lineTo(j * colWidth, gridCanvas.height);
          ctx.stroke();
        }
      }

    </script>
  </body>

</html>

```

# 試作品２
```html:test2.html
<!DOCTYPE html>
<html lang="ja">

  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>画像にグリッド線を追加</title>
    <style>
      #canvas-container {
        position: relative;
        display: inline-block;
      }

      #grid-canvas {
        position: absolute;
        top: 0;
        left: 0;
      }

    </style>
  </head>

  <body>
    <h1>画像にグリッド線を追加</h1> <input type="file" id="image-upload" accept="image/*"><br> 行数: <input type="number" id="rows" min="1" value="5"><br> 列数: <input type="number" id="cols" min="1" value="5"><br> <button onclick="drawGrid()">グリッドを描く</button>
    <div id="canvas-container"> <img id="image"> <canvas id="grid-canvas"></canvas> </div>
    <script>
      const imageUpload = document.getElementById('image-upload');
      const image = document.getElementById('image');
      const gridCanvas = document.getElementById('grid-canvas');
      const canvasContainer = document.getElementById('canvas-container');
      imageUpload.addEventListener('change', function(event) {
        const file = event.target.files[0];
        const reader = new FileReader();
        reader.onload = function(e) {
          image.src = e.target.result;
          image.onload = function() {
            gridCanvas.width = image.width;
            gridCanvas.height = image.height;
            gridCanvas.style.width = image.width + 'px';
            gridCanvas.style.height = image.height + 'px';
            gridCanvas.style.display = 'block';
          }
        }
        reader.readAsDataURL(file);
      });

      function drawGrid() {
        const rows = parseInt(document.getElementById('rows').value);
        const cols = parseInt(document.getElementById('cols').value);
        const ctx = gridCanvas.getContext('2d');
        ctx.clearRect(0, 0, gridCanvas.width, gridCanvas.height);
        const rowHeight = gridCanvas.height / rows;
        const colWidth = gridCanvas.width / cols;
        ctx.strokeStyle = 'red';
        ctx.lineWidth = 1;
        for (let i = 1; i < rows; i++) {
          ctx.beginPath();
          ctx.moveTo(0, i * rowHeight);
          ctx.lineTo(gridCanvas.width, i * rowHeight);
          ctx.stroke();
        }
        for (let j = 1; j < cols; j++) {
          ctx.beginPath();
          ctx.moveTo(j * colWidth, 0);
          ctx.lineTo(j * colWidth, gridCanvas.height);
          ctx.stroke();
        }
      }

    </script>
  </body>

</html>
```

# 試作品３
```html:test3.html
<!DOCTYPE html>
<html lang="ja">

  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>画像にグリッド線を追加</title>
    <style>
      #canvas-container {
        position: relative;
        display: inline-block;
      }

      #grid-canvas {
        position: absolute;
        top: 0;
        left: 0;
        pointer-events: none;
        /* 画像のインタラクションを保持 */
      }

    </style>
  </head>

  <body>
    <h1>画像にグリッド線を追加</h1> <input type="file" id="image-upload" accept="image/*"><br> 行数: <input type="number" id="rows" min="1" value="5"><br> 列数: <input type="number" id="cols" min="1" value="5"><br> <button onclick="drawGrid()">グリッドを描く</button>
    <div id="canvas-container"> <img id="image" style="display: none;"> <canvas id="grid-canvas"></canvas> </div>
    <script>
      const imageUpload = document.getElementById('image-upload');
      const image = document.getElementById('image');
      const gridCanvas = document.getElementById('grid-canvas');
      const canvasContainer = document.getElementById('canvas-container');
      imageUpload.addEventListener('change', function(event) {
            const file = event.target.files[0];
            const reader = new FileReader();
            reader.onload = function(e) {
                image.src = e.target.result;
                image.style.display = 'block';
                image.onload = function() { // 画像がロードされたらキャンバスのサイズを画像に合わせる                    gridCanvas.width = image.width;                    gridCanvas.height = image.height;                    gridCanvas.style.width = image.width + 'px';                    gridCanvas.style.height = image.height + 'px';                }            }            reader.readAsDataURL(file);        });        function drawGrid() {            const rows = parseInt(document.getElementById('rows').value);            const cols = parseInt(document.getElementById('cols').value);            const ctx = gridCanvas.getContext('2d');            ctx.clearRect(0, 0, gridCanvas.width, gridCanvas.height);            const rowHeight = gridCanvas.height / rows;            const colWidth = gridCanvas.width / cols;            ctx.strokeStyle = 'red';            ctx.lineWidth = 1;            for (let i = 1; i < rows; i++) {                ctx.beginPath();                ctx.moveTo(0, i * rowHeight);                ctx.lineTo(gridCanvas.width, i * rowHeight);                ctx.stroke();            }            for (let j = 1; j < cols; j++) {                ctx.beginPath();                ctx.moveTo(j * colWidth, 0);                ctx.lineTo(j * colWidth, gridCanvas.height);                ctx.stroke();            }        }    

    </script>
  </body>

</html>
```

# 試作品４（仮の完成版の予定）
```html:test4.html
<!DOCTYPE html>
<html lang="ja">

  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>画像にグリッド線を追加</title>
    <style>
      #canvas-container {
        position: relative;
        display: inline-block;
      }

      #grid-canvas {
        position: absolute;
        top: 0;
        left: 0;
        pointer-events: none;
        /* 画像のインタラクションを保持 */
      }

      img {
        display: block;
      }

    </style>
  </head>

  <body>
    <h1>画像にグリッド線を追加</h1> <input type="file" id="image-upload" accept="image/*"><br> 行数: <input type="number" id="rows" min="1" value="5"><br> 列数: <input type="number" id="cols" min="1" value="5"><br> <button onclick="drawGrid()">グリッドを描く</button>
    <div id="canvas-container"> <img id="image" style="display: none;"> <canvas id="grid-canvas"></canvas> </div>
    <script>
      const imageUpload = document.getElementById('image-upload');
      const image = document.getElementById('image');
      const gridCanvas = document.getElementById('grid-canvas');
      const canvasContainer = document.getElementById('canvas-container');
      imageUpload.addEventListener('change', function(event) {
            const file = event.target.files[0];
            const reader = new FileReader();
            reader.onload = function(e) {
                image.src = e.target.result;
                image.style.display = 'block';
                image.onload = function() { // キャンバスのサイズを画像のサイズに合わせる                    gridCanvas.width = image.width;                    gridCanvas.height = image.height;                    // グリッド線を引く                    drawGrid();                }            }            reader.readAsDataURL(file);        });        function drawGrid() {            const rows = parseInt(document.getElementById('rows').value);            const cols = parseInt(document.getElementById('cols').value);            const ctx = gridCanvas.getContext('2d');            ctx.clearRect(0, 0, gridCanvas.width, gridCanvas.height);            const rowHeight = gridCanvas.height / rows;            const colWidth = gridCanvas.width / cols;            ctx.strokeStyle = 'red';            ctx.lineWidth = 1;            for (let i = 1; i < rows; i++) {                ctx.beginPath();                ctx.moveTo(0, i * rowHeight);                ctx.lineTo(gridCanvas.width, i * rowHeight);                ctx.stroke();            }            for (let j = 1; j < cols; j++) {                ctx.beginPath();                ctx.moveTo(j * colWidth, 0);                ctx.lineTo(j * colWidth, gridCanvas.height);                ctx.stroke();            }        }    

    </script>
  </body>

</html>
```

この試作品では、まだ日本語がわかりにくいところがあるので、そこを整えてから完成にしました。
# 完成版はこちら
```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>画像にグリッド線を追加</title>
    <style>
        #canvas-container {
            position: relative;
            display: inline-block;
        }
        #grid-canvas {
            position: absolute;
            top: 0;
            left: 0;
            pointer-events: none; /* 画像のインタラクションを保持 */
        }
        img {
            display: block;
        }
    </style>
</head>
<body>
    <h1>画像にグリッド線を追加</h1>
    <input type="file" id="image-upload" accept="image/*"><br>
    行数: <input type="number" id="rows" min="1" value="5"><br>
    列数: <input type="number" id="cols" min="1" value="5"><br>
    <button onclick="drawGrid()">グリッドを描く</button>
    <div id="canvas-container">
        <img id="image" style="display: none;">
        <canvas id="grid-canvas"></canvas>
    </div>
    
    <script>
        const imageUpload = document.getElementById('image-upload');
        const image = document.getElementById('image');
        const gridCanvas = document.getElementById('grid-canvas');
        const canvasContainer = document.getElementById('canvas-container');

        imageUpload.addEventListener('change', function(event) {
            const file = event.target.files[0];
            const reader = new FileReader();
            reader.onload = function(e) {
                image.src = e.target.result;
                image.style.display = 'block';
                image.onload = function() {
                    // キャンバスのサイズを画像のサイズに合わせる
                    gridCanvas.width = image.width;
                    gridCanvas.height = image.height;
                    // グリッド線を引く
                    drawGrid();
                }
            }
            reader.readAsDataURL(file);
        });

        function drawGrid() {
            const rows = parseInt(document.getElementById('rows').value);
            const cols = parseInt(document.getElementById('cols').value);
            const ctx = gridCanvas.getContext('2d');
            ctx.clearRect(0, 0, gridCanvas.width, gridCanvas.height);

            const rowHeight = gridCanvas.height / rows;
            const colWidth = gridCanvas.width / cols;

            ctx.strokeStyle = 'red';
            ctx.lineWidth = 1;

            for (let i = 1; i < rows; i++) {
                ctx.beginPath();
                ctx.moveTo(0, i * rowHeight);
                ctx.lineTo(gridCanvas.width, i * rowHeight);
                ctx.stroke();
            }

            for (let j = 1; j < cols; j++) {
                ctx.beginPath();
                ctx.moveTo(j * colWidth, 0);
                ctx.lineTo(j * colWidth, gridCanvas.height);
                ctx.stroke();
            }
        }
    </script>
</body>
</html>


```
これで完成です。


CSSなどで、見た目を装飾することはなかったですが、CSSができる方は、CSS等での装飾等も試してください。


最後まで長いお付き合いありがとうございました。

# GitHubにも今回のコードを記載しておきましたので、よければそちらから使用していただけると幸いです。

[GitHubリポジトリ](https://github.com/ryou09269639/Add-grid-lines-to-images)

## 補足
このコードは少しずつ修正やアップデートをしていくので、最新版が欲しい方はGitHubをご覧ください。