Fly higher! Sky is the limit!

webの現場で働く人のブログ

【GA計測にも使える!】押された要素が何番目なのかを調べる方法。

押された要素が何番目か調べる方法は、いくつかありますが個人的によく使うものをご紹介します。
jQueryを使用しています。

パターン1:リストで何番目を押されたかを調べる。

HTML

<ul id="list">
<li>ああああああああ</li>
<li>いいいいいいいい</li>
<li>うううううううう</li>
<li>ええええええええ</li>
<li>おおおおおおおお</li>
</ul>

Javascript

$("#list li").on('click',function(){
  var index = $("li").index(this);
});

純粋にli要素を押したものをindex(this)で返せば良いです。

パターン2:子要素(a)を押して、親要素(li)が何番目かを調べる。

HTML

<ul id="list2">
<li><span><a href="#">ああああああああ</a></span></li>
<li><span><a href="#">いいいいいいいい</a></span></li>
<li><span><a href="#">うううううううう</a></span></li>
<li><span><a href="#">ええええええええ</a></span></li>
<li><span><a href="#">おおおおおおおお</a></span></li>
</ul>

Javascript

$("#list2 a").on('click',function(){
  var index = $(this).parents("li").prevAll().length;
  return false;
});

押した要素の親要素を取得し、prevAll()を使いその要素の前以前にある兄弟要素の数を数えることで何番目かを判定します。
例)3番目のリンクを押した場合、3番目の要素より前にある兄弟要素は1番目と2番目の要素になるので返り値は“2”になる。

あまりよくない例。

var num = $(this).parent().parent().prevAll().length;

a要素のお父さんは、spanお父さんでそのお父さんは、liお父さんで..みたいなノリのやつですね。
ソースを見返した際に分かりずらいし、目的の要素を探すのに無駄な処理だと思います。
一歩ミスったら取得できないですし...危険ッ。

ってことで、parents(elem)で探した方が断然わかりやすいのでオススメです。
ちなみに、parents(elem)の場合 class名やID名も指定できるのでかなり便利。

パターン3:子要素(a)を押して、親要素(.test)が何番目かを調べる。

HTML

<ul id="list3">
<li class="test"><div><span><a href="#">ああああああああ</a></span></div></li>
<li class="test"><div><span><a href="#">いいいいいいいい</a></span></div></li>
<li class="test"><div><span><a href="#">うううううううう</a></span></div></li>
<li class="test"><div><span><a href="#">ええええええええ</a></span></div></li>
<li class="test"><div><span><a href="#">おおおおおおおお</a></span></div></li>
</ul>

Javascript

$("#list3 a").on('click',function(){
  var index = $(this).parents(".test").prevAll().length;
  return false;
});

子要素(a)の親要素(.test)を取得し何番目かを返すやり方です。

DEMO

パターン1からパターン3までのDEMOになります。

See the Pen LRKrWo by paradox_tm (@takumaro-web) on CodePen.

いかがだったでしょうか。
特にparents()は使い方によっては、押した要素の親のclass名を取得したり、ID名を取得したり色々便利ですね。
そのclass名やID名をlabelにしてdatalayerでもってpushすることもできたり、label名の指定に取得した番号と文字列を合わせてpushすることもできそうですね!
ソースのダイエットにも繋がります。

それでは、また。

[GA][Googleアナリティクス]iPhone7(iOS 10)safariで クリックイベント計測がうまくいかない時の対処方法。

2016年9月13日にiOS 10が配信されました。
さっそくアップデートしましたが今までの仕様に慣れていたので起動時や目覚ましタイマーを止める際に、一度ホームボタンを押さないといけない新しい仕様が若干煩わしいです。
※ ちなみに自分のiPhoneiPhone 6です。

前置きはさておき本題です。
iOS 10にしてから普段通りクリックイベントの計測をしていたところ...
「あれ!?クリックイベントが正しく計測されてない」という事に気づきました。

