【入門者向け】Canvas入門講座#18 canvasに描いた内容を保存、復元してみよう【JavaScript】

#問題18

クリックした座標を中心に四角形を描画しなさい。
四角形は赤色(#ff0000)で塗りつぶすこと。
四角形は1辺の長さが30の正方形とする。
saveボタン押下で描画内容をlocalStorageへ保存すること
loadボタン押下でlocalStorageから復元すること

以下のHTMLを使用すること。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>問題18</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
$(() => {
    $('#my-canvas').click(e => {
    });

    $('#save-button').click(e => {
    });

    $('#load-button').click(e => {
    });    
});
</script>
</head>
<body>
<canvas id="my-canvas" width="500" height="300"></canvas>
<br>
<button id="save-button">save</button>
<button id="load-button">load</button>
</body>
</html>
```

#解答

```html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>問題18</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
$(() => {
    // ローカルストレージのキー
    const LOCAL_STORAGE_KEY = 'q18';

    // 四角形の中心座標群
    let rectArray = [];

    $('#my-canvas').click(e => {
        const cursorX = e.offsetX,
            cursorY = e.offsetY;
        // 配列に追加
        rectArray.push({
            x: cursorX,
            y: cursorY
        });
        // 四角形群を描画
        drawRectArray(rectArray);
    });

    $('#save-button').click(e => {
        const item = JSON.stringify(rectArray);
        localStorage.setItem(LOCAL_STORAGE_KEY, item); 
    });

    $('#load-button').click(e => {
        const item = localStorage.getItem(LOCAL_STORAGE_KEY);
        if(!item) {
            return;
        }
        rectArray = JSON.parse(item);
        drawRectArray(rectArray);
    });    

    function drawRectArray(array) {
         // コンテキストを取得
        const ctx = $('#my-canvas')[0].getContext('2d');

        // 現在の描画状態を保存する
        ctx.save(); 

        // canvasをクリアする
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

        // 塗りつぶしの色を赤(#ff0000)にする
        ctx.fillStyle = '#ff0000';

        // 四角形をすべて描画する
        array.forEach(elm => {
            // (elm.x, elm.y) を中心に1辺が30の正方形を塗りつぶす
            ctx.fillRect(elm.x - 15, elm.y - 15, 30, 30);
        });

        // 描画状態を保存した時点のものに戻す
        ctx.restore();
    }
});
</script>
</head>
<body>
<canvas id="my-canvas" width="500" height="300"></canvas>
<br>
<button id="save-button">save</button>
<button id="load-button">load</button>
</body>
</html>
```

#解説

ローカルストレージへ保存するためには固定のキー(適当な文字列)を決める必要があります。
四角形の中心座標を配列で持つことにします。

```js
// ローカルストレージのキー
const LOCAL_STORAGE_KEY = 'q18';

// 四角形の中心座標群
let rectArray = [];
```

canvasクリック時にカーソルの座標を配列へ追加し、canvasをクリアして全て描画します。

```js
$('#my-canvas').click(e => {
    const cursorX = e.offsetX,
        cursorY = e.offsetY;
    // 配列に追加
    rectArray.push({
        x: cursorX,
        y: cursorY
    });
    // 四角形群を描画
    drawRectArray(rectArray);
});

function drawRectArray(array) {
     // コンテキストを取得
    const ctx = $('#my-canvas')[0].getContext('2d');

    // 現在の描画状態を保存する
    ctx.save(); 

    // canvasをクリアする
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

    // 塗りつぶしの色を赤(#ff0000)にする
    ctx.fillStyle = '#ff0000';

    // 四角形をすべて描画する
    array.forEach(elm => {
        // (elm.x, elm.y) を中心に1辺が30の正方形を塗りつぶす
        ctx.fillRect(elm.x - 15, elm.y - 15, 30, 30);
    });

    // 描画状態を保存した時点のものに戻す
    ctx.restore();
}
```

saveボタン押下時に四角形の中心座標配列を<b>JSON.stringifyメソッドでJSON文字列変換して</b>
ローカルストレージへ保存します。
localStorage.setItem(keyName, keyValue);
keyNameはキー(今回は'q18')で、keyValueが今回はJSON文字列です。

```js
$('#save-button').click(e => {
    const item = JSON.stringify(rectArray);
    localStorage.setItem(LOCAL_STORAGE_KEY, item); 
});

```

saveボタン押下時にローカルストレージへ保存されているJSON文字列を取得し
<b>JSON.parseメソッドで復元します。</b>
ローカルストレージへ何も保存されていない場合は、
localStorage.getItemがnullを返すのでその時は何も処理を行わないようにします。

```js
$('#load-button').click(e => {
    const item = localStorage.getItem(LOCAL_STORAGE_KEY);
    if(!item) {
        return;
    }
    rectArray = JSON.parse(item);
    drawRectArray(rectArray);
});    
```