LoginSignup
11
11

More than 5 years have passed since last update.

GoogleForm+GoogleSpreadsheet で集めたコメントをタグクラウドにする

Last updated at Posted at 2018-03-22

概要

とあるイベントに参加しているユーザが自由なテキストを投稿した際に、それらのワードがタグクラウドとなって会場のディスプレイに表示されたら面白そうだよね!

と言っていた方がいたので検討してみました。

実際には mentimeter を活用して当日は下記のようなものができたそうです。

image.png

大まかな仕組み

  1. Google Form にて一行テキストが投稿できるように設定
  2. 投稿の保存先をSpreadsheetにしておく
  3. そのSpreadsheetをWebアプリケーションとして公開しJSONを吐くようにする
  4. JSONを読み込むWebページ(HTML/JavaScriptで良い)を設置する

手順

Google Form で投稿フォームを作成

下記のようにします。あとで楽なので、質問のタイトルは「comment」などの半角英字にしておくと良いと思います。(本記事はここでcommentと設定した前提とします)

image.png

下記のようなフォームができます。

image.png

上記の動作をするものを下記リンクから辿れるようにしてあります

投稿の保存先をスプレッドシートにする

テスト回答して、回答を一件作成すると、回答先としてスプレッドシートが選べるようになります。

image.png

回答が記入されています。

image.png

このスプレッドシートのURLを控えておきます。

今回は:https://docs.google.com/spreadsheets/d/1XTXONJ3pMBE8qiWlATCnHNqCwbsF8bEO1WaeVQ8x6Nk/edit#gid=1574077758 というURLです。

スプレッドシートのデータをWebアプリケーションとして公開

AppsScriptを用いて、Webアプリケーションを作成します。

スクリーンショット 2018-03-22 10.16.22.png

コードの記述

image.png

コード.gs として、以下のコードを貼り付けます。

こちらを利用させていただきました:https://gist.github.com/daichan4649/8877801

URL_BOOKの値には、先程控えたスプレッドシートのURLを入れてください。

コード.gs
var URL_BOOK = 'https://docs.google.com/spreadsheets/d/1XTXONJ3pMBE8qiWlATCnHNqCwbsF8bEO1WaeVQ8x6Nk/edit#gid=1574077758';

function doGet(e) {
  var url = URL_BOOK;
  var book = SpreadsheetApp.openByUrl(url);
  var sheets = book.getSheets();
  var sheet = sheets[0];

  var json = convertSheet2Json(sheet);
  return ContentService.createTextOutput(JSON.stringify(json))
    .setMimeType(ContentService.MimeType.JSON);
}



function convertSheet2Json(sheet) {
  // first line(title)
  var firstRange = sheet.getRange(1, 1, 1, sheet.getLastColumn());
  var firstRowValues = firstRange.getValues();
  var titleColumns = firstRowValues[0];

  // after the second line(data)
  var lastRow = sheet.getLastRow();
  var rowValues = [];
  for(var rowIndex=2; rowIndex<=lastRow; rowIndex++) {
    var colStartIndex = 1;
    var rowNum = 1;
    var range = sheet.getRange(rowIndex, colStartIndex, rowNum, sheet.getLastColumn());
    var values = range.getValues();
    rowValues.push(values[0]);
  }

  // create json
  var jsonArray = [];
  for(var i=0; i<rowValues.length; i++) {
    var line = rowValues[i];
    var json = new Object();
    for(var j=0; j<titleColumns.length; j++) {
      json[titleColumns[j]] = line[j];
    }
    jsonArray.push(json);
  }
  return jsonArray;
}

公開

メニューの「公開」>ウェブアプリケーションとして導入... を選択します。

image.png

設定は上記のようにします。匿名ユーザがアプリケーションにアクセスできるようにしましょう。

「導入」を選ぶと「承認が必要です」と言われるので「許可を確認」します。

警告などが出ますが、自分が作っているアプリケーションなので問題ありません。許可してください。

完了すると、WebアプリケーションのURLを取得できるので、それを控えてください。

image.png

JSON出力の確認

上記で控えたURL(今回は:https://script.google.com/macros/s/AKfycbya60HH2kMsthpWX54Ncu9efhoqHViWIh3NOBVBRdjBhDv2saQ/exec) を実行すると、JSONデータが返ってきます。

[{"タイムスタンプ":"2018-03-22T01:12:58.167Z","comment":"test"}]

試しにデータを追加してみると

[{"タイムスタンプ":"2018-03-22T01:12:58.167Z","comment":"test"},{"タイムスタンプ":"2018-03-22T01:26:44.029Z","comment":"test2"}]

このような形にかわります。

このJSONを読み込むHTML/JavaScriptを用意

今回は、d-cloudというライブラリを使ってみました。

HTML/JSのコードはこんな感じになります。

こちらを利用させていただきました: https://shimz.me/blog/d3-js/2711

test.html
<script src="../d3.v3.min.js"></script>
<script src="d3.layout.cloud.js"></script>
<script>
var spUrl = "JSONを吐いてくれるアプリケーションのURL";
d3.select('svg').append('text')
.attr({
    x:50,
    y:50,
    fill:"black",
    "font-size":40
})
.text('Loading...');

// メイン
d3.json(spUrl, function(data) {
    // [{timestamp: ts, comment: comment}, ... ] を [{count:c, word: w}, ... ] に変換
    var words = [];
    var objMap = [];
    var map = data.map(function(d) {
        // 単語だけの配列:words
        var i = words.indexOf(d.comment);
        if (i !== -1) {
            objMap[i]["count"]++;
        } else {
            words.push(d.comment);
            objMap.push({"count": 1, "word": d.comment});
        }
    });
    data = objMap;
    var h = 400;
    var w = 400;
    data = data.splice(0, 1200); //処理wordを1200件に絞る

    var random = d3.random.irwinHall(2)

    var countMax = d3.max(data, function(d){ return d.count} );
    var sizeScale = d3.scale.linear().domain([0, countMax]).range([10, 100])
    var colorScale = d3.scale.category20();
    var words = data.map(function(d) {
        return {
            text: d.word,
            size: sizeScale(d.count) //頻出カウントを文字サイズに反映
        };
    });

    d3.layout.cloud().size([w, h])
        .words(words)
        .rotate(function() { return Math.round(1-random()) *90; }) //ランダムに文字を90度回転
        .font("Impact")
        .fontSize(function(d) { return d.size; })
        .on("end", draw) //描画関数の読み込み
        .start();

    //wordcloud 描画
    function draw(words) {
        d3.selectAll('text').remove();
        d3.select("svg")
            .attr({
                "width": w,
                "height": h
            })
            .append("g")
            .attr("transform", "translate(150,150)")
            .selectAll("text")
            .data(words)
            .enter().append("text")
            .style({
                "font-family": "Impact",
                "font-size":function(d) { return d.size + "px"; },
                "fill": function(d, i) { return colorScale(i); }
            })
            .attr({
                "text-anchor":"middle",
                "transform": function(d) {
                    return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
                }
            })
            .text(function(d) { return d.text; });
    }

});
</script>

完成

それっぽい感じになりました。

image.png

レイアウト等々はオプションで調整してみてください! 実際に利用するには自動リフレッシュとかも入れたほうがいいと思います。

11
11
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
11
11