最近、canvasの勉強の一環として、画像を切り替えるだけの簡単なシミュレーションコンテンツを作成しました。
この記事では、備忘録としてそのコンテンツについて紹介したいと思います。
コンテンツ概要
ラジオボタンを押すと、canvasに表示される画像が切り替わります。
下の画像はコンテンツのスクリーンショットです。画面下部の4つの正方形がラジオボタンとなっています。ボタンを押すとそのボタンに対応した画像がcanvasに表示されます。

サンプルコードはこちらです。
※サンプルで使用している画像は、非商業に限りご自由にお使いください。
環境
- OS:Windows 11
- ブラウザ:Google Chrome (ver. 150.0.7871.187)
- エディタ:Visual Studio Code
- 使用言語:HTML / CSS / JavaScript
HTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/nicolas-cusan/destyle.css@latest/destyle.css">
<link rel="stylesheet" href="./css/style.css">
<title>canvas simulation</title>
</head>
<body>
<canvas id="canvas" width="640" height="480"></canvas>
<nav class="ui-panel">
<h2 class="ui-panel__title">猫の色</h2>
<ul class="ui-panel__list">
<li class="ui-panel__item">
<label>
<input class="ui-panel__input" type="radio" name="color" value="brownwhite" checked>
<span class="ui-panel__color ui-panel__color--brown-white"></span>
<span class="ui-panel__name">brown-white</span>
</label>
</li>
<li class="ui-panel__item">
<label>
<input class="ui-panel__input" type="radio" name="color" value="blackwhite">
<span class="ui-panel__color ui-panel__color--black-white"></span>
<span class="ui-panel__name">black-white</span>
</label>
</li>
<li class="ui-panel__item">
<label>
<input class="ui-panel__input" type="radio" name="color" value="black">
<span class="ui-panel__color ui-panel__color--black"></span>
<span class="ui-panel__name">black</span>
</label>
</li>
<li class="ui-panel__item">
<label>
<input class="ui-panel__input" type="radio" name="color" value="white">
<span class="ui-panel__color ui-panel__color--white"></span>
<span class="ui-panel__name">white</span>
</label>
</li>
</ul>
</nav>
<script src="./js/main.js"></script>
</body>
</html>
HTMLは基本的な記述のみのため、詳細な説明は省略します。
CSS
#canvas {
border: 1px solid #000;
display: block;
margin: 20px auto;
}
.ui-panel__title {
font-family: sans-serif;
font-size: 18px;
font-weight: bold;
text-align: center;
}
.ui-panel__list {
display: grid;
gap: 10px;
grid-template-columns: repeat(4, 150px);
justify-content: center;
margin-top: 20px;
}
.ui-panel__item label {
align-items: center;
display: flex;
flex-direction: column;
position: relative;
}
.ui-panel__input {
appearance: none;
position: absolute;
}
.ui-panel__input:checked + .ui-panel__color {
border: 3px solid #a8a8a8;
box-shadow: 0 0px 0px 2px #020202;
}
.ui-panel__color {
aspect-ratio: 1;
box-shadow: 0 1px 2px 1px #ccc;
width: 50px;
}
.ui-panel__color--brown-white {
background: linear-gradient(#D3C190 50%, #FDF2DF 50%);
}
.ui-panel__color--black-white {
background: linear-gradient(#5E5E5E 50%, #FDF2DF 50%);
}
.ui-panel__color--black {
background-color: #2A2A2A;
}
.ui-panel__color--white {
background-color: #FDECEC;
}
.ui-panel__name {
margin-top: 10px;
}
CSSについても基本的な記述のみのため、詳細な説明は省略します。
JavaScript
const canvasEl = document.getElementById('canvas');
const ctx = canvasEl.getContext('2d');
const imagePathList = [
['brownwhite', './image/illust_cat_01.jpg'],
['blackwhite', './image/illust_cat_02.jpg'],
['black', './image/illust_cat_03.jpg'],
['white', './image/illust_cat_04.jpg'],
];
const images = {};
// 画像の切り替え
function changeImage(name) {
const image = images[name];
if (!image) {
console.error(`画像が読み込まれていない:${name}`)
return;
}
const x = (canvasEl.width - image.width) / 2;
const y = (canvasEl.height - image.height) / 2;
ctx.clearRect(0, 0, canvasEl.width, canvasEl.height);
ctx.drawImage(image, x, y);
}
// 画像の読み込み
async function loadImage(path) {
const img = new Image();
img.src = path;
await img.decode();
return img;
}
async function init() {
const entries = imagePathList.map(
async ([name, path]) => {
const image = await loadImage(path);
return [name, image];
}
);
const settledResults = await Promise.allSettled(entries);
settledResults.forEach((result) => {
if (result.status === 'fulfilled') {
const [name, image] = result.value;
images[name] = image;
} else {
console.error('読み込み失敗:', result.reason);
}
});
// ラジオボタンでの画像切り替え
const inputRadioEl = document.querySelectorAll('.ui-panel__input');
inputRadioEl.forEach((input) => {
input.addEventListener('change', (e) => {
changeImage(e.target.value);
});
});
const checkedRadioEl = document.querySelector('input[name="color"]:checked');
if (checkedRadioEl) {
changeImage(checkedRadioEl.value);
}
}
init();
画像の読み込み処理については、別の記事で詳しくまとめています。詳細は以下の記事をご参照ください。
画像の読み込みにはPromise.allSettled()を使用しています。こちらについても以前の記事で解説しているため、あわせてご参照ください。
ラジオボタンによる画像の切り替え処理には、各ラジオボタンにchangeイベントのイベントリスナーを登録することで実装しています。
最後に
本記事では、canvasを使った簡単なシミュレーションコンテンツについてまとめました。
今後は、目の色や耳の形など選択できる項目を増やしてみたいと考えています。画像保存機能も付けてみるのも面白いかもしれません。