Skip to content

Instantly share code, notes, and snippets.

@imk2o
Last active August 30, 2017 09:29
Show Gist options
  • Save imk2o/51dadedd681c256390b45dda1406a8de to your computer and use it in GitHub Desktop.
Save imk2o/51dadedd681c256390b45dda1406a8de to your computer and use it in GitHub Desktop.
Canvasアニメーションテンプレ #HTML #PHH
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>HTML Canvas Animation</title>
<script src="canvas_animation.js"></script>
<style type="text/css">
canvas { border: 1px solid black; }
</style>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</head>
<body>
<div class="well">
<button id="restart_button" class="btn btn-info">リスタート</button>
<button id="stop_button" class="btn btn-warning">停止</button>
</div>
<div>
<canvas id="canvas1" width="600" height="400"></canvas>
</div>
</body>
</html>
document.addEventListener('DOMContentLoaded', function() {
// リスタートボタンのクリックを監視
const restart_button = document.getElementById('restart_button');
restart_button.addEventListener('click', function() {
start();
});
// 停止ボタンのクリックを監視
const stop_button = document.getElementById('stop_button');
stop_button.addEventListener('click', function() {
window.cancelAnimationFrame(request_id);
request_id = null;
});
// 描画とアニメーションを開始
start();
});
let request_id = null;
let startTimestamp;
let lastTimestamp;
function start() {
startTimestamp = null;
lastTimestamp = null;
if (request_id == null) {
request_id = window.requestAnimationFrame(draw);
}
}
function draw(timestamp) {
// 経過時間を求める
if (startTimestamp == null) {
startTimestamp = timestamp;
lastTimestamp = timestamp;
}
//// 描画開始からの経過時間(秒)
let progress = (timestamp - startTimestamp) / 1000;
//// 前回の描画からの経過時間(秒)
let delta = (timestamp - lastTimestamp) / 1000;
// canvasの取得
const canvas = document.getElementById('canvas1');
const canvas_width = Number.parseInt(canvas.getAttribute('width'));
const canvas_height = Number.parseInt(canvas.getAttribute('height'));
const ctx = canvas.getContext('2d');
// canvasをクリア
ctx.clearRect(0, 0, canvas_width, canvas_height);
// 罫線を表示 (邪魔ならコメントアウトしてよい)
debugDrawGrid(ctx, canvas_width, canvas_height);
// 1フレームを描画
drawFrame(ctx, progress, delta, canvas_width, canvas_height);
// 経過時間の表示 (邪魔ならコメントアウトしてよい)
debugDrawTime(ctx, progress, delta);
// 一定時間後、再度draw()を呼び出すようリクエストする
lastTimestamp = timestamp;
request_id = window.requestAnimationFrame(draw);
}
// 1フレームを描画
// ctx: canvas 2D コンテキスト
// progress: 開始からの経過時間
// delta: 前回の描画からの経過時間
// canvas_width: キャンバスの幅
// canvas_height: キャンバスの高さ
function drawFrame(ctx, progress, delta, canvas_width, canvas_height) {
////////////////////////////////////////////////////////////
// TODO: ここに描画とアニメーション処理を追加...
ctx.fillStyle = 'rgb(240, 0, 0)';
let x = 10 * progress;
let y = x;
ctx.fillRect(x, y, 100, 100);
////////////////////////////////////////////////////////////
}
// 以下、デバッグ用 ////////////////////////////////////////////////////////////
function debugDrawGrid(ctx, width, height) {
const grid_width = 10;
const grid_height = 10;
const grid_scale = 10;
const small_grid_color = 'rgb(160, 160, 160)';
const large_grid_color = 'rgb(255, 160, 160)';
ctx.save();
ctx.lineWidth = 1;
// 水平線
for (let y = 0; y < height; y += grid_height) {
ctx.strokeStyle = (y % (grid_height * grid_scale) == 0) ? large_grid_color : small_grid_color;
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(width, y);
ctx.stroke();
}
// 垂直線
for (let x = 0; x < width; x += grid_width) {
ctx.strokeStyle = (x % (grid_width * grid_scale) == 0) ? large_grid_color : small_grid_color;
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, height);
ctx.stroke();
}
ctx.restore();
}
function debugDrawTime(ctx, progress, delta) {
const text_size = 16;
ctx.save();
ctx.fillStyle = 'rgb(80, 80, 255)';
ctx.font = `${text_size}pt serif`;
ctx.fillText(`progress: ${progress.toFixed(3)}sec, delta: ${delta.toFixed(3)}sec`, 0, text_size);
ctx.restore();
}
// HSVの値からカラースタイルを生成する。
//
// h: 色相(0 〜 1, 1より大きな値の場合も0〜1の範囲で循環する)
// s: 彩度(0 〜 1)
// v: 明度(0 〜 1)
// a: 不透明度(0 〜 1, 省略時は1)
function styleWithHSV(h, s, v, a = 1) {
const i = Math.floor(h * 6);
const f = h * 6 - i;
const p = v * (1 - s);
const q = v * (1 - f * s);
const t = v * (1 - (1 - f) * s);
let r, g, b;
switch (i % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
return `rgba(${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(b * 255)}, ${a})`;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment