色々と思うところがあり、Canvasコンテンツ制作についての勉強を始めました。
とは言っても時間的なコストはなるべく抑えたいので、CanvasをFlashライクに扱えるらしいライブラリEaselJSを使うことにしました。また、環境面ではMicrosoft製JavaScriptコンパイル言語TypeScriptを導入しました。アロー関数式おいしいです。
作ってみたもの (古くないPCとブラウザ専用)
想像していたよりずっと動きが重い、というのが作ってみての率直な感想ですが、ただこれは自分が理解してないってだけで、もしかしたら同じ表現をするのでももっと早い書き方とかがあるのかも。
ずっと前に買ったFlash用の数学・物理学表現の本を引っ張り出してきてそれを参考にしながら作ってみましたが、やっぱり数値演算は難しいです…。とりあえずは継続することが大事なので、自分自身が楽しみながらやれるよう工夫しながら身に付けていき、今後の案件に備えようと思います。
※以下、デモのTypeScriptコード
PhysicalPoint.ts
/// <reference path="../lib/easeljs/easeljs.d.ts" /> class PhysicalPoint extends createjs.Point { private INTERVAL:number = 41; private AR:number = .95; public vx:number; public vy:number; public ax:number; public ay:number; public ts:number; public timerId:number; constructor( xx:number = 0, yy:number = 0 ) { super( xx, yy ); this.vx = 0; this.vy = 0; this.ax = 0; this.ay = 0; this.ts = new Date().getTime(); this.timerId = setInterval( ()=> { this.loop(); }, this.INTERVAL ); } private loop() { var now:number = new Date().getTime(); var t:number = (now - this.ts) / 1000; this.x += this.vx * t + 0.5 * this.ax * t * t; this.y += this.vy * t + 0.5 * this.ay * t * t; this.vx += this.ax * t; this.vy += this.ay * t; this.vx *= this.AR; this.vy *= this.AR; this.ax = 0; this.ay = 0; this.ts = now; } setSpeed( aax:number = 0, aay:number = 0 ) { this.ax += aax; this.ay += aay; } }
Dots.ts
/// <reference path="../lib/easeljs/easeljs.d.ts" /> /// <reference path="PhysicalPoint.ts" /> class Dots extends createjs.Shape { public stage:createjs.Stage; public canvas:HTMLCanvasElement; public xNum:number; public yNum:number; public interval:number; public pptAry:PhysicalPoint[]; public locAry:createjs.Point[]; public brightness:number; public timerId:number; constructor( xNum:number = 10, yNum:number = 10, interval:number = 10 ) { super(); this.xNum = xNum; this.yNum = yNum; this.interval = interval; this.pptAry = []; this.locAry = []; this.brightness = 0; this.timerId = 0; } private distance( pt1:createjs.Point, pt2:createjs.Point ):number { return Math.sqrt( Math.pow( pt2.x - pt1.x, 2 ) + Math.pow( pt2.y - pt1.y, 2 ) ); } start() { this.stage = this.getStage(); this.canvas = this.stage.canvas; var i:number = 0; var j:number = 0; for ( ; i < this.yNum; i++ ) { j = 0; for ( ; j < this.xNum; j++ ) { var xLoc:number = this.canvas.width / 2 - (this.xNum) * this.interval / 2 + j * this.interval; var yLoc:number = this.canvas.height / 2 - (this.yNum) * this.interval / 2 + i * this.interval; this.pptAry.push( new PhysicalPoint( xLoc, yLoc ) ); this.locAry.push( new createjs.Point( xLoc, yLoc ) ); } } } onTick() { var ppt:PhysicalPoint; var loc:createjs.Point; var maxDist:number = 50; var dist:number; var par:number; var mouseX = this.stage.mouseX; var mouseY = this.stage.mouseY; var g:createjs.Graphics = this.graphics; var i:number = 0; var len:number = this.pptAry.length; for ( ; i < len; i++ ) { ppt = this.pptAry[i]; loc = this.locAry[i]; ppt.setSpeed( (loc.x - ppt.x) * 10, (loc.y - ppt.y) * 10 ); dist = this.distance( new createjs.Point( mouseX, mouseY ), <createjs.Point> ppt ); if ( dist < maxDist ) { par = (maxDist - dist) / maxDist; ppt.setSpeed( (ppt.x - mouseX) * par * 50, (ppt.y - mouseY) * par * 50 ) } } g.clear(); for ( i = 0; i < len; i++ ) { ppt = this.pptAry[i]; loc = this.locAry[i]; g.moveTo( ppt.x, ppt.y ); g.beginFill( '#' + Math.floor( Math.random() * 0xFFFFFF ).toString( 16 ) ); g.drawRect( ppt.x, ppt.y, 1, 1 ); g.endFill(); } } }
Main.ts
/// <reference path="../lib/easeljs/easeljs.d.ts" /> /// <reference path="Dots.ts" /> class Main { private canvas; private stage:createjs.Stage; private dots:Dots; constructor() { this.canvas = document.getElementById( 'mycanvas' ); this.canvas.width = this.canvas.height = 500; this.stage = new createjs.Stage( this.canvas ); this.dots = new Dots( 20, 20 ); this.stage.addChild( this.dots ); this.dots.start(); createjs.Ticker.addListener( this.stage ); createjs.Ticker.setFPS( 24 ); } } window.addEventListener( 'load', ( e )=> { var main = new Main(); } );