canvasとccs3でアニメーション
canvasとccs3
先日jsdo.itで「HTML5+CSS3+JavaScriptで「代表試合」の演出を考えてください。」
というお題が挙げられたので試しに出してみました。
当初ルールをよく読んでおらず、Canvasで作り終わってみて
「◇今回はCanvasとSVGは無し。」という条件が入っていたことに気がつき
途中からCSS3で書き直しました。せっかく書いたのでCanvas版とCSS3版の両方をメモとして残しておきます。
応募
http://jsdo.it/Event/7E8o
自分の作品
http://jsdo.it/Fumitoshi.Ogata/y5BB
CanvasとCSS3の違いはどちらもタイムラインを設定して時間を進めていく事には変わりないのですが、
Canvasは進め方がjavascriptの$i++などで時間を進めていくのに対して、
CSS3は@-webkit-keyframesを使って0%から100%と%を使って時間を進めていく事に違いがあります。
Canvas版
html
<html lang="ja-JP"> <head> <meta charset="UTF-8"> <title>COLOPL inc.</title> <meta name="format-detection" content="telephone=no"> <meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1, maximum-scale=1"/> <meta name="apple-mobile-web-app-capable" content="yes"> </head> <body> <div style="text-align:center;"> <canvas id="testCanvas" width="320" height="480" style="border:0px solid #CCC;"></canvas> </div> </body> </html>
css
body { background-color: #000000; }
javascript
// forked from Event's "SPEC vol.4 投稿用コード" http://jsdo.it/Event/7E8o var timerID; var cW=320; var cH=480; var back_X=0; var back_Y=0; var human_X=-50; var human_Y=0; window.onload = function(){ setTimer(); } //フレームレート function setTimer(){ clearInterval(timerID); timerID = setInterval("setMove()", 100); } //制御 function setMove(){ back_Y-=5; if(back_Y<-2000){ back_Y=0; } human_X+=1; if(human_X>=80){ human_X = 100; } draw(); } var i=0; var movie_timer=0; var logo1_x = 100; var pitcher_x = -150; var logo2_x = 0; var batter_x = 0; var ball_size = 50; var ball_x = 100; //描画 function draw(){ movie_timer++; var canvas=document.getElementById('testCanvas'); if (!canvas||!canvas.getContext) return false; var ctx = canvas.getContext('2d'); //read image particle =new Image(); particle.src = "/particle3.png"; hikari =new Image(); hikari.src = "./hikari.png"; logo1 =new Image(); logo1.src = "./logo1.png"; logo2 =new Image(); logo2.src = "./logo2.png"; ball = new Image(); ball.src = "./ball.png"; pitcher = new Image(); pitcher.src = "./pitcher.png"; batter = new Image(); batter.src = "./batter.png"; cover_img = new Image(); cover_img.src = "./coverb.png"; cover_img2 = new Image(); cover_img2.src = "./coverb2.png"; cover_img3 = new Image(); cover_img3.src = "./coverb3.png"; daihyou = new Image(); daihyou.src = "./daihyou4.png?11"; daihyou2 = new Image(); daihyou2.src = "./daihyou4.png?21"; //action manage if(movie_timer<=20){ //action logo1_x -= 10; if(logo1_x <= 0){logo1_x = 0;} pitcher_x += 15; if(pitcher_x >= 0){pitcher_x = 0;} //draw ctx.drawImage(cover_img, 0, 0, 320, 480); ctx.drawImage(pitcher, pitcher_x, 50 ); ctx.drawImage(logo1, logo1_x, 50 ); }else if((movie_timer>20) && (movie_timer<=40)){ //action logo2_x += 10; if(logo2_x >= 80){logo2_x = 80;} batter_x -= 15; if(batter_x <= -120){batter_x = -120;} //draw ctx.drawImage(cover_img2, 0, 0, 320, 480); ctx.drawImage(batter, batter_x, 50 ); ctx.drawImage(logo2, logo2_x, 250 ); }else if((movie_timer>40) && (movie_timer<=80)){ //action ctx.drawImage(cover_img3, 0, 0, 320, 480); ball_size += 30; ball_x -= 10; if(ball_size <= 300){ctx.drawImage(ball, ball_x, 100, ball_size, ball_size); }else{ if(movie_timer >= 50){ if(movie_timer%2==0){ ctx.drawImage(daihyou, 0, 130 ); }else{ ctx.drawImage(daihyou2, 0, 130 ); } } ctx.drawImage(logo1, logo1_x, 50 ); ctx.drawImage(logo2, logo2_x, 250 ); } } if(movie_timer<=80){ var rand_x = Math.floor( Math.random() * 200 ); ctx.drawImage(particle, 50-rand_x, 0); } if((movie_timer%5==0)&& (movie_timer<=78)){ var rand_x = Math.floor( Math.random() * 200 ); var rand_y = Math.floor( Math.random() * 200 ); ctx.drawImage(hikari, rand_x-50, rand_y-50 ); } //ctx.font = "18px 'MS Pゴシック'"; //ctx.fillStyle = "Red"; //ctx.fillText(movie_timer,40,260); //ctx.fillText("debug comment",40,280); }
CSS3版
html
<html lang="ja-JP"> <head> <meta charset="UTF-8"> <title>COLOPL inc.</title> <meta name="format-detection" content="telephone=no"> <meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1, maximum-scale=1"/> <meta name="apple-mobile-web-app-capable" content="yes"> </head> <body> <div id="bossEffect" class="homeTeam1 awayTeam2"> <div id="teamColorSet"> <div id="crossLine"></div> </div> <div id="coverImg1"><img src="./coverb.png" alt="背景1"></div> <div id="coverImg2"><img src="./coverb2.png" alt="背景2"></div> <div id="coverImg3"><img src="./coverb3.png" alt="背景3"></div> <div id="pitcherImg"><img src="./pitcher.png" alt="ピッチャー"></div> <div id="batterImg"><img src="./batter.png" alt="バッター"></div> <div id="logo1Img"><img src="./logo1.png" alt="ロゴ1"></div> <div id="logo2Img"><img src="./logo2.png" alt="ロゴ2"></div> <div id="pitcher2Img"><img src="./pitcher2.png?12" alt="ピッチャー2"></div> <div id="fireImg"><img src="./fire.png?111" alt="炎"></div> <div id="ballImg"><img src="./ball.png" alt="ボール"></div> <div id="txtImg"><img src="./daihyou.png" alt="代表試合"></div> <div id="cameraFlashImg"><img src="./hikari.png" alt="カメラフラッシュ"></div> <div id="cameraFlashImg2"><img src="./hikari.png" alt="カメラフラッシュ2"></div> <div id="cameraFlashImg3"><img src="./hikari.png" alt="カメラフラッシュ3"></div> <div id="particleImg"><img src="./particle3.png" alt="パーティクル"></div> </div> <input id="btnStart" type="button" value="スタート"> <input id="btnReset" type="button" value="リセット"> </body> </html>
css
html, body, h1, h2, h3, h4, h5, h6, ul, ol, dl, li, dt, dd, p, header, hgroup, section, article, aside, hgroup, footer, figure, figcaption, nav { position: relative; margin: 0; padding: 0; font-size: 100%; font-weight: normal; font-family: "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", "メイリオ", Meiryo, Osaka, "MS Pゴシック", "MS PGothic", sans-serif; } ul, ol, dl, li, dt, dd{ list-style: none; } body { position: relative; width: 100%; line-height: 1.0; background-color: #a6a6a6; -webkit-text-size-adjust: none; text-align: center; } #bossEffect{ position: relative; margin: 0 auto; width: 320px; height:480px; background: url(http://ooedo-img.blamestitch.com/baseball/coverb3.png) center top no-repeat; -webkit-background-size: 100% auto; background-size: 100% auto; overflow:hidden; } #teamColorSet{ position: absolute; width: 100%; height: 100%; } #coverImg1 { position: absolute; height: 100%; width: 100%; text-align: center; vertical-align: middle; opacity: 0; } .animeStart #coverImg1{-webkit-animation: 'animeCover1' 6s ease-in;} #coverImg2 { position: absolute; height: 100%; width: 100%; text-align: center; vertical-align: middle; opacity: 0; } .animeStart #coverImg2{-webkit-animation: 'animeCover2' 6s ease-in;} #coverImg3 { position: absolute; height: 100%; width: 100%; text-align: center; vertical-align: middle; opacity: 0; } .animeStart #coverImg3{-webkit-animation: 'animeCover3' 6s ease-in;} #logo1Img { position: absolute; opacity: 1; -webkit-transform:translate(0px,20px); } .animeStart #logo1Img{-webkit-animation: 'animeLogo1' 6s ease-in;} #logo2Img { position: absolute; opacity: 1; -webkit-transform:translate(70px,300px); } .animeStart #logo2Img{-webkit-animation: 'animeLogo2' 6s ease-in;} #ballImg { position: absolute; opacity: 0; } .animeStart #ballImg{-webkit-animation: 'animeBall' 6s ease-in;} #txtImg { position: absolute; opacity: 1; } .animeStart #txtImg{-webkit-animation: 'animeTxt' 6s ease-in;} #fireImg { position: absolute; opacity: 0; } .animeStart #fireImg{-webkit-animation: 'animeFire' 6s ease-in;} #pitcherImg { position: absolute; opacity: 0; } .animeStart #pitcherImg{-webkit-animation: 'animePitcher' 6s ease-in;} #pitcher2Img { position: absolute; opacity: 0; } .animeStart #pitcher2Img{-webkit-animation: 'animePitcher2' 6s ease-in;} #batterImg { position: absolute; opacity: 0; } .animeStart #batterImg{-webkit-animation: 'animeBatter' 6s ease-in;} #cameraFlashImg { position: absolute; opacity: 0; -webkit-transform:translate(-20px,-20px); } #cameraFlashImg2 { position: absolute; opacity: 0; -webkit-transform:translate(100px,120px); } #cameraFlashImg3 { position: absolute; opacity: 0; -webkit-transform:translate(-70px,270px); } .animeStart #cameraFlashImg{ -webkit-animation: 'animeCameraFlash'; -webkit-animation-duration: 0.5s;/* 0.5秒かけて実行 */ -webkit-animation-iteration-count:5;/* 何回実行するか。infiniteで無限 */ -webkit-animation-timing-function:ease-in-out;/* イーズインアウト */ -webkit-animation-direction: alternate;/* alternateにするとアニメーションが反復 */ -webkit-animation-delay: 0s; /* 実行までの待ち時間 */ } .animeStart #cameraFlashImg2{ -webkit-animation: 'animeCameraFlash2'; -webkit-animation-duration: 1s;/* 1秒かけて実行 */ -webkit-animation-iteration-count:5;/* 何回実行するか。infiniteで無限 */ -webkit-animation-timing-function:ease-in-out;/* イーズインアウト */ -webkit-animation-direction: alternate;/* alternateにするとアニメーションが反復 */ -webkit-animation-delay: 0s; /* 実行までの待ち時間 */ } .animeStart #cameraFlashImg3{ -webkit-animation: 'animeCameraFlash3'; -webkit-animation-duration: 1s;/* 1秒かけて実行 */ -webkit-animation-iteration-count:5;/* 何回実行するか。infiniteで無限 */ -webkit-animation-timing-function:ease-in-out;/* イーズインアウト */ -webkit-animation-direction: alternate;/* alternateにするとアニメーションが反復 */ -webkit-animation-delay: 0s; /* 実行までの待ち時間 */ } #particleImg { position: absolute; opacity: 0.6; } .animeStart #particleImg{ -webkit-animation: 'animeParticle'; -webkit-animation-duration: 1s;/* 0.3秒かけて実行 */ -webkit-animation-iteration-count:5;/* 何回実行するか。infiniteで無限 */ -webkit-animation-timing-function:ease-in-out;/* イーズインアウト */ -webkit-animation-direction: alternate;/* alternateにするとアニメーションが反復 */ -webkit-animation-delay: 0s; /* 実行までの待ち時間 */ } /*animation*/ @-webkit-keyframes animeLogo1 { 0% {opacity: 1;-webkit-transform:translate(100px,20px) scale(1)} 30% {opacity: 1;-webkit-transform:translate(0px,20px) scale(1)} 35% {opacity: 0;-webkit-transform:translate(0px,20px) scale(1)} 60% {opacity: 0;-webkit-transform:translate(0px,20px) scale(1)} 80% {opacity: 0;-webkit-transform:translate(0px,20px) scale(1)} 85% {opacity: 1;-webkit-transform:translate(0px,20px) scale(1)} 100% {opacity: 1;-webkit-transform:translate(0px,20px) scale(1)} } @-webkit-keyframes animeLogo2 { 0% {-webkit-transform:scale(1);opacity: 0;} 30% {opacity: 0;-webkit-transform:translate(0px,300px) scale(1)} 35% {opacity: 1;-webkit-transform:translate(0px,300px) scale(1)} 60% {opacity: 1;-webkit-transform:translate(70px,300px) scale(1)} 65% {opacity: 1;-webkit-transform:translate(70px,300px) scale(1)} 66% {opacity: 0;-webkit-transform:translate(70px,300px) scale(1)} 80% {opacity: 0;-webkit-transform:translate(70px,300px) scale(1)} 85% {opacity: 1;-webkit-transform:translate(70px,300px) scale(1)} 100% {opacity: 1;-webkit-transform:translate(70px,300px) scale(1)} } /*animation*/ @-webkit-keyframes animeCover1 { 0% {-webkit-transform:scale(1);opacity: 1;} 30% {-webkit-transform:scale(1);opacity: 1;} 35% {-webkit-transform:scale(1);opacity: 0;} 100% {-webkit-transform:scale(1);opacity: 0;} } @-webkit-keyframes animeCover2 { 0% {-webkit-transform:scale(1);opacity: 0;} 30% {-webkit-transform:scale(1);opacity: 0;} 35% {-webkit-transform:scale(1);opacity: 1;} 60% {-webkit-transform:scale(1);opacity: 1;} 65% {-webkit-transform:scale(1);opacity: 0;} 100% {-webkit-transform:scale(1);opacity: 0;} } @-webkit-keyframes animeCover3 { 0% {-webkit-transform:scale(1);opacity: 0;} 60% {-webkit-transform:scale(1);opacity: 0;} 65% {-webkit-transform:scale(1);opacity: 1;} 100% {-webkit-transform:scale(1);opacity: 1;} } @-webkit-keyframes animePitcher { 0% {opacity: 0.5;-webkit-transform:translate(-60px,60px) scale(0.8)} 30% {opacity: 1;-webkit-transform:translate(0px,60px) scale(0.8)} 35% {opacity: 0;-webkit-transform:translate(0px,60px) scale(0.8)} 70% {opacity: 0;-webkit-transform:translate(0px,60px) scale(0.8)} 100% {opacity: 0;-webkit-transform:translate(0px,60px) scale(0.8)} } @-webkit-keyframes animePitcher2 { 0% {opacity: 0;-webkit-transform:translate(-80px,0px) scale(0.7)} 60% {opacity: 0;-webkit-transform:translate(-80px,0px) scale(0.7)} 68% {opacity: 1;-webkit-transform:translate(-80px,0px) scale(0.7)} 80% {opacity: 1;-webkit-transform:translate(-80px,0px) scale(0.7)} 85% {opacity: 0;-webkit-transform:translate(-80px,0px) scale(0.7)} 100% {opacity: 0;-webkit-transform:translate(-80px,0px) scale(0.7)} } @-webkit-keyframes animeBatter { 0% {opacity: 0;-webkit-transform:translate(0px,20px) scale(0.8)} 30% {opacity: 0;-webkit-transform:translate(0px,20px) scale(0.8)} 35% {opacity: 0.5;-webkit-transform:translate(0px,20px) scale(0.8)} 60% {opacity: 1;-webkit-transform:translate(-80px,20px) scale(0.9)} 65% {opacity: 0;-webkit-transform:translate(-80px,20px) scale(0.8)} 100% {opacity: 0;-webkit-transform:translate(-80px,20px) scale(0.8)} } @-webkit-keyframes animeBall { 0% {opacity: 0;-webkit-transform:translate(20px,60px) scale(0.0)} 60% {opacity: 0;-webkit-transform:translate(20px,60px) scale(0.2)} 80% {opacity: 1;-webkit-transform:translate(20px,60px) scale(0.8)} 85% {opacity: 1;-webkit-transform:translate(20px,60px) scale(1.0)} 87% {opacity: 0;-webkit-transform:translate(20px,60px) scale(1.4)} 100% {opacity: 0;-webkit-transform:translate(20px,60px) scale(1.0)} } @-webkit-keyframes animeTxt { 0% {opacity: 0;-webkit-transform:translate(0px,0px) scale(1.0)} 84% {opacity: 0;-webkit-transform:translate(0px,0px) scale(1.0)} 95% {opacity: 1;-webkit-transform:translate(0px,0px) scale(1.0)} 100% {opacity: 1;-webkit-transform:translate(0px,0px) scale(1.0)} } @-webkit-keyframes animeFire { 0% {opacity: 0;-webkit-transform:translate(0px,0px) scale(1.0)} 77% {opacity: 0;-webkit-transform:translate(0px,0px) scale(1.0)} 83% {opacity: 1;-webkit-transform:translate(0px,0px) scale(1.0)} 93% {opacity: 0;-webkit-transform:translate(0px,0px) scale(1.0)} } @-webkit-keyframes animeCameraFlash { 0% {opacity: 0;} 10% {opacity: 0.7;} 20% {opacity: 0;} } @-webkit-keyframes animeCameraFlash2 { 20% {opacity: 0;} 30% {opacity: 0.7;} 40% {opacity: 0;} } @-webkit-keyframes animeCameraFlash3 { 40% {opacity: 0;} 50% {opacity: 0.7;} 60% {opacity: 0;} } @-webkit-keyframes animeParticle { 0% {opacity: 0.7;-webkit-transform: translate(-200px);} 10% {opacity: 0.4;-webkit-transform: translate(-100px);} 20% {opacity: 0.7;-webkit-transform: translate(-30px);} 30% {opacity: 0.5;-webkit-transform: translate(-60px);} 40% {opacity: 0.7;-webkit-transform: translate(-120px);} 50% {opacity: 0.3;-webkit-transform: translate(-90px);} 60% {opacity: 0.7;-webkit-transform: translate(-10px);} 70% {opacity: 0.6;-webkit-transform: translate(-150px);} 80% {opacity: 0.7;-webkit-transform: translate(-80px);} 90% {opacity: 0.8;-webkit-transform: translate(-40px);} 100%{opacity: 0.7;-webkit-transform: translate(0px);} }
javascript
(function(){ var BossEffect = { loaded:function(){ var _self = this, defaultClass; var bossEffect$ = document.getElementById('bossEffect'), crossLine$ = document.getElementById('crossLine'), btnStart$ = document.getElementById('btnStart'), btnReset$ = document.getElementById('btnReset'); var winWidth = 320, winHeight = 480; var rotateDeg = Math.atan2(winWidth, winHeight) * 180 / Math.PI + 'deg'; var lineLength = Math.sqrt((winWidth*winWidth) + (winHeight*winHeight))+2; crossLine$.style.webkitTransform = 'rotate(' + rotateDeg + ')'; crossLine$.style.height = lineLength + 'px'; btnStart$.addEventListener('click', function (ev) { if(!defaultClass){ defaultClass = bossEffect$.getAttribute('class'); bossEffect$.setAttribute('class', defaultClass+ ' animeStart'); } }, false); btnReset$.addEventListener('click', function () { bossEffect$.setAttribute('class', defaultClass); defaultClass = ''; }, false); } }; document.addEventListener("DOMContentLoaded",function(){ BossEffect.loaded(); },false); })();