Sebastian DeRossi氏がEaselJS 0.7.1を使って「Smooth Line」というサンプルコードを公開されました。マウスポインタの動きにしたがって、滑らかな曲線が描かれては消えていきます。この振る舞いを少し変えるとともに、これまでFumioNonaka.comやgihyo.jpの連載でご紹介した小技をコードに採入れてみました(サンプル001)。
サンプル001■EaselJS 0.7.1: Smooth LineSebastian DeRossi氏のコードは、GitHubに公開されています。このコードにもとづいて、前掲サンプル001ではドラッグの軌跡にしたがった滑らかな曲線を、つぎのような関数(drawCurve())で描きました。引数には描画するGraphicsオブジェクト(myGraphics)とともに、曲線の始点(oldPoint)と終点(newPoint)、およびコントロールポイント(controlPoint)の座標をPointオブジェクトで渡します。
function draw() {
var midPoint = new createjs.Point((lastPoint.x + currentPoint.x) / 2, (lastPoint.y + currentPoint.y) / 2);
drawCurve(myShape.graphics, lastMidPoint, midPoint, lastPoint);
}
function drawCurve(myGraphics, oldPoint, newPoint, controlPoint) {
myGraphics.beginStroke("black")
.setStrokeStyle(getLineThickness(oldPoint, newPoint), "round", "round")
.moveTo(oldPoint.x, oldPoint.y)
.quadraticCurveTo(controlPoint.x, controlPoint.y, newPoint.x, newPoint.y);
}
このお題はgihyo.jp連載「HTML5のCanvasでつくるダイナミックな表現―CreateJSを使う」第10回「ドラッグの軌跡を滑らかな曲線で描く」で扱いました。「2次ベジエ曲線で滑らかな軌跡を描く」の項で各座標の定め方が解説されています。連続した座標はすべてコントロールポイントにして、座標の中点をアンカーポイントとして結ぶのです(図001)。gihyo.jp連載第10回の解説には、jsdo.itのシミュレーションサンプルも掲げてあります。
図001■軌跡の座標に対する滑らかな曲線の描き方
このサンプルでは、予め決めた数までの多くのインスタンスに、つぎつぎと線を書き加えてステージに置きます。そして、古いオブジェクトから順に表示リストから除くことで、線の消えるアニメーションを表現しています。
このような場合、新たなインスタンスを毎回つくるより、すでにあるオブジェクトはそのまま使った方がお得です。そこで、前掲サンプル001は、gihyo.jp連載第14回「オブジェクトの使い回しとアニメーション素材の変更」にならって、「つくったオブジェクトを使い回す」ことにしました。使い回しの関数は、つぎのふたつです。
function getNewChild() {
var child;
if (children.length) {
child = children.pop();
child.graphics.clear();
} else {
child = new createjs.Shape();
}
return child;
}
function removeOldChild() {
var child = container.getChildAt(0);
container.removeChildAt(0);
children.push(child);
}
使い終えたオブジェクトは変数(children)の配列に入れます。オブジェクトを返す関数(getNewChild())は、配列にエレメントがないときだけ新たにつくります。オブジェクトがあれば、配列から取出して、描画を消したうえで返します。
一番古いオブジェクトを表示リストから除く関数(removeOldChild())は、その後配列エレメントに加えます。これで、つくられたインスタンスは消されることなく、使い回されます。
サンプル001の動きに、不具合といえるところはありません。ただ、曲線の描かれるアニメーションに滑らかさが少し足りないようです。とくに、線の太さが変わるとき、階段状に見えてしまうことがあります。
そこで、ふたつ手を加えました。まず、線の太さはイージングを加えながら変えます。
var currentLineThickness = 1;
function drawCurve(myGraphics, oldPoint, newPoint, controlPoint) {
getLineThickness(oldPoint, newPoint);
myGraphics.beginStroke("black")
// .setStrokeStyle(getLineThickness(oldPoint, newPoint), "round", "round")
.setStrokeStyle(currentLineThickness, "round", "round")
.moveTo(oldPoint.x, oldPoint.y)
.quadraticCurveTo(controlPoint.x, controlPoint.y, newPoint.x, newPoint.y);
}
function getLineThickness(oldPoint, newPoint) {
var lineThickness = distance / ratio;
currentLineThickness += (lineThickness - currentLineThickness) * 0.5;
// return lineThickness;
}
つぎに、Ticker.timingMode
プロパティに定数Ticker.RAF
を定めて、requestAnimationFrameのモードにしました。これで描画の効率が上がり、描替えの頻度も高まります。今回のサンプルでは、経過時間を計算に用いていないので、変更も楽です。
function initialize() {
createjs.Ticker.timingMode = createjs.Ticker.RAF;
createjs.Ticker.addEventListener("tick", draw);
}
これらふたつの調整を加えたのが、つぎのサンプル002です。
サンプル002■EaselJS 0.7.1: Smooth Line tuned