HTML5のCanvasでつくるダイナミックな表現―CreateJSを使う

第8回 ぼかしフィルタとアルファマスク

この記事を読むのに必要な時間:およそ 10 分

クリックした位置にアルファマスクを加える

もう一歩進めて,インタラクションを加えよう。円形のアルファマスクを,マウスクリックした位置に加える。つぎのコードのように,マスクを描く関数(wipe())Stage.stagemousedownイベントのリスナーに定める。リスナー関数は,Stage.mouseXStage.mouseYプロパティでクリックした座標を調べ,その座標が中心となるように円形のマスクを描く。

クリックするたびに,マスクには円形の塗りが加わる。すると,アルファマスクのキャッシュも描き直さなければならない。だが,新たなCanvasを増やすには及ばない。そういうときは,DisplayObject.updateCache()メソッドを呼び出すと,すでにあるCanvasの描画が改められる。

Canvasにキャッシュする関数(updateCache())は,第1引数のブール値でDisplayObject.updateCache()DisplayObject.cache()のどちらのメソッドを呼び出すのかを選べるようにした。したがって,始めは引数falseで新たなCanvasをつくり,その後はtrueにして描画を更新すればよい。

function draw(eventObject) {

  stage.addEventListener("stagemousedown", wipe);
  wipingShape = new createjs.Shape();

  // wipe();
  updateCacheImage(false);
}

function wipe(eventObject) {
  var mouseX = stage.mouseX;
  var mouseY = stage.mouseY;
  wipingShape.graphics
  .beginFill(createjs.Graphics.getRGB(0x0, 0.5))
  // .drawCircle(50, 50, radius);
  .drawCircle(mouseX, mouseY, radius);
  // updateCacheImage(false);
  updateCacheImage(true);
}

function updateCacheImage(update) {
  updateCache(update, wipingShape);
  var maskFilter = new createjs.AlphaMaskFilter(wipingShape.cacheCanvas);
  imageBitmap.filters = [maskFilter];
  updateCache(update, imageBitmap);
  stage.update();
}
function updateCache(update, instance) {
  if (update) {
    instance.updateCache();
  } else {
    instance.cache(0, 0, imageSize.x, imageSize.y);
  }
}

前述のコードで試してみると,クリックした座標と円形のマスクの中心がずれてしまう図6⁠。なぜなら,マウス座標はステージの基準点にもとづいて定められる。ところが,フィルタはインスタンスの中の座標で演算されるからだ。インスタンスをステージの真ん中に置くため,座標を動かした。その座標の差がマスクの位置をずらしてしまう。

図6 ステージの基準点とインスタンスの座標の差がマスクの位置をずらす

図6 ステージの基準点とインスタンスの座標の差がマスクの位置をずらす

そこで,インスタンスを描く関数(draw())の中で,真ん中に位置合わせした座標をPointオブジェクトにして変数(bitmapPoint)に納めた。そして,マスクを描く関数(wipe())は,円の中心座標をその分ずらす。新たに定めた関数(getMousePoint())は,インスタンスの基準点から見たマウスポインタの座標を返すようにした。

var bitmapPoint = new createjs.Point();

function draw(eventObject) {

  var nX = bitmapPoint.x = (canvasSize.x - imageWidth) / 2;
  var nY = bitmapPoint.y = (canvasSize.y - imageHeight) / 2;
  stage.addEventListener("stagemousedown", wipe);

}

function wipe(eventObject) {
  // var mouseX = stage.mouseX;
  // var mouseY = stage.mouseY;
  var mousePoint = getMousePoint();
  var mouseX = mousePoint.x;
  var mouseY = mousePoint.y;
  wipingShape.graphics
  .beginFill(createjs.Graphics.getRGB(0x0, 0.5))
  .drawCircle(mouseX, mouseY, radius);

}
function getMousePoint() {
  var mouseX = stage.mouseX - bitmapPoint.x;
  var mouseY = stage.mouseY - bitmapPoint.y;
  return new createjs.Point(mouseX, mouseY);
}

これで,クリックした座標を中心に円形のアルファマスクが加えられる図7⁠。script要素全体は,つぎのコード3のとおりだ。半透明の塗りを重ねると,アルファ値は高まる。それがわかりやすいように,塗りのアルファを少し下げた。また,ぼけたイメージのインスタンス(blurBitmap)も,アルファを下げている。そうすると,手前のインスタンス(imageBitmap)が濃くなるにつれ,アルファも高まって見えるからだ。

