プログラミング初心者のための「HTML・CSS・Javascript」で作るアニメーションアプリ開発入門
プログラミング初心者の方にとってハードルが高く感じてしまいがちな「アニメーションアプリ開発」ですが、「HTML・CSS・Javascript」を利用してアニメーションアプリを作ることができます。
「アニメーションアプリの作り方」も複数あり、シンプルなアプリケーションを作りながら、少しずつ「アニメーションの作り方」を学んでいきましょう。
アニメーション作成のバリエーション
WEBアプリケーションでアニメーションを表示する方法には、
- HTML要素をJavascriptで操作
- CSS3のアニメーション機能を利用
- HTML5のCANVAS要素を利用
などの方法がありますが、今回は「HTML5のCANVAS要素を利用」する方法でアニメーション処理を作っていきたいと思います。
CANVASの座標系
CANVASは、Javascriptのプログラムで図形を描画しますが、まず初めに「CANVAS要素」をHTML内に用意しておきます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex,nofollow">
<title>WEB SCREEN APP</title>
<style>
#screen {
border: solid 1px #000000;
}
</style>
</head>
<body>
<canvas id="screen"></canvas>
</body>
</html>
CANVASの座標系は下図のように、右側へ行くほど「X座標値」が増加し、下側へ行くほど「Y座標値」が増加します。

左上の黒い枠線はCANVAS要素を表しています。
CANVASに図形を描画する方法
CANVAS要素のDOMを取得後、CANVASの2Dコンテキストを取得します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex,nofollow">
<title>WEB SCREEN APP</title>
<style>
#screen {
border: solid 1px #000000;
}
</style>
</head>
<body>
<canvas id="screen"></canvas>
<script>
//canvas要素のDOM(Document Object Model)を取得
var canvas = document.getElementById('screen');
var context;
//コンテキストの取得可否チェック
if(canvas.getContext){
//canvas要素のコンテキストを取得
context = canvas.getContext('2d');
}
</script>
<div id="link"></div>
</body>
</html>
描画処理を行う場合は、取得したコンテキストに対して描画用の関数を実行します。
例えば「円・半円・四角」を描画する場合は次のようになります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex,nofollow">
<title>WEB SCREEN APP</title>
<style>
#screen {
border: solid 1px #000000;
}
</style>
</head>
<body>
<canvas id="screen"></canvas>
<script>
//canvas要素のDOM(Document Object Model)を取得
var canvas = document.getElementById('screen');
var context;
//コンテキストの取得可否チェック
if(canvas.getContext){
//canvas要素のコンテキストを取得
context = canvas.getContext('2d');
//現在の描画パスをリセット
context.beginPath();
//円の描画設定
context.arc(30, 30, 15, 0, Math.PI*2, true);
//円(円弧)の描画設定
context.arc(70, 30, 15, 0, Math.PI, true);
//円と円弧の描画
//context.fill();
//四角の描画
context.fillRect(100, 15, 30, 30);
}
</script>
<div id="link"></div>
</body>
</html>
このプログラムを実行すると下図のように、塗りつぶされた「円・円弧・四角」が表示されます。

CANVASヘの描画方法にはさまざまな方法が用意されていますので、図形を描画しながらCANVASへの図形描画方法を身に付けていきましょう。
アニメーション機能を実装してみよう!
今回作成するアニメーションは下の動画のようなものです。
「MOVE」ボタンを押すと、ボールが動き出し、「STOP」ボタンを押すとボールが停止します。
動画内で「動いているボール」を管理するためにボールの「クラス(設計図)」を作ります。
「クラス」とは、「オブジェクトの設計図」のことを言いますが、今回の場合、「オブジェクト」は「動いているボール」に相当します。
「動いているボールの設計図」が「クラス」となります。
- ボールのX座標位置
- ボールのY座標位置
- ボールの移動速度
- ボールの回転角度
などの情報を「クラス」として定義し、ボールの「実体(インスタンス)」を作ります。