前に書いた記事iPhoneなんて怖くない!と思っていたのですが再び、調査しなきゃいけないのかと少し青ざめました、、、がなんとか計測できるようになったので覚書きです。

iOS 10からclickの処理の仕様が変わった?

詳しくはわからないですが前に書いた記事の中でクリックイベント計測がうまく取れない理由として“リンク先に飛ぶ処理の方が埋め込んだイベント計測の発火よりも速く処理されてしまうのが原因”ということを述べました。
そこでeventCallback関数を使用してリンクに飛ぶ前に計測用の処理を入れてしまおう!というのが前回のお話でした。

しかし...

明らかにiOS 9以下で計測できていたものが計測できなくなっているんです。

憶測ですがiOS 10のsafariからviewportのプロパティuser-scalable=noを指定しても画面を拡大できるようになったり独自の仕様を積んでいるのでこのリンクを押してからリンク先へ飛ぶ処理についても若干変更されたのかと思います。(多分)

clickがダメならtouchで計測する。

もうこれしかないかなと思いつつ実装してみたところ無事に計測できるようになったので記しておきます。

実装の流れ

iPhoneiOS)をユーザーエージェントで判定
iPhoneiOS)と他の端末との計測方法を変える
iPhoneiOS)のみ、touchイベントを使い計測する
④他の端末は従来通りの計測方法で計測する

ソース

※ 今回もjQueryを使用しております。

/*①iPhoneiOS系)をユーザーエージェントで判定*/
var appleKit = false;
if(navigator.userAgent.indexOf('iPad') > 0 || navigator.userAgent.indexOf('iPhone') > 0 || navigator.userAgent.indexOf('iPod') > 0){
  appleKit = true;
}

//クリックイベント計測用
var eventGA = function(event,category,action,label,link,target){
  dataLayer.push({
    'event': event,
    'category':category,
    'action': action,
    'label': label,
    'eventCallback' : function(){
      /*別窓指定じゃない時だけ実行*/
      if(!target){
        document.location = link;
        return false;
      }
    }
  });
};

/*②iPhoneiOS)と他の端末との計測方法を変える*/
if(appleKit){
/*③iPhoneiOS)のみ、touchイベントを使い計測する*/

  $(".element").on("touchstart touchmove touchend",function(){
    /* touchstartの座標とtouchendの座標が同じ時 = 疑似的なclick */
    if ('touchstart' == event.type){
      $(this).attr('data-touchstarted', '');
      return;
    }
    /*指を動かしたときは判定しない*/
    if ('touchmove' == event.type){
      $(this).removeAttr('data-touchstarted');
      return;
    }
    /*指をつけたところと指を離したところが同じ場合に処理*/
    if ('undefined' != typeof $(this).attr('data-touchstarted')){
      var link = $(this).attr("href");
      var target = ($(this).attr("target")) ? true : false;
      /*イベント送信!*/
      eventGA("event","category","action","label",link,target);
      
      /*フラグ削除*/
      $(this).removeAttr('data-touchstarted');
    }
  });

}else{
/*④他の端末は本来と同じように計測する*/
  $(".element").on("click" , function(){
    var link = $(this).attr("href");
    var target = ($(this).attr("target")) ? true : false;
    /*イベント送信!*/
    eventGA("event","category","action","label",link,target);
  });
}

説明はソース上にコメントアウトしておきましたが補足です。

  • touchstartのみだとリンクに触れた瞬間に計測が始まってしまうので、touchstart = touchendのときに計測するようにする。
  • eventCallbackは、別窓でない時のみに使用する。(別窓リンクの場合は計測できるので)

「たった1つの要素を計測するのにこれだけ記述するのは、ちょっと...」って気がしますが本気で計測したい場合に使うと良いかもしれません。
暫定対応ではありますが、このやり方で計測していきたいと思います。

余談 Firefox クリックイベント計測ができない場合...?

たまにあるんですけど、Googleアナリティクスの管理画面を見ながら計測のテストをしているとFirefoxだけ計測がいきなり取れなくなることが...(僕だけでしょうか...)
その場合の自分の対処方法なんですが【新規ウィンドウを立ち上げる】と計測できるようになったりします。
※ 別タブやリロードではダメ

