Blog
canvasのテスト
HTML5の目玉機能(?)、canvas要素とJavascriptでいろいろサンプル作成中。画面をマウスクリックでパーティクルが吸着するよ。
追記:ちょっと修正 (19:30)
Javascriptのソースはこんな感じ。
const NUM = 500; //円の数 const WIDTH = 400; //画面の幅 const HEIGHT = 400; //画面の高さ var speedX = new Array(NUM); //X方向のスピードの配列 var speedY = new Array(NUM); //Y方向のスピードの配列 var locX = new Array(NUM); //円の中心位置のX座標の配列 var locY = new Array(NUM); //円の中心位置のY座標の配列 var radius = new Array(NUM); //円の半径の配列 var r = new Array(NUM); //Red成分の配列 var g = new Array(NUM); //Green成分の配列 var b = new Array(NUM); //Blue成分の配列 var ctx; //描画コンテキスト var mouseX, mouseY; //マウス座標 var mouseMoved = false; //マウスが移動しているか否か var mouseDown = false; //マウスクリックしているか否か //ばねのパラメーター var stiffness = 0.03, damping = 0.99, mass = 10.0; window.onload = function() { setup(); }; function setup(){ var canvas = document.getElementById('tutorial'); if (canvas.getContext){ ctx = canvas.getContext('2d'); //イベントリスナー:マウス移動 canvas.onmousemove = mouseMoveListner; canvas.onmousedown = mouseDownListner; canvas.onmouseup = mouseUpListner; //初期値を生成して配列に格納 for(var i = 0; i < NUM; i++){ locX[i] = WIDTH / 2; locY[i] = HEIGHT / 2; radius[i] = Math.random() * 6.0 + 2.0; r[i] = Math.floor(Math.random() * 32); g[i] = Math.floor(Math.random() * 64); b[i] = Math.floor(Math.random() * 128); } //スピード初期化 randomVector(); //60fps setInterval(update, 1000.0/60.0); } } function update(){ //もしマウスクリックしていたらばねの動きでマウスに吸着 if(mouseDown){ for(var i = 0; i < NUM; i++){ var forceX = stiffness * (mouseX - locX[i]); var accelerationX = forceX / mass; speedX[i] = damping * (speedX[i] + accelerationX); var forceY = stiffness * (mouseY - locY[i]); var accelerationY = forceY / mass; speedY[i] = damping * (speedY[i] + accelerationY); } } //座標を更新 for(var i = 0; i < NUM; i++){ locX[i] += speedX[i]; locY[i] += speedY[i]; if(getLength(locX[i], locY[i], WIDTH/2 , HEIGHT/2) > WIDTH*0.75){ speedX[i] *= -1; speedY[i] *= -1; } } //drawを実行 draw(); } function draw(){ //背景を描画 ctx.globalCompositeOperation = "source-over"; ctx.fillStyle = "rgba(0,0,0,.1)"; ctx.fillRect(0, 0, WIDTH, HEIGHT); //更新した座標で円を描く ctx.globalCompositeOperation = "lighter"; for(var i = 0; i < NUM; i++){ ctx.beginPath(); ctx.fillStyle = 'rgba(' + r[i] + ',' + g[i] + ',' + b[i] + ', 0.8)'; ctx.arc(locX[i], locY[i], radius[i], 0, Math.PI*2.0, true); ctx.fill(); } } function mouseMoveListner(e) { //画面左上からのマウス座標取得 adjustXY(e); //マウスを移動中に mouseMoved = true; } function mouseDownListner(e) { mouseDown = true; } function mouseUpListner(e) { mouseDown = false; randomVector(); } //ランダムな方向にスピード設定 function randomVector(){ for(var i = 0; i < NUM; i++){ var length = Math.random() * 1.0 + 2.0; var angle = Math.random() * Math.PI * 2.0; speedX[i] = Math.cos(angle) * length; speedY[i] = Math.sin(angle) * length; } } //二点間の距離 function getLength(x1 , y1 , x2 , y2 ) { var pointLength; pointLength = Math.sqrt(Math.pow(x2 - x1 , 2 )+Math.pow(y2 - y1 , 2 )); return pointLength; } //画面左上からのマウス座標を求める function adjustXY(e) { var rect = e.target.getBoundingClientRect(); mouseX = e.clientX - rect.left; mouseY = e.clientY - rect.top; }