クラスをJavascriptで定義すると下記のようになります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex,nofollow">
<title>WEB SCREEN APP</title>
<style>
body {
margin: 0;
}
#screen {
width: 50%;
height: 50%;
border: solid 1px #000000;
}
</style>
</head>
<body>
<canvas id="screen"></canvas>
<script>
//canvas要素のDOM(Document Object Model)を取得
var canvas = document.getElementById('screen');
var context;
class Ball{
constructor(x, y, width, height, rotFlg, speed,image_fname ) {
this.posX = x; // X座標位置
this.posY = y; // Y座標位置
this.width = width; // 画像の横幅
this.height = height; // 画像の縦幅
this.posXmoveDirection = true; // true : X座標増加, false : X座標減少
this.posYmoveDirection = true; // true : Y座標増加, false : Y座標減少
this.moveSpeed = speed; // 移動速度
this.rotateAngle = 0; // 回転角度
this.rotateFlag = rotFlg; // 回転フラグ
// Imageオブジェクト生成
var img = new Image();
// 画像ファイルを読み込み
img.src = image_fname;
// 画像ファイルをセット
this.image = img;
}
move(){
if( this.posXmoveDirection === false ) {
this.posX -= this.moveSpeed;
} else {
this.posX += this.moveSpeed;
}
if( this.posYmoveDirection === false ) {
this.posY -= this.moveSpeed;
} else {
this.posY += this.moveSpeed;
}
}
}
//コンテキストの取得可否チェック
if(canvas.getContext){
//canvas要素のコンテキストを取得
context = canvas.getContext('2d');
}
</script>
</body>
</html>
「constructor(コンストラクタ)」は、ボールの実体(インスタンス)を作る際に自動的に呼ばれて実行されるメソッドです。
クラスは、「情報(プロパティ)」と「動作(メソッド)」を定義することができ、コンストラクタ内の「this.~」という部分では、プロパティを定義しています。
プロパティの部分は、
- posX
- ボールのX座標位置
- posY
- ボールのY座標位置
- width
- ボール画像の横幅
- height
- ボール画像の縦幅
- posXmoveDirection
- ボールのX座標の移動方向
- posYmoveDirection
- ボールのX座標の移動方向
- moveSpeed
- ボールの移動速度
- rotateAngle
- ボールの回転角度
- rotateFlag
- ボールの回転フラグ
- image
- ボールの画像イメージオブジェクト
となります。
一方、「動作(メソッド)」は、
- constructor
- コンストラクタ
- move
- ボールの移動メソッド
となっています。
コンストラクタには「引数」を渡すことができますので、ボールの実体(インスタンス)を作る際に「ボールの情報の設定値」を渡すことができます。