2016/11/2 追記

Firefoxやっぱりおかしいなーということでいろいろ試したのですが...

clickだと取れたり取れなかったり別窓ページ遷移の場合や同ページ内のクリックイベント計測であれば問題ないのですが、 同窓ページ遷移の場合にうまくいかない事が多いですね。

そこで、clickからmousedownに変えたところ計測できるようになりましたが...
そうなると今度はキーボードからのクリックイベント計測はできなくなります。
キーボードもすべて網羅するのであれば、また別の実装方法を考えなくてはいけません。

あくまで“マウスを使ってクリックイベントを計測する”ということであれば、mousedownで計測すればよいかもしれませんが、、、要件定義次第ですね。

もし同じ事象でお困りの方は試してみてください。

それでは、また。

[JavaScript]日本語を数値に変換 / 日本語を数値に変換

クイズの回答との照合やパスワードのチェックなどに使えるメソッド。

charCodeAt() メソッド

与えられたインデックスに位置する文字の Unicode コードポイントを10進数値で返す。
(例)"あいうえお"という文字列の場合、"あ" が charCodeAt(0)にあたる。
⇒ 指定されない場合は、デフォルトでcharCodeAt(0)が返ってくる。

String.fromCharCode() メソッド

Unicode の値の指定のシーケンスを使用することによって生成された文字列を返す。
このメソッドは String オブジェクトではなく文字列を返すので、JavaScript内で数値(文字)を指定しなければならない。
(例)String.fromCharCode(12354,12356,12358,12360,12362) ⇒ "あいうえお"

DEMO

See the Pen charCodeAt / String.fromCharCode by @paradox_tm (@takumaro-web) on CodePen.

jQueryを使用してます。

[JQuery]たった9行でInstagram(インスタグラム)の写真一覧をWebサイトに表示する。

準備するもの

参考サイト

InstagramのAPIを使用して自分の投稿した写真をWEBサイトに出力する

instagram api 事始め access_tokenを取得する - Qiita

Instagram APIを取得してWebサイトと連携し、投稿写真を自動に掲載する方法 | 株式会社LIG

この辺の記事を参考にするとよい。

アクセストークンについて

もし「アプリの登録はできたけど、Instagramのアクセストークンが取得できない!」という場合、以下のページにアクセスし「Generate Access Token」をクリックすると良いかもしれないです。

instagram.pixelunion.net

※ ちなみに私はこちらのサイトを利用しました。

準備ができたところで、本題。

HTML

<ul id="js-instalib"></ul>

JavaScript

$(function(){
  var accessToken = 'xxxxxxxx.xxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; //取得したアクセストークンを貼り付ける
  $.getJSON('https://api.instagram.com/v1/users/self/media/recent/?access_token='+accessToken+'&callback=?',function (insta) {
    $.each(insta.data,function (photos,src) {
      if ( photos === 10 ) { return false; } //上限設定
      $('<li><img src="'+src.images.standard_resolution.url+'"></li>').appendTo('#js-instalib');
    });
  });
});

css

お好みで調整

DEMO

See the Pen insta lib by @paradox_tm (@takumaro-web) on CodePen.

編集後記

//api.instagram.com/v1/users/self/media/recent/?access_token=[アクセストークン]にアクセスすると いいね数やコメント、時間、リンク先など様々な情報が載っているので必要に応じてカスタマイズするのもありですね。

参考オプション

//インスタグラム詳細URL
src.link
//いいね数
src.likes.count
//コメント数
src.comments.count
//自分のコメント
src.caption.text

TweenMaxを使ってオープニングアニメーションをつくる。

TweenMaxを使ってオープニングアニメーションをつくる。

日本でもTweenMax(トゥイーンライブラリ)を使用しているリッチサイトが大分増えてきた気がますねー。 大体、動きがかっくいいサイトのソースを覗くと「TweenMax」の文字が見受けられます!

