LoginSignup
4
4

More than 5 years have passed since last update.

CreateJS: iOS7 on iPhone4 で hitArea を設定したシンボルへのイベントが走らなくなる件の応急処置

Last updated at Posted at 2014-04-17

主に FlashCC からはき出した CreateJS ファイルの話です。生 CreateJS で適用する方法は下にメモってあります。

タイトルの通り、 iOS7 かつ iPhone4 という組み合わせのみ、hitArea を設定したシンボルへのイベントが走らなくなる。

createjs.Container.prototype._getObjectsUnderPoint というメソッド内の処理では、引数で受け取った x, y とステージ上の各シンボルとで hitTest を行っているのだが、その方法として 1 x 1ピクセルの canvas にそれらのシンボルを転写して、何らかの描画がされてるかどうか で判断している。

iOS7 かつ iPhone4 という組み合わせだと、この転写がうまくいっておらず何も描画されていない状態と判定されてしまい hitTest が false になる。その辺りはまだ深掘りしてない。

そもそもはブラウザ側のバグだが、どうにか逃げないといけないので、取り急ぎ下記のように逃げた。

var Container = cjs.Container;

// 元のコードをコピペしてきて、一部を書き換えてる
Container.prototype._getObjectsUnderPoint = function(x, y, arr, mouse, activeListener) {
    var ctx = createjs.DisplayObject._hitTestContext;
    var mtx = this._matrix;
    var children = this.children;
    var l = children.length;

    activeListener = activeListener || (mouse&&this._hasMouseEventListener());

    for (var i=l-1; i>=0; i--) {
        var child = children[i];
        var hitArea = child.hitArea;

        if (!child.visible || (!hitArea && !child.isVisible()) || (mouse && !child.mouseEnabled)) { continue; }

        // if a child container has a hitArea then we only need to check its hitArea, so we can treat it as a normal DO: > だそうです
        if (!hitArea && child instanceof Container) {
            var result = child._getObjectsUnderPoint(x, y, arr, mouse, activeListener);
            if (!arr && result) { return (mouse && !this.mouseChildren) ? this : result; }
        } else {
            if (mouse && !activeListener && !child._hasMouseEventListener()) { continue; }

            // ## ここから
            // 対象のシンボルが visible: true、かつ alpha > 0( = オブジェクトが見えている状態で)、かつそのシンボルに hitArea が設定されていた場合 hitArea の nominalBounds の情報を元に hitTest を行う
            // nominalBounds は FlashCC が CreateJS ファイルをはき出す際に付加している Rectangle オブジェクト。座標と大きさが入ってる。
            if (child.visible && child.alpha > 0 && hitArea && hitArea.nominalBounds) {
                // イベントの座標を hitArea のローカル座標に直して、x, y の四辺の座標と比較する
                var localRect = hitArea.globalToLocal(x, y);
                var nominalBounds = hitArea.nominalBounds;

                if ((nominalBounds.x <= localRect.x && localRect.x <= (nominalBounds.x + nominalBounds.width)) &&
                    (nominalBounds.y <= localRect.y && localRect.y <= (nominalBounds.y + nominalBounds.height))) {
                        // 配列タイプだったらここで push して返る
                        if (arr) {
                            arr.push(child);
                            continue;
                        }
                        // 直接シンボルを返す
                        else {
                            return (mouse && !this.mouseChildren) ? this : child;
                        }
                }
                // 範囲内に存在しなかったことは確認できてるので、ここで返る
                continue;
            }
            // ## ここまで

            child.getConcatenatedMatrix(mtx);

            if (hitArea) {
                mtx.appendTransform(hitArea.x, hitArea.y, hitArea.scaleX, hitArea.scaleY, hitArea.rotation, hitArea.skewX, hitArea.skewY, hitArea.regX, hitArea.regY);
                mtx.alpha = hitArea.alpha;
            }
            ctx.globalAlpha = mtx.alpha;
            ctx.setTransform(mtx.a,  mtx.b, mtx.c, mtx.d, mtx.tx-x, mtx.ty-y);
            (hitArea||child).draw(ctx);
            if (!this._testHit(ctx)) {
                continue;
            }
            ctx.setTransform(1, 0, 0, 1, 0, 0);
            ctx.clearRect(0, 0, 2, 2);
            if (arr) {
                arr.push(child);
            } else {
                return (mouse && !this.mouseChildren) ? this : child;
            }
        }
    }
    return null;
};
  • canvas に転写する手間が省けてるので、処理が軽くなってるとは思われる
  • hitArea が何らかの方法で変形されてる(scale がかかってる)とうまくいかないかもしれない
  • 矩形の範囲しか指定できない = hitTest が全部矩形で判断されてしまう
  • globalToLocal してるので、動いてるオブジェクトに対しても問題なく走る(と思う)

オマケ

上のコードは FlashCC で書きだした前提なので、そのまま生の CreateJS で動いているところには適用できないが

座標値を渡して nominalBounds というプロパティで Rectangle をシンボルに付加すれば動く。

target_symbol.nominalBounds = new createjs.Rectangle(0, 0, 100, 100);
4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4