インスタンスを作る際には「new」キーワードの右にクラス名を書き、コンストラクタに渡す引数を指定します。
new クラス名(コンストラクタに渡す引数);
今回は、8個のボールを作りますので、8個のインスタンスを作ります。
ボールのインスタンスは配列に格納し、「ボールの移動」を行う際には、配列内のインスタンスに対して「move」メソッドを実行します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex,nofollow">
<title>WEB SCREEN APP</title>
<style>
body {
margin: 0;
}
#screen {
width: 50%;
height: 50%;
border: solid 1px #000000;
}
#control {
background-color: #5f5f5f;
padding: 2px
}
</style>
</head>
<body>
<canvas id="screen"></canvas>
<div id="control">
<button id="move_btn">MOVE</button>
<button id="stop_btn">STOP</button>
</div>
<script>
//canvas要素のDOM(Document Object Model)を取得
var canvas = document.getElementById('screen');
var context;
var objArray = new Array();
class Ball{
constructor(x, y, width, height, rotFlg, speed,image_fname ) {
this.posX = x; // CanvasのX座標
this.posY = y; // CanvasのY座標
this.width = width; // 画像の横幅
this.height = height; // 画像の縦幅
this.posXmoveDirection = true; // true : X座標増加, false : X座標減少
this.posYmoveDirection = true; // true : Y座標増加, false : Y座標減少
this.moveSpeed = speed; // 移動速度
this.rotateAngle = 0; // 回転角度
this.rotateFlag = rotFlg; // 回転フラグ
// Imageオブジェクト生成
var img = new Image();
// 画像ファイルを読み込み
img.src = image_fname;
// 画像ファイルをセット
this.image = img;
}
move(){
if( this.posXmoveDirection === false ) {
this.posX -= this.moveSpeed;
} else {
this.posX += this.moveSpeed;
}
if( this.posYmoveDirection === false ) {
this.posY -= this.moveSpeed;
} else {
this.posY += this.moveSpeed;
}
}
}
//コンテキストの取得可否チェック
if(canvas.getContext){
//canvas要素のコンテキストを取得
context = canvas.getContext('2d');
// new Ball(X座標,Y座標,横幅,高さ,回転有無,移動速度,画像ファイル名)
objArray.unshift(
new Ball(150,75,30,30,false,0.4,"./img/image1.png"),
new Ball(70,120,30,30,true,0.6,"./img/image2.png"),
new Ball(45,115,30,30,true,0.8,"./img/image3.png"),
new Ball(53,45,30,30,true,1.0,"./img/image4.png"),
new Ball(178,103,30,30,false,1.2,"./img/image5.png"),
new Ball(223,141,30,30,false,1.4,"./img/image6.png"),
new Ball(255,111,30,30,false,1.6,"./img/image7.png"),
new Ball(215,121,30,30,true,1.8,"./img/image8.png")
);
}
</script>
</body>
</html>
ボールを動かすためには「Ballクラス」の「moveメソッド」を実行します。
「moveメソッド」は、アニメーションの1フレームごとにボールのX・Y座標を移動しているだけなのですが、「moveSpeedプロパティ」の設定値でボールごとに、「ボールの移動量」を変化させています。
計算を簡単にするために移動角度は「45度」のみとしました。
こうすることで、「SIN・COS」などの三角関数で幾何計算を行わなくてもボールが移動できるようになります。
移動パターンは下図の4通りとなります。

ボールが「CANVAS要素の端」に到達した場合は、ボールの移動方向を反転させるため、
- posXmoveDirection
- ボールのX座標の移動方向
- posYmoveDirection
- ボールのX座標の移動方向
の2つの変数でボールの移動方向を制御しています。
「posXmoveDirection」が「true」の時にボールのX座標が増加し、「false」の時はX座標が減少します。
「posYmoveDirection」が「true」の時にボールのY座標が増加し、「false」の時はY座標が減少します。
ボールの移動方向を変更するタイミングは、CANVAS要素の「枠」にボールが触れた時です。