本記事は、TimelineMaxの基本的なアニメーション操作と記述方法のメモ書き。

オープニングアニメーションっぽい適当なDEMO| TimelineMax

See the Pen TweenMax sample by @paradox_tm (@takumaro-web) on CodePen.

以下、ソース抜粋

//TweenMaxを使用するための宣言
var timeLine = new TimelineMax();

//セレクターを指定
var elm1 =  document.getElementById("js-anim-01");
var elm2 =  document.getElementById("js-anim-02");
var elm3 =  document.getElementById("js-anim-03");
var elm4 =  document.getElementById("js-anim-04");
var elm5 =  document.getElementById("js-anim-05");
var elm6 =  document.getElementById("js-anim-06");

//第1引数:セレクター指定.
//第2引数:秒数指定(1000msではなく1秒単位).
//第3引数:アニメーション指定.
//第4引数:オプション指定.

//.toでタイムラインをつくっていく。
//コールバックは、onComplete: function(){}を指定.

//詳しくは以下を参照
//https://greensock.com/get-started-js
//https://ihatetomatoes.net/wp-content/uploads/2016/07/GreenSock-Cheatsheet-4.pdf

timeLine.to(elm1, 1, {opacity: '1', x:0, rotation:360}, "blueGreenSpin")
        .to(elm1, 1, {opacity: '0'})
        .to(elm2, 1, {top: '50%',opacity: '1'})
        .to(elm2, 1, {opacity: '0'})
        .to(elm3, 1, {right: '40%',opacity: '1'})
        .to(elm3, 1, {opacity: '0'})
        .to(elm4, 1, {opacity: '1', width:"50%", top:"100px", ease:Power2.easeInOut})
        .to(elm4, 1, {opacity: '0'})
        .to(elm5, 1, {opacity: '1', x:0, y:0, rotation:1440})
        .to(elm5, 2, {opacity: '0',top:'60%', ease:Power2.easeOut, onComplete:
                      function(){
                        //アニメーションが終わった後の処理
                     }})
        .to(elm6, 1, {opacity: '1',scale:"2"});

CDNの利用

2016年7月16日に最新版の1.19.0をリリースされた模様。 greensock.com

Cheat Sheet

https://ihatetomatoes.net/wp-content/uploads/2016/07/GreenSock-Cheatsheet-4.pdf

触ってみての感想

直感的でわかりやすい!!
他にも色々なオプションがたくさんある!!
Canvas/WebGLなどの制御も可能!!
jQueryも使える!!

胸がワキワキしちゃいますね!

facebookのOGPキャッシュをボタン1つで消せるBookmarkletを作製しました。

ページ公開直後のコンテンツに対してシェアボタンを押してもOGP情報をうまく取得できずシェアされない場合がありますよねー。 これは公開前のURLにfacebookのクローラがアクセスしてしまうことによって、facebook側にキャッシュが残ってしまいそちらを参照してしまうのが原因だそう。 (つまり、空ページをfacebook側がキャッシュしてしまっている。)

今まではページが公開されるとfacebook側が提供しているデバッグページにてキャッシュをクリアしていたけど少し煩わしさを感じていた。 いちいちfacebookにログインしなきゃいけないし、対象のURLをコピーして貼り付けなきゃだし、ボタンを押さなきゃいけないわけで...

『なんとかこの作業について簡略化・自動化できないか』と調べたところAPIの「https://graph.facebook.com/?scrape=true&id=URL」にPOSTメソッドでアクセスすると、再クロールしてくれるという記事を発見!

公開ページそのものにこのスクリプトないしプログラムを組み込めば、完全に自動化できるけど閲覧する度にPOSTするのもパフォーマンス的にいかがなものか? と思いBookmarkletでポチッとボタンを押すだけでキャッシュを消すことができるものを作製することにした。

自分は普段使いのブラウザがChromeなのでこちらのBookmarkletで問題ないのだが、現場から「Firefoxで動かねぇーよ!」という声が上がってきた。実際に確認してみるとなぜか、FirefoxだとBookmarklet内でAjaxを使ってPOSTできない..(誰かエロい人教えてください。)

