lxyuma BLOG

開発関係のメモ

createjs,canvasでハマるところ2014

経緯

先日、初めてcreatejs使ったスマホ向けwebアプリ作ってリリースした。

まあ、予想通り、createjs、canvasにいろいろハマった。

はまったところは、gistにメモしておいたので、ここにも整理して乗っけておく。

なお、類似blog記事多数あり、俺もほとんど8割位それらの記事で助かりました。

ここで、参考にlink貼った記事書かれた方々に感謝します。

そして、次にcreatejs使う人のために、

既出の物、あまり他の記事に見ない物も、まとめて書いておきます。

参考までに。

概要

  • 以下の現象の原因と対応について書いていきます
    • タッチイベントがずれる
    • staging環境で画像click時にエラーに
    • retinacanvasがぼやける
    • (android)canvasが2つ出てきた
    • (android)でcanvasに1clickすると2clickした事になってる
    • (android)特定の条件で、eventに対して意図しないオブジェクトが反応してしまう
    • (android) 古い端末でcanvasが重すぎる
    • (android)一部の端末でcanvasではじめに描画した画像の残像が残って画面が崩れる
    • (iOS)iphone4をios7にした端末で、なぜか一部タッチできない

タッチイベントがずれる

  • 現象
    • タッチした時、実際のタッチした箇所と反応している箇所にズレがあった
  • 原因
    • 全体のzoomの割合に合わせてcanvasのzoomとscaleの調整が必要だった
    • よくスマホ向けに偽装userAgentのブラウザpluginとか入れてるとzoom入ってておかしくなる
    • ズレがあったら、まずは、zoomをチェックしよう
  • 対応
    • 全体にかかっているズーム率を取得。その後、canvasに対して以下スタイルをあてる
    • zoom: 1 / ズーム率
    • transform-origin: top left
    • transform: scale(ズーム率, ズーム率)
  • 参考

staging環境で画像click時にエラーに

  • 現象
    • localでは正常に動いたのに、stagingにあげた途端に、画面は描写されるが、タッチなど反応しない。
    • consoleのエラー「Unable to get image data from canvas because the canvas has been tainted by cross-origin data.」
  • 原因
    • canvasのcross domainにひっかかってた
  • 対応
    • mask用のclick領域を準備した
    • 具体的には、hitAreaにmask用のshapeを突っ込んだ
  • 参考

retinacanvasがぼやける

  • 現象
    • iphone5など、retinaな端末で見ると画像がぼやけて見える
  • 原因
    • 当然、canvasも実際のサイズの2倍しないといけない
  • 対応
    • devicePixcelRatioがあるものだけ、幅高さ2倍で、canvasを伸縮する
  • 参考
if (window.devicePixelRatio) {
    var height = canvas.getAttribute('height');
    var width = canvas.getAttribute('width');
    canvas.setAttribute('width', Math.round(width * window.devicePixelRatio));
    canvas.setAttribute('height', Math.round( height * window.devicePixelRatio));
    canvas.style.width = width+"px";
    canvas.style.height = height+"px";
    stage.scaleX = stage.scaleY = window.devicePixelRatio;
}

(android)canvasが2つ出てきた

  • 現象
    • canvasはHTML/DOM上1つしか存在しないが、ブラウザ表示では、その上に、架空のcanvas(表示内容は全く一緒)が出現
    • androidの少し古めの端末で出現(arrowsとか)
  • 原因
  • 対応
    • 親要素のoverflow(or overflow-x):hiddenをvisibleにして解決
    • 不都合あれば、DOMを調整しよう。

(android)でcanvasに1clickすると2clickした事になってる

  • 現象
    • createjsのtouch enableつけて、androidの一部の機種に悪影響
  • 原因
    • どうやら、タッチした時に、touchstartと、mousedownもfireしてるっぽい。
    • androidの一部端末に見られた。(galaxy系とか)
  • 対策
    • 初めにclick時に100ms以内か否かの判定つけたが、他に影響ありすぎた 参考:記事1
    • 結局、click時に毎回、touchstart以外をのぞく設定をした 参考:記事2
    • touchstart/touchend/touchmove全部この対応が必要

(android)特定の条件で、eventに対して意図しないオブジェクトが反応してしまう

  • 現象
    • あるobjをclickすると、そのobjのeventではなく、canvasの最も上のobjのeventをfireする
    • objに対してのあたり判定は成功していて、イベントバブリング、caputringフェーズで、元のobjを見つけられず、最後のobjがイベントの対象と勘違いして、そのobjをfireしてしまう
    • これも、一部のandroid端末だけで発生した。(端末は忘れたが)
  • 原因
    • 対象objの上に別のobjを重ねてtweenアニメしていたのが原因で、元の対象objまでevent callできなくなってる様子
    • 普通にcreatejsのバグっぽい
  • 対応
    • 今回の場合、たまたまanimeしてるobjはtouchする必要がなかったので、animeしてるobjにmouseEnabled = falseすると、解決

(android) 古い端末でcanvasが重すぎる

  • 現象
    • 古いandroidで重すぎて動かない。
    • 反応が遅すぎ
  • 原因
    • 指定のFPSについて来れてない
  • 対応
    • userAgentでandroidだけ分岐して、低めのFPS指定した(setFPS)
    • 参考値:android2,3,4.0まで FPS=5、android4.1,4.2をFPS=10、それ以外を20にした。全体挙動を見て、このあたりが妥当なんじゃないかなー。と。
    • ただ、こうすると、古い端末で自分でos upgradeしてると守りきれない
    • 最悪、アプリの中の設定で、低いFPSに切り替えられるようにしてもいいかもしれない(ゲームとかでこういうのありますよね)

(android)一部の端末でcanvasではじめに描画した画像の残像が残って画面が崩れる

  • 現象
    • androidの一部の端末で、画面の一部の描写がcanvasに残っていて消されなかった
    • 縞状の画面崩れや、画面の隅の1/8ほどの領域の崩れが起こった。
  • 原因
    • 描画についてこれていないっぽい
  • 対応
    • 1)問題端末の9割は、上述の通り、FPSを下げる(5らへん)と解決
    • 2)一部の端末(sony xperiaらへん)は、FPS下げるだけでは解決されず、FPSで自動でupdateのsyncかけていく直前に、手動で初めの一回だけstage.update()したら解決した
    • 3)一部の端末(sharp aquosらへん)は、それでもうまくいかず、調べていくと、android4.1/4.2で、clearRectが失敗してるらしい。4.1か4.2の時だけ、clearRect後に、visibilityをon/off切り替える感じにした。参考記事
// android4.1と4.2の時だけ、毎回のupdate()で、以下。
      this.canvas.style.visibility = 'hidden';
      this.canvas.offsetHeight;
      this.canvas.style.visibility = 'inherit';

(iOS)iphone4をios7にした端末で、なぜか一部タッチできない

結論

  • やっぱり、androidで苦労したなーという印象。

以上。