いやそもそも、Google にはクラウドのアンケートフォーム機能があるのでそっちを使えって話ですが。

HTML と CSS でフォームを作り、JavaScript で簡単なデータ加工をして…と、結構自由度の高いアンケートが作れるので、Google Analytics(以下の文章ではGAと略記)でこんなこともできまっせ、という覚書をひとつ。

Google Analytics で扱えるデータ

GA はアクセス解析ツールなので、アンケート目的での使用は想定されたものではなく、本来好ましいことではありません。
しかし GA の非常に優れたポテンシャルの一例として、こんなこともできるんだーという顕彰の意を込めて、本稿を書きたいと思います。

使用するのは、ユーザーがかなり自由にカスタマイズできる、トラックイベント機能。
ga('send', 'event', CATEGORY, 'click', LABEL, COUNT, false);
CATEGORY と LABEL は文字列、COUNT は数値のデータ。
この辺をうまく利用すれば、そこそこアンケートっぽいことができます。

締切日時の設定

var today = new Date(),
    deadline = new Date('2017/2/3 00:00:00 +0900');
if (deadline.getTime() - today.getTime() <= 0) {
    return $('#message').html('投票の受附は終了しました'), false;
}
まずtodaydeadlineというふたつの時刻オブジェクト変数を宣言して、
前者に現在日時を取り込み、後者に締切日時を設定します。
Date()に日時を指定しなければ現在日時が自動的に取得されます。
この現在日時取得は最初に一回だけ行っています。
つまりこのスクリプトでは、ページ読込が締切前なら、送信が翌日になってもセーフになるわけですね。
送信のタイミングで現在日時を取得すれば、無慈悲にアウトにできますが…まあ、ぬるい方向で。
時刻の書式は上の2017/2/3 00:00:00 +0900以外にもいろいろありますが、すべての主要ブラウザで有効な書き方はこれだけです。
ふたつの時刻オブジェクトをgetTime()メソッドで単純数値に変換し、両者を比較して現在日時が締切日時を過ぎていたらメッセージを表示し、スクリプトを終了します。

というわけで、以下は締切前に実行されるスクリプトということになります。

HTML要素

さて、いよいよアンケートの中身ですが。
ここでは白糸台先輩アンケートを例にします。
このアンケートの仕様は、
  • 画像などをクリックすると、票が入る
  • 五票(クリック五回)に達したら回答終了
という単純なものです。
まず、クリックされる要素を指定する HTML は
<div style="background: url('画像URL')" data-vote="0" title="渡辺琉音" class="gapict"></div>
<div style="background: url('画像URL')" data-vote="1" title="宇野沢栞" class="gapict"></div>
<div style="background: url('画像URL')" data-vote="2" title="棚橋菜月" class="gapict"></div>
<div style="background: url('画像URL')" data-vote="3" title="沖土居蘭" class="gapict"></div>
まあこんな感じです。
title属性とか必要ではないんですが、分り易くするために残しました。
最初は普通にタグで画像を表示していたところ、ライブドアブログの仕様でスマホ版の画像には自動でリンクが貼られ、クリックすると強制的に画像表示ページに移行してしまうので、CSS のbackgroundでの表示に変更しました。
この場合、画像サイズに合わせてwidthheightの指定も必要になりますが、省略。
ここで重要なのは、「クリックで票が入る」共通のクラス.gapictと、個別のデータ値を取るdata-vote属性です。

data-○○属性について

今回のように単純なスクリプトの場合、id属性を使って何の問題もないのですが、「要素自体に要素のデータを保持させる」ことができるdata-○○属性は、非常に便利です(○○の部分は適当な半角英数字)。
利点は、
  • 値の書式が自由。カンマなどで区切って複数のデータを保持させられる。日本語も使える
  • jQuery のdata()メソッドで簡単に操作できる
各属性もデータの一種と言えるので、逆に言えば、コードを書く人が、新たな属性を無制限に作れる、ということになりますね。

クリックイベント

