canvas遊び
やってみたいことがあって、機能を考えると htmlのcanvas要素が使えそう。
オブジェクトに描画させて、intervalを設定してアニメーションしてマウスに反応して…と考えると、何のことはない、ゲームプログラミングでいうタスクシステムだった。
ということで実装中。
http://bitbucket.org/leather_sole/cantas/
- 済
- タスクの登録
- 更新間隔の設定
- タスクの順次実行
- mouseoverイベントに対応
- これから
- タスクにcanvas以外の要素を持たせる
- タスクに描画要素を複数持たせる
今のところタスクはコードに実装しているが、動きや画像は、データとして持った方がいいんだろうな。後々考えてみよう。
javascriptは、初めてまともに触るけど、細々したところで迷う。今のも、特にスコープがおかしいが、とりあえず動かすの前提で作っている。
bitbucket.org と、ditzを使うのも初めてに近いが、こちらはさほど迷うでもなく使えている。
task.js
var Task = function(canvas_,x,y,angle){ this.canvas = canvas_; this.ctx = this.canvas.getContext("2d"); this.x=x; this.y=y; this.angle=angle; this.operations=[this.moveTo,this.rotate,this.draw]; this.mouseover=false; }; Task.prototype.draw= function(task){ if (!task.mouseover){ var ctx = task.ctx; ctx.fillStyle = "rgb(255,0,0)"; ctx.fillRect (0, 0, 80, 80); ctx.beginPath(); ctx.arc(75,75,50,0,Math.PI*2,false); ctx.fillStyle = "rgba(255,50,100,0.5)"; ctx.fill(); ctx.beginPath(); ctx.arc(85,75,50,0,Math.PI*2,false); ctx.fillStyle = "rgba(55,250,10,0.5)"; ctx.fill(); }else{ var ctx = task.ctx; ctx.beginPath(); ctx.arc(75,75,70,0,Math.PI*2,false); ctx.strokeStyle = "green"; ctx.stroke(); } }; Task.prototype.moveTo= function(task){ var ctx = task.ctx; ctx.translate(task.x,task.y); }; Task.prototype.rotate=function(task){ var ctx = task.ctx; ctx.rotate(task.angle); }; Task.prototype.nextPosition=function(x,y,angle){ this.x=this.x + x; this.y=this.y + y; this.angle = this.angle + angle; }; Task.prototype.show=function(){ var ctx = this.ctx; ctx.save(); this.calculate(); for (var i = 0; i < this.operations.length; i ++){ this.operations[i](this); } ctx.restore(); }; Task.prototype.calculate=function(){ this.nextPosition(0,0,0.1); }; Task.prototype.act = function(x,y,firstObj,task){ var deltaX = x - task.x; var deltaY = y - task.y; var nx = (deltaX != 0) ? deltaX / Math.abs(deltaX) : 0; var ny = (deltaY != 0) ? deltaY / Math.abs(deltaY) : 0; task.nextPosition(nx,ny,0); if (-25 <= deltaX && deltaX <= 25 && -25 <= deltaY && deltaY <= 25 ){ task.mouseover=true; return true; } else{ task.mouseover=false; return false; } };
task_system.js
var TaskSystem = function(canvas_){ this.canvas = canvas_; this.offsets = getElementPosition(canvas_); this.tasks = []; this.timerId=0; this.init = function(){ var tmp=this; if(this.canvas.addEventListener) { this.canvas.addEventListener('mousemove', function(e){tmp.produceTasks(e,tmp);}, false); } else if(this.canvas.attachEvent) { this.canvas.attachEvent('onmousemove',function(e){tmp.produceTasks(e,tmp);}); } } this.init(); } TaskSystem.prototype.clear = function(){ var ctx = this.canvas.getContext("2d"); ctx.clearRect(0, 0, parseInt(this.canvas.width), parseInt(this.canvas.height)); }; TaskSystem.prototype.addTask = function(task){ this.tasks.push(task); }; TaskSystem.prototype.showTasks = function(){ this.clear(); for (var i = 0; i < this.tasks.length; i ++){ this.tasks[i].show(); } }; TaskSystem.prototype.produceTasks = function(e,taskSystem){ var x = e.layerX-taskSystem.offsets['left']; var y = e.layerY-taskSystem.offsets['top']; var isFirstActor = true; for (var i = 0; i < taskSystem.tasks.length; i ++){ isFirstActor = isFirstActor && taskSystem.tasks[i].act(x,y,isFirstActor,taskSystem.tasks[i]); } }; TaskSystem.prototype.startTimer = function(interval){ var tmp=this; this.timerId = setInterval(function(){ tmp.showTasks();},interval); }; TaskSystem.prototype.clearTimer = function(interval){ clearInterval(this.timerId); }; function getElementPosition(element) { var offsetTrail = (typeof element == 'string') ? document.getElementById(element) : element; var offsetLeft = 0; var offsetTop = 0; while (offsetTrail) { offsetLeft += offsetTrail.offsetLeft; offsetTop += offsetTrail.offsetTop; offsetTrail = offsetTrail.offsetParent; } if (navigator.userAgent.indexOf('Mac') != -1 && typeof document.body.leftMargin != "undefined") { offsetLeft += document.body.leftMargin; offsetTop += document.body.topMargin; } return ({left: offsetLeft, top: offsetTop}); }
これ、予想はしてたけどunit testが役に立たないな…。
作りたいものは、例えばこれのようなもの。iCal拾ってきて動的に生成させたい。