2016/9/8修正
実は圧縮でミスってることがわかりました。
YUI Compressorを使用していたのですが、圧縮に問題が...
他の圧縮ツールを使用したところ、問題なくできたのでこちらを使用ください。
こちらは、Firefox/Chromeでも使用できます。

Bookmarkletソース(Firefox/Chrome用)

javascript:(function(){!function(c,b,a){a=c.createElement("script");a.src="//j.mp/1bPoAXq";a.onload=function(){b(jQuery.noConflict(1))};c.body.appendChild(a)}(document,function(a){a.ajax({url:"https://graph.facebook.com/?scrape=true&id="+location.href,method:"post"}).done(function(){alert("OGPキャッシュを消しましたー。")})})})();

これで、facebook側が提供しているデバッグページを使わずに済むので煩わしさが無くなりそう。

ちなみにIEsafariでは試してないです。

参考

web-tan.forum.impressrd.jp

developers.facebook.com

superuser.com

【canvas】画像を回転させながら落とす

最近、インタラクティブな実装に興味を持ち始めました。
覚え書きとして、canvasで画像を用いて回転させながら落ちるアニメーションの実装方法を記しておきます。

DEMO

補足
- 画像を複数個使用することを想定して、配列を用いています。

JavaScriptコード

$(function(){
var canvas = document.getElementById ('canvas');
var ctx = canvas.getContext ('2d');

function canvasbg(pageY,pageX,flag){
  var counter1 = 0;
  var counter2 = 0;
  var TO_RADIANS = Math.PI/180;
  var SPEED = 5;
  var X = pageX;
  var Y = pageY;

  function start() {

    x = [];
    y = [];

    /*初期座標*/
    x[0] = X / 2;
    y[0] = 0;
    
    x[1] = 150;
    y[1] = 0;

    img = [];
    img[0] = new Image ();
    img[0].src = "data:image/png;base64,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";
    
     img[1] = new Image ();
     img[1].src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAxCAMAAACvdQotAAAABGdBTUEAALGPC/xhBQAAAwBQTFRFTS8SjHlse1Q4iXRisKCUtJmBlHVdkH5qmoVwqJF5iGNHZ0UpZ0csXC8SUSYTg2pUXjwgbU41g2xQYEAkVDYa1cKxdFRBl3Vbk3dkYz8giGpXZUYwj3ZippWDzbina00zsZ2Jbkouup6KdVc9a084n4h4nIdxgmpVmHxpf2JPhGdPeVpBwqmWeVlF1L+wqpeGvKubw7GhY0QpXzwkVjMWdVQ85dDB59jJUzMXrpiG49C/vKOQ4NDC2se13Mi1u6mYAAAAjmxYjmpIo56dsbe3k2BEl31uqI5ywMHCxK+QsZR7n5CD9/DeqWhKCg0RWllZaWVkNDMysKmlYmBhi4ySJyUk7dvGU1JUjWE9gVQucEkrilgtekkkfUwWnmREUCQLm2A0dEkSy7qpVRwC5uryx7qyHRwZbG1rd3d33+Xlg1lBhm5XimREyLOd5e3v6ufk08a8XSgNrJF2nGY8iE0mnGI3fkUjYjkRej8S4+LhAQABERAOCgoKfFk8FBQTgmFDyM3QLCwt5NbLbUQjooJtjWpNhWtP1sS3Z0ccfU0n+ff31c3MkVclWC0Kg0khbj0LlVw2lVowf0UTajYJnnle7N/T7+7t+Pv9r5iL2tjZjnBc/fjypYl0rpWCdEkft5+Kd1AylGAv+PXujVs4bEAU9Pb4SCQFZzQNZC0CcjwUdDgKFxga8efg397eaT8dkndfwKmUlm5RkVw0hFg2cUEahEwbTR8EdUgYlF84gUYZdUEUhVAkHh8e/P7/lWc9//73XSkBhVQui1EkWy4K1czG1dHRi1kxeEYTnGxGnGhBomhAeUQbYjMNdT4MbjwXVCQAgEITbjcNViwGc0ASbTsSkl4yazoOcT0PlmI2VCYIZTAITikLdD4TVigCTyQBi1cpeEIUe0YcfUgfbz4UeEQZfEIUfUgYe0kbXCwGe0UWmGM9aDoR6OrshlQnjlgsfUcbekgeekgWgk4hgEwffkociFMneUQYfkYYeEIXj1ovc0AWdkIaekUY////fEcbe0YaIEcY1AAAAEF0Uk5T+2Pd3mOanHZbgsa9xfr+wOzctefsL8OVPsWo3IF2PNVvundQ0G+IlJGlS8dgtA9CRErk6vnKBxPzVBsrBSYDVABZxbcMAAAFzUlEQVRIx5XWZVRbSRgGYNa1W3dvoVDcXXrOulW3Lrs16lRpCwVKBS1a3F2KuwSXBkkgFAghQiAhQILEPbnJToDdhW0p8J7kx3czz8y5mbnfuUp7Fh2lt65Y6mjqaC+OfPzN7SVGKtqLIZtL7vkh8Rs/t144MVke5ENnp2G1Vi+Y7FnRyfYrLh46v0pzoWS1KUZAJjO4snTi5oUR4zXY4WEmSS6TM9JSty2IaJZIpghDzsDhbRZC1uA4wyz5VARUffP5ifHKnlIWiyadzFn5ebUFrKIfVNo0IJTK5VKpvLT8jYHJfER7myGOy+WwKzgMqZTEFAzgdechZhuxZDRa1M/jyPhyOYkk4OPN3k8249vt7UV0HhvcugyEzBASPzF/H9FMPWUfqAD8SQAIhYDEL/vUYk5iYpATQJ/gcKWUaSETkwuSCotQq3TnIirYunt+JJrg/n3yyAhzhEwReyUlwSu4gtplVnOQDbVsEoIkl4I1RpgkipgykSDq57CaaOVEtTmIVjqNWZTz7FnyWRYDIaGwCxJ82LGxnsn8YtxWy7lWYeY8jg6PcfcsEiIm0L0iuBcowyOfUd7oG7+baKJyIi++zo5o/PVEf28v2J1Tk+WL8BO1H75zFeMPlEucPRwuuF65EBEDR8P7eeTCiw52rtnj2dG+S7R03iZWRthY54MOoYf2Hngdeut6XZ1fR1G4Q+glpyeuKY2R8LRvdv2fmCjfLqjOb/T+1nGv4/6qrGAJUzAUfyvloKOT49Gwm3cKRu//97hNk12pJ9ETwSFV+50yHx0ej/qljcWCuWdDl50yXSqzvfPgBYEEU6tZxGSluH+CHZwVtu9RpW1lBBTnz2J1XbsJHXKpzLSNgG7UweuLiV/MInp/lp/mItyyoEsulbYH7KCYHj4N8zgLuuxy2PbJFSjv+AR7pHPpLKKC7WgqFceHVH2XWfnoMhSV2zNAEF59Cv0EyktQ1HMmZ4SJXG48k3zW95JV2tSeB1X98WTfOHTEE8MIPHP95xpQHr0CHSlknWZxkcrWM4lN5xBFMjAYHwJB42FgVq/qltaW6nxQ2oVBNdFFwywWE7t79r00BLW/wmCQV5/WQFBi3Petzc0td+3huZPlnZzYYam8qGTHDGK12xRJqaurFwUk5cfdyAs+1tI6Ojram4A+7vxjXszjsdIRmVzYTTVQM/+H6BncLmwF87b+3txcXZZUKEpAlwUEggZQX8xKHgsaaGqSkqQwXv0ror7OFNli2t7S3Nra0tJy5m51dfPzH3JzcyPz8/Pd3Nyuu1/LvSqh0aRCAo9ez0ZQTbcoiLFR2t3q0an09h4L9mhsfAE+rxVpfOH6NLpdSIF18SZ7CKPWCPzRSrr4/r96y8rKwDcAjU4qjMnKujluNz6d0BuxXbAuPl3EY8tAm4bhwTJKm3x9fETToZ88WRf/PKQmJSXF2zsxMTEsKs7Tv43AptN5HC5oH/JhIjjQSksb6ut5E5OpqGBzuOSc+LzfaqCqKgiq8bj2wL9tuJ/Oq+DI5IqeW94JNkfpI18Ox4vDVQRMQxvq6MCMOd85d8vjXJz7A1xGxz0wniMT8vlC0NfLqRsAUe18KThFAt0R9BYpbWjo4UMCoQeHfIDEpeOC2gRchpxCkUgQCIQUzNZRogKITerASylDIBDQwC8SsVg8ONjd3T02NtadPAjjd4HAYGKJIhSZlGoAdlNJeyO1HADB0NAAGN4Ohve8UYQgHkwGfHCwC4MhiMWEhwOIVyhTvcmt1DNsEJIRFImY4I+rRRFRKFQtLiMjo62tDaNYbGysp7u9vSgjI70P+6XF9IHRVcb3NVCpVCLecOsK1U2bdmvoGzZ0ElF9nQ0N1L6+Pt+GTiwRa7hVVdf632NpbLN2u5HRdjUzq+mHSNtKx2zHLlWt7evXa2hofP2V1todZlaWs9qFtYW6mY26xcz+ZmlibrFOfedOGxsb9Z3rLMyt3/t2sfiXq3nzNyGTwPWnqzsiAAAAAElFTkSuQmCC";
    // img[2] = new Image ();
    // img[2].src = "";
    // img[3] = new Image ();
    // img[3].src = "";
    // img[4] = new Image ();
    // img[4].src = "";
    // img[5] = new Image ();
    // img[5].src = "";

    var time;
    time = setInterval(function(){
      draw(X,Y);
    },SPEED);

  }

  function draw(X,Y) {
    ctx.clearRect (0 , 0 , pageX , pageY);
    drawRotatedImage(img[0],x[0], y[0],counter1);
    drawRotatedImage(img[1],x[1], y[1],counter2);

    /*回転用 角度*/
    counter1 += 0.5;
    counter2 += 0.3; 

    /*落下スピード*/
    x[0] -= 1 * Math.random();
    y[0] += 2;
  
    x[1] -= 1 * Math.random();
    y[1] += 1;

    /*再描画判定座標*/
    if(y[0] > pageY + 20){
      x[0] = pageX / 2;
      y[0] = 0;
    }
    if(y[1] > pageY + 20){
      x[1] = pageX / 3;
      y[1] = 0;
    }
  }

  /*回転*/
  function drawRotatedImage(image, x, y, angle) {
    ctx.save(); 
    ctx.translate(x, y);
    ctx.rotate(angle * TO_RADIANS);
    ctx.drawImage(image, -(image.width/2), -(image.height/2));
    ctx.restore();
  }

  /*ループ*/
  window.requestAnimationFrame = (function(){
    return  window.requestAnimationFrame   ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
        window.oRequestAnimationFrame      ||
        window.msRequestAnimationFrame     ||
        function(callback){
          window.setTimeout(callback, 1000 / 60);
        };
  })();

  requestAnimationFrame(start);
  sizing();
}

  function sizing(){
    $('#canvas').attr({height:$('#wrap').height()});
    $('#canvas').attr({width:$('#wrap').width()});
  }

  $(window).load(function(){
    pageY = $('#wrap').height();
    pageX = $('#wrap').width();
    canvasbg(pageY,pageX,0);
  });
  
});
  • 初期座標、イメージパスを指定する。
  • 画像を描画する際に回転用の関数を使用する。
  • 角度をつける(インクリメント)
  • 落下スピードを指定する。
  • 最下部までいったら元の位置に戻す。

応用として、「雪」「落ち葉」「雨」などにも適応できそうです。