図7 クリックした座標を中心に円形のアルファマスクが重なる

図7 クリックした座標を中心に円形のアルファマスクが重なる

コード3 クリックした座標を中心に円形のアルファマスクを塗り重ねてインスタンスに加える

<script src="http://code.createjs.com/easeljs-0.6.1.min.js"></script>
<script src="http://code.createjs.com/preloadjs-0.3.1.min.js"></script>
<script src="easeljs/filters/AlphaMaskFilter.js"></script>
<script src="easeljs/filters/BoxBlurFilter.js"></script>
<script>
var stage;
var wipingShape;
var imageBitmap;
var blurBitmap;
var imageSize = new createjs.Point();
var radius = 40;
var bitmapPoint = new createjs.Point();
function initialize() {
  var canvasElement = document.getElementById("myCanvas");
  var canvasSize = new createjs.Point(canvasElement.width, canvasElement.height);
  stage = new createjs.Stage(canvasElement);
  var loader = new createjs.LoadQueue(false);
  loader.addEventListener("fileload", draw);
  loader.loadFile({
    src: "images/image.png", 
    data: canvasSize
    });
}
function draw(eventObject) {
  var image = eventObject.result;
  var canvasSize = eventObject.item.data;
  var imageWidth = imageSize.x = image.width;
  var imageHeight = imageSize.y = image.height;
  var nX = bitmapPoint.x = (canvasSize.x - imageWidth) / 2;
  var nY = bitmapPoint.y = (canvasSize.y - imageHeight) / 2;
  stage.addEventListener("stagemousedown", wipe);
  wipingShape = new createjs.Shape();
  blurBitmap = createBitmap(image, nX, nY);
  blurBitmap.filters = [new createjs.BoxBlurFilter(15, 15, 2)];
  blurBitmap.cache(0, 0, imageWidth, imageHeight);
  blurBitmap.alpha = 0.8;
  imageBitmap = createBitmap(image, nX, nY);
  updateCacheImage(false);
}
function createBitmap(image, nX, nY) {
  var myBitmap = new createjs.Bitmap(image);
  myBitmap.x = nX;
  myBitmap.y = nY;
  stage.addChild(myBitmap);
  return myBitmap;
}
function wipe(eventObject) {
  var mousePoint = getMousePoint();
  var mouseX = mousePoint.x;
  var mouseY = mousePoint.y;
  wipingShape.graphics
  .beginFill(createjs.Graphics.getRGB(0x0, 0.15))
  .drawCircle(mouseX, mouseY, radius);
  updateCacheImage(true);
}
function getMousePoint() {
  var mouseX = stage.mouseX - bitmapPoint.x;
  var mouseY = stage.mouseY - bitmapPoint.y;
  return new createjs.Point(mouseX, mouseY);
}
function updateCacheImage(update) {
  updateCache(update, wipingShape);
  var maskFilter = new createjs.AlphaMaskFilter(wipingShape.cacheCanvas);
  imageBitmap.filters = [maskFilter];
  updateCache(update, imageBitmap);
  stage.update();
}
function updateCache(update, instance) {
  if (update) {
    instance.updateCache();
  } else {
    instance.cache(0, 0, imageSize.x, imageSize.y);
  }
}
</script>

今回はここまでにしよう。コードはjsdo.itにも掲げた。次回は,お題と同じように,ドラッグでアルファマスクを描く。

著者プロフィール

野中文雄(のなかふみお)

ソフトウェアトレーナー,テクニカルライター,オーサリングエンジニア。上智大学法学部卒,慶応義塾大学大学院経営管理研究科修士課程修了(MBA)。独立系パソコン販売会社で,総務・人事,企画,外資系企業担当営業などに携わる。その後,マルチメディアコンテンツ制作会社に転職。ソフトウェアトレーニング,コンテンツ制作などの業務を担当する。2001年11月に独立。Web制作者に向けた情報発信プロジェクトF-siteにも参加する。株式会社ロクナナ取締役(非常勤)。

URLhttp://www.FumioNonaka.com/

著書