01 Graphicsクラスに新たに備わったコマンドオブジェクト
Graphicsクラスにコマンドオブジェクトをつくるクラスが新たに備わった。
01-01 EaselJSのGraphicsクラスとCanvasの描画の違い
EaselJSはCanvasに描画する。しかし、そのためのGraphicsクラスのメソッドは直感的に描けるよう設計されている。Canvasのメソッドを使った場合との違いを確かめておこう。線と塗りのついた円を描いてみる(図002)。
図001■Canvasに線と塗りのついた円を描く
Graphicsクラスのメソッドで円を描くのは、FlashやFireworksでツールやプロパティを使って操作するのは同じ手順になる。
Graphicsクラスのメソッドで円を描く手順
- Graphics.setStrokeStyle()
- Graphics.beginStroke()
- Graphics.beginFill()
- Graphics.drawCircle()
EaselJSのGraphicsクラスのメソッドで円を描くスクリプトは、以下にまとめたコード001のとおりだ。つぎに抜書きした円を描く関数(drawCircle())は。前述の手順どおりに処理している(第11〜14行目)。
- function drawCircle(_graphics, x, y, radius, fillColor) {
- _graphics.setStrokeStyle(1);
- _graphics.beginStroke("black");
- _graphics.beginFill(fillColor);
- _graphics.drawCircle(x, y, radius);
- }
|
コード001■Graphicsクラスのメソッドで円を描く
- var stage;
- function initialize(){
- var canvas = document.getElementById("myCanvas");
- var shape = new createjs.Shape();
- stage = new createjs.Stage(canvas);
- stage.addChild(shape);
- drawCircle(shape.graphics, canvas.width / 2, canvas.height / 2, 50, "cyan");
- stage.update();
- }
- function drawCircle(_graphics, x, y, radius, fillColor) {
- _graphics.setStrokeStyle(1);
- _graphics.beginStroke("black");
- _graphics.beginFill(fillColor);
- _graphics.drawCircle(x, y, radius);
- }
|
Canvasのメソッドでは、目に見えないパスでかたちをつくったうえで、そのパスにもとづいて塗りや線を描く(HTML5.JP「さまざまな図形を描く」参照)。ことさら複雑ではないものの、直感的な手順とはいえない(第7〜11行目)。
Canvasのメソッドで円を描く手順
- beginPath()
- fillStyle()
- arc()
- fill()
- stroke()
- function drawCircle(context, x, y, radius, fillColor) {
- context.beginPath();
- context.fillStyle = fillColor;
- context.arc(x, y, radius, 0, Math.PI*2, false);
- context.fill();
- context.stroke();
- }
|
コード002■Canvasのメソッドで円を描く
- function initialize(){
- var canvas = document.getElementById("myCanvas");
- var context2D = canvas.getContext("2d");
- drawCircle(context2D, canvas.width / 2, canvas.height / 2, 50, "cyan");
- }
- function drawCircle(context, x, y, radius, fillColor) {
- context.beginPath();
- context.fillStyle = fillColor;
- context.arc(x, y, radius, 0, Math.PI*2, false);
- context.fill();
- context.stroke();
- }
|
01-02 Graphicsクラスのコマンドオブジェクトを使う
GraphicsクラスからCanvasに与える指示が、Graphicsコマンドとしてクラスに定められた(図002)。これらの新たなGraphicsコマンドオブジェクトを用いて描画することもできる(「EaselJS 0.8.0: Graphicsクラス」参照)。Graphicsコマンドオブジェクトは、Graphics.append()メソッドでキューに加える。
図002■Graphicsクラスに備わったコマンドをつくるクラス
Graphicsコマンドを用いると、Canvasのメソッドに沿った手順で描画することになる(コード003)。
Graphicsコマンドで円を描く手順
- Graphics.beginCmd
- Graphics.Circle()
- Graphics.Fill()
- Graphics.Stroke()
コード003■Graphicsクラスのコマンドオブジェクトで円を描く
- function drawCircle(_graphics, x, y, radius, fillColor) {
- _graphics.append(createjs.Graphics.beginCmd);
- _graphics.append(new createjs.Graphics.Circle(x, y, radius));
- _graphics.append(new createjs.Graphics.Fill(fillColor));
- _graphics.append(new createjs.Graphics.Stroke("black"));
- }
|
Graphicsコマンドで行った描画は、コマンドのプロパティにより後から変えられる。たとえば、描いた円の半径と塗りは、それぞれGraphics.Circle.radiusとGraphics.Fill.styleプロパティで描き変えられる。
- var circle;
- var fill;
- function initialize(){
- shape.addEventListener("click", changeCircle);
- }
- function drawCircle(_graphics, x, y, radius, fillColor) {
- circle = new createjs.Graphics.Circle(x, y, radius);
- fill = new createjs.Graphics.Fill(fillColor)
- }
- function changeCircle(eventObject) {
- var radius = Math.random() * 50 + 20;
- var color = createjs.Graphics.getRGB(Math.floor(Math.random() * 0xFFFFFF));
- circle.radius = radius;
- fill.style = color;
- stage.update();
- }
|
つぎのサンプル001は、円をクリックすると半径と塗りがランダムに変わる。まとめたスクリプトは以下のコード004のとおりだ。
サンプル001■EaselJS 0.8.0: Using Graphics commands
コード004■インスタンスへのクリックでGraphicsコマンドの設定をランダムに変えて描き直す
- var stage;
- var circle;
- var fill;
- function initialize(){
- var canvas = document.getElementById("myCanvas");
- var shape = new createjs.Shape();
- stage = new createjs.Stage(canvas);
- stage.addChild(shape);
- drawCircle(shape.graphics, canvas.width / 2, canvas.height / 2, 50, "cyan");
- shape.addEventListener("click", changeCircle);
- stage.update();
- }
- function drawCircle(_graphics, x, y, radius, fillColor) {
- _graphics.append(createjs.Graphics.beginCmd);
- circle = new createjs.Graphics.Circle(x, y, radius);
- _graphics.append(circle);
- fill = new createjs.Graphics.Fill(fillColor)
- _graphics.append(fill);
- _graphics.append(new createjs.Graphics.Stroke("black"));
- }
- function changeCircle(eventObject) {
- var radius = Math.random() * 50 + 20;
- var color = createjs.Graphics.getRGB(Math.floor(Math.random() * 0xFFFFFF));
- circle.radius = radius;
- fill.style = color;
- stage.update();
- }
|
Graphicsコマンドのクラスを使わなくても、メソッドの呼出しによりつくられた直近のGraphicsコマンドオブジェクトはGraphics.commandプロパティで参照が得られる(「EaselJS 0.8.0: Graphics.commandプロパティ」参照)。すると、その参照したコマンドのプロパティが操作できるようになる(コード005)。前掲サンプル001を書替えたのが、以下のサンプル002だ。
コード005■Graphics.commandプロパティでコマンドオブジェクトを得る
- function drawCircle(_graphics, x, y, radius, fillColor) {
- _graphics.setStrokeStyle(1);
- _graphics.beginStroke("black");
- fill = _graphics.beginFill(fillColor).command;
// _graphics.beginFill(fillColor);
// fill = _graphics.command;
- circle = _graphics.drawCircle(x, y, radius).command;
- }
|
サンプル002■EaselJS 0.8.0: Using the Graphics.command property
02 CreateJSのクラスの新たな継承の仕方
「CreateJS 14/12/12: 新たな継承の仕組みを定めるextend()とpromote()メソッド」が備わり、CreateJSのクラスはすべてこの仕組みにしたがって書直された。
これまでのCreateJSのクラスは、Function.prototypeプロパティにスーパークラスのオブジェクトを与えて継承した。また、コンストラクタは、クラスのinitialize()メソッドを呼出すのが決まりだった。
function スーパークラス() {
this.initialize();
}
function サブクラス() {
// スーパークラスのinitialize()メソッドを呼ぶ
// インスタンスの初期化
}
サブクラス.prototype = new スーパークラス();
|
新たなCreateJSのクラスは、extend()メソッドでスーパークラスを継承する。また、promote()メソッドが、オーバーライドされたスーパークラスのメソッドをサブクラスに定め直す。呼出すメソッドは「スーパークラス_メソッド()」で参照され、コンストラクタは「スーパークラス_constructor()」として定められる。
function サブクラス() {
this.スーパークラス_constructor() // promote()で備わる
// インスタンスの初期化
}
createjs.extend(サブクラス, スーパークラス);
createjs.promote(サブクラス, "スーパークラス名");
|
03 PreloadJSの新しいローダーを使う
PreloadJSに新しくローダーのクラスが備わった。読込むコンテンツに応じて、用いるローダーが変わる。
03-01 LoadQueueクラスは引続き使える
これまでは、LoadQueueクラスを用いてさまざまなファイルが読込めた。たとえば、「ドラッグする軌跡でアルファマスクを描く」は、画像ファイルをロードしている(図003)。画像を読込む処理は、以下に抜書きしたとおりだ。読込むファイルのオブジェクト(file)にdataプロパティを与えると、AbstractLoader.fileloadイベントのリスナー(draw())に引数として渡されるイベントオブジェクト(eventObject)からitemプロパティをとおして参照できる。
図003■マウスポインタの軌跡が滑らかな曲線でアルファマスクに描かれる
function initialize() {
var canvasElement = document.getElementById("myCanvas");
var canvasSize = new createjs.Point(canvasElement.width, canvasElement.height);
var file = {
src: "images/image.png",
data: canvasSize
};
var loader = new createjs.LoadQueue(false);
loader.addEventListener("fileload", draw);
loader.loadFile(file);
}
function draw(eventObject) {
var canvasSize = eventObject.item.data;
}
|
03-02 イメージはImageLoaderクラスで読込むのがお得
LoadQueueクラスは、読込むデータを調べて、内部的に実際の仕事はローダーに振り分ける。その数多くのローダーのクラスが、直に使うこともできるように整えられた。そして、イメージは「PreloadJS 0.6.0: ImageLoaderクラス」が引受ける。
読込むのがイメージと決まっていれば、ImageLoaderクラスを使う方がデータを調べる手間が省ける。ImageLoaderクラスによりイメージを読込む手順は、LoadQueueクラスとは用いるメソッドや引数、イベントなどが少しずつ異なる。
ImageLoaderクラスでイメージを読込む手順
- ImageLoader()コンストラクタに読込むファイルを引数で渡す
- 読込みの終わりはAbstractLoader.completeイベントで捉える
- ファイルはImageLoader.load()メソッドで読込む
「PreloadJS 0.6.0: 古いコードのイメージ読込みをImageLoaderクラスで書直す」例では、まずはつぎのように置き替えてみる。
function initialize() {
// var loader = new createjs.LoadQueue(false);
var loader = new createjs.ImageLoader(file);
// loader.addEventListener("fileload", draw);
loader.addEventListener("complete", draw);
// loader.loadFile(file);
loader.load();
}
|
ここで考えなければならないのは、リスナー関数へのデータの渡し方だ。なぜなら、AbstractLoader.completeイベントで引数に渡されるイベントオブジェクトはitemプロパティをもたない。そこで、つぎのコード006では、ImageLoaderインスタンスにプロパティでデータを与え(第8行目)、イベントオブジェクトのEvent.targetプロパティからImageLoaderインスタンスとそこに定めたプロパティを得ている(第13行目)。前掲の例は、つぎのサンプル003のように手直しした。
コード006■ImageLoaderクラスでイメージを読込む
- function initialize() {
- var canvasElement = document.getElementById("myCanvas");
- var canvasSize = new createjs.Point(canvasElement.width, canvasElement.height);
- var file = "images/image.png";
- stage = new createjs.Stage(canvasElement);
- var loader = new createjs.ImageLoader(file);
- loader.addEventListener("complete", draw);
// ImageLoaderインスタンスにプロパティを定める
- loader.canvasSize = canvasSize;
- loader.load();
- }
- function draw(eventObject) {
- var image = eventObject.result;
// ImageLoaderインスタンスからプロパティを取出す
- var canvasSize = eventObject.target.canvasSize;
// イメージの処理
- }
|
サンプル003■EaselJS 0.8.0 & PreloadJS 0.6.0: Wiping out blur from a image with AlphaMaskFilter
04 古いコードを新たに書替えてみる
CreateJSの古いバージョンで書いたコードを新たなバージョンで動くように書替えてみよう。まず、サブクラスの継承を、新たなextend()およびpromote()メソッドに改めたのがつぎのサンプル004だ。なお、「EaselJS 0.8.0: extend()メソッドを使った継承に書替えるときに注意すること」も参照してほしい。
サンプル004■EaselJS 0.8.0: Particles
function Particle(radius, color, landscape) {
// this.initialize();
this.Shape_constructor();
}
// Particle.prototype = new createjs.Shape();
createjs.extend(Particle, createjs.Shape);
createjs.promote(Particle, "Shape");
|
つぎに、Matrix2D.rotate()メソッドの引数に渡す角度は、ラジアンから度数に変わった。つぎのサンプル005は角度の単位を改めている。なお、Matrix2Dクラスのメソッドにおける行列の乗算の順序も変わったので、詳しくは「EaselJS 0.8.0: Matrix2Dクラスの基本的なメソッドと行列演算」をお読みいただきたい。
サンプル005■EaselJS 0.8.0: Rotating a Cube around the X and Y axes
var matrixX = new createjs.Matrix2D();
var matrixY = new createjs.Matrix2D();
function rotate(eventObject) {
var RAD_TO_DEG = 1 / createjs.Matrix2D.DEG_TO_RAD;
// matrixY.identity().rotate(angle.y);
matrixY.identity().rotate(angle.y * RAD_TO_DEG);
// matrixX.identity().rotate(angle.x);
matrixX.identity().rotate(angle.x * RAD_TO_DEG);
}
|
そして、前述02「CreateJSのクラスの新たな継承の仕方」に変わったことにともなって、initialize()メソッドが除かれてしまった。つぎのサンプル006は、このメソッドをPointオブジェクトの初期化に用いていた場合だ。geomパッケージのクラス(PointとRectangleおよびMatrix2Dなど)には、コンストラクタと同じ引数でオブジェクトを定め直せるメソッドsetValues()が新たに備わったので差替えた(「EaselJS 0.8.0: 使い回すオブジェクトにプロパティを定める」参照)。
サンプル006■EaselJS 0.8.0: Smooth Line tuned
var lastMidPoint = new createjs.Point();
var currentPoint = new createjs.Point();
var lastPoint = new createjs.Point();
function draw() {
currentPoint.x += velocityX;
currentPoint.y += velocityY;
var midPoint = new createjs.Point((lastPoint.x + currentPoint.x) / 2, (lastPoint.y + currentPoint.y) / 2);
// lastPoint.initialize(currentPoint.x, currentPoint.y);
lastPoint.setValues(currentPoint.x, currentPoint.y);
// lastMidPoint.initialize(midPoint.x, midPoint.y);
lastMidPoint.setValues(midPoint.x, midPoint.y);
}
|
作成者: 野中文雄
作成日: 2015年2月11日