座標の増減を制御しているメソッドが、Ballクラスの「moveメソッド」です。
class Ball{
constructor(x, y, width, height, rotFlg, speed,image_fname ) {
//省略
}
move(){
if( this.posXmoveDirection === false ) {
this.posX -= this.moveSpeed;
} else {
this.posX += this.moveSpeed;
}
if( this.posYmoveDirection === false ) {
this.posY -= this.moveSpeed;
} else {
this.posY += this.moveSpeed;
}
}
}
これでアニメーションを行う準備ができました。
アニメーションを行うためには、一定時間ごとに「ボールの座標」を移動する必要がありますが、この処理は「setInterval」「clearInterval」メソッドを使用します。
- setInterval
- 一定時間ごとに繰り返し処理を開始する
- clearInterval
- serIntervalで開始した繰り返し処理を停止する
「setInterval」と「clearInterval」は下記のようになります。
// 繰り返し処理を実行したい関数
function hoge(){
// 繰り返し実行したい処理を記述
}
var timerID;
// 繰り返し処理を開始
timerID = setInterval(hoge, 33);
// 繰り返し処理を停止
clearInterval(timerID);
「setIntervalメソッド」の第1引数には「実行したいメソッド名」、第2引数には「繰り返し間隔」を「ミリ秒」で指定します。
戻り値には繰り返し処理を停止するためのIDが返ってきますので、「clearIntervalメソッド」の引数にこの値を渡すと、繰り返し処理を停止することができます。
これでようやくアニメーションができるようになりました。
完成したコードは下記のようになります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex,nofollow">
<title>WEB SCREEN APP</title>
<style>
body {
margin: 0;
}
#screen {
width: 50%;
height: 50%;
border: solid 1px #000000;
}
#control {
background-color: #5f5f5f;
padding: 2px
}
</style>
</head>
<body>
<canvas id="screen"></canvas>
<div id="control">
<button id="move_btn">MOVE</button>
<button id="stop_btn">STOP</button>
</div>
<script>
var timer_id = null;
var canvas = document.getElementById('screen');
var context;
var timerID = null;
var objArray = new Array();
const INTERVAL = 1000;
class Ball{
constructor(x, y, width, height, rotFlg, speed,image_fname ) {
this.posX = x; // CanvasのX座標
this.posY = y; // CanvasのY座標
this.width = width; // 画像の横幅
this.height = height; // 画像の縦幅
this.posXmoveDirection = true; // true : X座標増加, false : X座標減少
this.posYmoveDirection = true; // true : Y座標増加, false : Y座標減少
this.moveSpeed = speed; // 移動速度
this.rotateAngle = 0; // 回転角度
this.rotateFlag = rotFlg; // 回転フラグ
// Imageオブジェクト生成
var img = new Image();
// 画像ファイルを読み込み
img.src = image_fname;
// 画像ファイルをセット
this.image = img;
}
move(){
if( this.posXmoveDirection === false ) {
this.posX -= this.moveSpeed;
} else {
this.posX += this.moveSpeed;
}
if( this.posYmoveDirection === false ) {
this.posY -= this.moveSpeed;
} else {
this.posY += this.moveSpeed;
}
}
}
//コンテキストの取得可否チェック
if(canvas.getContext){
//canvas要素のコンテキストを取得
context = canvas.getContext('2d');
// new Ball(X座標,Y座標,横幅,高さ,移動速度,回転有無,画像ファイル名)
objArray.unshift(
new Ball(150,75,30,30,false,0.4,"./img/image1.png"),
new Ball(70,120,30,30,true,0.6,"./img/image2.png"),
new Ball(45,115,30,30,true,0.8,"./img/image3.png"),
new Ball(53,45,30,30,true,1.0,"./img/image4.png"),
new Ball(178,103,30,30,false,1.2,"./img/image5.png"),
new Ball(223,141,30,30,false,1.4,"./img/image6.png"),
new Ball(255,111,30,30,false,1.6,"./img/image7.png"),
new Ball(215,121,30,30,true,1.8,"./img/image8.png")
);
}
function move(){
context.clearRect(0, 0, canvas.width, canvas.height);
objArray.forEach(function( obj ) {
if(obj.posX >= canvas.width - (obj.width / 2)){
obj.posXmoveDirection = false;
}
if(obj.posX <= (obj.width / 2)){
obj.posXmoveDirection = true;
}
if(obj.posY >= canvas.height - (obj.height / 2)){
obj.posYmoveDirection = false;
}
if(obj.posY <= (obj.height / 2)){
obj.posYmoveDirection = true;
}
obj.move();
context.beginPath();
if(obj.rotateFlag === true){
context.save();
context.translate(obj.posX, obj.posY);
obj.rotateAngle++;
context.rotate(( obj.rotateAngle % 360 ) / 180 * Math.PI);
context.translate(-obj.width/2, -obj.height/2);
context.drawImage(obj.image, 0, 0);
context.restore();
} else {
context.drawImage(obj.image, obj.posX - (obj.width/2), obj.posY - (obj.height/2));
}
});
}
function start_move(){
timer_id = setInterval(move, 33);
}
function stop () {
clearInterval(timer_id);
}
document.getElementById('move_btn').addEventListener('click', start_move, false);
document.getElementById('stop_btn').addEventListener('click', stop, false);
</script>
</body>
</html>
実際の動きは、下記リンクから確認することができます。
今回作成したアニメーションプログラムはシンプルなものでしたが、本格的なアニメーションを作成するためには「幾何計算」などの専門的な知識が必要となってきます。