さて話を JavaScript(jQuery)に戻しまして。
まず、countという変数を定義し、投票の上限である 5 という数字をセットします。
次に、.gapictというクラスの要素がクリックされた時のイベントリスナーを登録します。
var count = 5;
$('.gapict').click(function() {
  /********(処理)********/
});
ここの/********(処理)********/の部分に、させたいことを書いていきます。
if(!count) return false;
カウントがゼロに達していたら、何もせずに抜けます。
以下はカウント(票数)が残っている場合の処理になります。
  1. 残り票数のカウント処理

    count--;
    _ls.setItem('vote', count);
    カウントを一つ減らします。
    また、Local Storage 機能を使う場合、setItem()でデータ(この場合残り票数)を保存します。
    これをやっておくと、いったん投票ページを離れてもブラウザが記憶してくれています。
    詳しくはで。
  2. Google Analytics へのデータ送信処理

    ga('send', 'event', 'VOTE-SRITDI', 'click', $(this).attr('title'), 1, false);
    そして、ここで GA に投票データを送信しています。
    送信のタイミングは、投票内容をいったん回答者様に確認してもらい、ボタンが押された時、などとした方がいいかもしれませんが…
    'VOTE-SRITDI'はイベントカテゴリの名前。
    GA の管理画面で、全イベントの中からこのカテゴリだけを抽出して表示させることができます。
    イベントラベルにはtitle属性の先輩の名前を格納します。
    こうすることで、管理画面でこんな風に表示させることができます。
    sritdivote
  3. ギミック処理

    クリックしたとき、先輩にセリフを言わせます。
    一人当たり五通りのセリフを用意しておき、ランダムにフキダシを表示します。
    var rect = this.getBoundingClientRect();
    $('<div class="baloon">' + words[1*$(this).data('vote')][Math.floor(Math.random()*5)] + "</div>").css({
        left: rect.left + (document.body.scrollLeft || document.documentElement.scrollLeft) + 84 + 'px',
        top: rect.top + (document.body.scrollTop || document.documentElement.scrollTop) - 20 + 'px'
    }).appendTo(document.body).fadeIn('normal').delay(1000).fadeOut('fast', function() {
        this.remove()
    })
    処理内容は喋る麻雀牌とほぼ同じです。
    違うのは、フキダシを表示する座標が、マウスではなく、クリックされた画像の位置を基準にしていることです。
    なお、セリフはあらかじめ、wordsという二次元配列に、セリフ5通り×4人分、の計20個を入れて定義しています。
    定義の仕方はこんな感じ。
    var words = [
        [ 'セリフ0-0', 'セリフ0-1', 'セリフ0-2', 'セリフ0-3', 'セリフ0-4' ],
        [ 'セリフ1-0', 'セリフ1-1', 'セリフ1-2', 'セリフ1-3', 'セリフ1-4' ],
        [ 'セリフ2-0', 'セリフ2-1', 'セリフ2-2', 'セリフ2-3', 'セリフ2-4' ],
        [ 'セリフ3-0', 'セリフ3-1', 'セリフ3-2', 'セリフ3-3', 'セリフ3-4' ]
    ];
    words[1][2]と書けば、「セリフ1-2」が指定されます。
  4. メッセージ表示処理

    デフォルトのメッセージは
    <div id="message">あなたの残り票数は<span>5</span>です</div>
    という<div>要素で表示してあります。
    ここに、票数が残っていればその値を、残っていなければ「投票ありがとうございました!」を表示します。
    if(count > 0){
        $('#message>span').html(count);
    }
    else{
        $('#message').html('投票ありがとうございました!');
    }
    

CSSでフキダシのフォントを漫画仕様に

漫画のセリフの写植は、漢字がゴシック体・かなが明朝体という組合せになっていることが多いですよね。
それをCSSで再現するのは地味に大変ですが、とりあえずいちばん頭の悪そうなやり方でやってみました。
フキダシ要素div.baloonは、喋る麻雀牌のdiv.pai-saidとほぼ同じなので、変更点であるフォント設定の部分だけを御覧に入れます。
.baloon{
  font-weight: bold;
  font-family: '游明朝', YuMincho, 'ヒラギノ明朝 ProN W3', 'Hiragino Mincho ProN', 'HG明朝E', 'MS P明朝', 'MS 明朝', serif;
}
.baloon>i{
  font-style: normal;
  font-family: '游ゴシック体', 'Yu Gothic', YuGothic, 'ヒラギノ角ゴ Pro', 'Hiragino Kaku Gothic Pro', 'メイリオ', 'Meiryo', sans-serif;
}
明朝体を主とし、漢字にひたすら<i>タグをかぶせていくというまさかの手作業…
HTMLをこういう風に書くと
<div class="baloon">
  <i>私</i>は<i>麻雀</i><br />それほど<i>好</i>きじゃないんです
</div>
麻雀
それほどきじゃないんです
まあ、こんな感じにね!
なおスマホなどで明朝体のフォントが入っていないOSだと、何の効果も出ません。
本格的にやるなら、WEBフォントを使うのがいいと思います。
(ただ、日本語でフリーのWEBフォントってなかなか無いんですよね…)

<i>タグはもともと文字を斜体にするために使われていたタグですが、HTML5ではそうした修飾はCSSで行うことが推奨されており、現在あまり使いどころがないのでここで使ってみました。
セカイでは「i」だからアイコン用のタグにしちゃえば?なんて話も出ているようですが。

Local Storage を利用した二重回答回避策

白糸台先輩人気投票では使いませんでしたが、どうしても二重回答させたくない場合には、この機能が便利です。
Local Storage とは、閲覧者のブラウザに保存される、 Cookie に似たデータの塊です。
Cookie と違い、有効期限を必ず設定しなければならないという縛りがないなど、利便性が高いので、Cookie に取って代わりつつあるようです。
var _ls = localStorage,
    _cnt = _ls.getItem('vote'),
    count = null==_cnt? 5 : parseInt(_cnt);
localStorageは JavaScript のグローバルオブジェクトで、ブラウザに以前保存したページの情報があれば、それが格納されています。
上の例ではvoteという項目の有無を調べ、それが存在しなければ新規ということでカウントに5をセットし、存在すればその値をカウントにセットしています。
そして回答が送信されたタイミングで
_ls.setItem('vote', count);
などと実行すれば、「残り票数はcount、回答済み」という情報が保存されるわけです。

他にもサイトへの訪問回数、ニックネームなどを、サーバーに送ることなく(サイト管理人に知らせることなく)保存できます。
ゲームサイトならプレイデータなんかをセーブするのに便利ですね。
ウチもそのうち何かに使ってみたいなあ…