Javascriptで自分の体重をグラフ化する（JavascriptからGoogle SpreadSheetをGET/POSTして作成する）

# 目的
Javascriptで自分の体重をグラフ化する（JavascriptからGoogle SpreadSheetをGET/POSTして作成する）際の備忘録です

# Google Spread Sheetのデータをget/postする

### Google Spread Sheetの準備

以下を参照してGoogleスプレッドシートの内容をWebアプリケーションから取得できる状態にする。

> [Googleスプレッドシートの内容をjsonデータとして利用する](https://www.koreyome.com/web/make-spreadsheet-to-json-at-google-apps-script)

以下のようにdate/weightを入力する。
<img width="347" alt="スクリーンショット 2020-05-06 17.55.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344880/3eaee043-28c1-e797-43f2-f7dfac418c05.png">

### スクリプトからget/post functionを作成

GoogleスプレッドシートのTools→ScriptEditorから、
doGet/doPostでスプレッドシートに対してget/postするコードを作成する。
作成した後はPublish→Deploy as WebAppを選択してURLを取得する。
アクセス権設定は、今回はAnyone even anonymousなどにした（適切に設定する）

```js:コード.gs
const SHEET_ID = 'xxxxxxx'
const SHEET_NAME = 'yyyyyyy'

function getData(id, sheetName) {
  var sheet = SpreadsheetApp.openById(id).getSheetByName(sheetName);
  var rows = sheet.getDataRange().getValues();
  var keys = rows.splice(0, 1)[0];
  return rows.map(function(row) {
    var obj = {}
    row.map(function(item, index) {
      obj[keys[index]] = item;
    });
    return obj;
  });
}

function doGet(request) {
  var func = 'jsondata';
  var data = getData(SHEET_ID, SHEET_NAME);
  return ContentService.createTextOutput(func + '(' + JSON.stringify(data, null, 2) + ')')
  .setMimeType(ContentService.MimeType.JAVASCRIPT);
}

function createRow(sheet, parameter) {
  var keys = sheet.getDataRange().getValues()[0];
  var row = [];  
  keys.map(function(key) {
    var value = parameter[key];
    if (value) {
      row.push(value);
    }
  });
  return row;
}
function appendRow(sheet, parameter) {
  var row = createRow(sheet, parameter);
  sheet.appendRow(row);
}

function doPost(e) {
  console.log(e);
  var sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName(SHEET_NAME);
  appendRow(sheet, e.parameter);
}
```

尚、SHEET_ID/SHEET_NAMEは以下の通り。

```
const SHEET_ID = 'xxxxxxx' // https://docs.google.com/spreadsheets/d/xxxxxxx/edit#gid=0 の xxxxxxx の部分
const SHEET_NAME = 'yyyyyyy' // シート名
```

Publish→Deploy as WebAppを選択して取得したURLはJavascriptから指定する。
（https://script.google.com/macros/s/zzzzzzzz/exec などのこと）

# JavascriptからGET/POSTリクエスト

フォルダ構成

```
my_weight.html
my_weight.js
```

```html:my_weight.html
<!DOCTYPE html>
<html lang="ja">
  <head>
<meta charset="utf-8">
<title>自分の体重とか</title>
</head>
<body>
<h1>自分の体重とか</h1>
<div style="width: 50%; height: 50%;">
    <canvas id="my_weight" style="width: 100%; height: 100%;"></canvas>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"></script>
<script src="./my_weight.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<br><br>
<div style="width:300px; border: 2px solid #000000;">
    <form id="my-form">
        データ追加<br>
        <table>
            <tr>
            <td>記入日</td><td>><input type="date" name="date" required /></td>
            </tr>
            <tr><td>体重</td><td>><input type="number" name="weight" step="0.1" required /></td>
            </tr>
            <tr><td><input type="submit"></td><td id="status"></td></tr>
        </table>
	<div>
	  <a href="https://docs.google.com/spreadsheets/d/xxxxxx/edit?usp=sharing">引用元データはこちら</a>
	</div>
    </form>
</div>
<br><br>
<script>
    // ページ読み込み後の処理 -> SpreadSheetからデータを読み込み、canvasに描画
    window.onload = function(){
        getJsonp_GAS();
    }

    // 送信ボタンを押した際の挙動 -> SpreadSheetへデータを投稿
    $("form").submit( function(){
        var valDate = $('#my-form [name=date]').val();
        var valWeight = $('#my-form [name=weight]').val();
        sendData_GAS(valDate, valWeight);
        $("#status").text("送信しました");
        return false;                       // 遷移無効化
    });
</script>
</body>
</html>
```

```js:my_weight.js
function drawBarChart(labels, data) {
    // 4)chart.jsで描画
    var ctx = document.getElementById("my_weight").getContext("2d");
    var myChart = new Chart(ctx, {
	    type: 'line',
	    data: {
		labels: labels,
		datasets: [ {
			label: "体重(kg)", 
			data: data, 
			backgroundColor: 'rgba(60, 160, 220, 0.3)',
			borderColor: 'rgba(60, 160, 220, 0.8)',
			fill: true
		    },
		],
	    },
	    options: {
		scales: {
		    yAxes: [{
			    type: 'linear',
			    ticks: {
				beginAtZero: true,
				max: 120.0
			    }
			}]
		},
	    }
    });
}

// 出力用にlabelを整形
function format_label(date) {
	format_str = "YY/MM/DD";
	format_str = format_str.replace(/YY/g, -100 + date.getYear());
	format_str = format_str.replace(/MM/g, 1 + date.getMonth());
	format_str = format_str.replace(/DD/g, date.getDate());
	return format_str;
}

function insertionSort(l_lab, l_wei, in_lab, in_weight){
	var result = new Object();
	result.lab = new Array(0);
	result.wei = new Array(0);
	var idx;

	for (idx = 0; idx < l_lab.length; idx++) {
		if(in_lab < l_lab[idx]) {
			break;
		} else {
			result.lab.push(l_lab[idx]);
			result.wei.push(l_wei[idx]);
		}
	}

	result.lab.push(in_lab);
	result.wei.push(in_weight);

	for (let idx2 = idx; idx2 < l_lab.length; idx2++) {
		result.lab.push(l_lab[idx2]);
		result.wei.push(l_wei[idx2]);
	}

	return result;
}

// SpreadSheetからデータを受信
function getJsonp_GAS() {
	$.ajax({
		type: 'GET',
		url: 'https://script.google.com/macros/s/zzzzzzzz/exec',
		dataType: 'jsonp',
		jsonpCallback: 'jsondata',
		    success: function(json){
			var label = new Array(0);
			var weight = new Array(0);

			// jsonデータを読み込む
			for(let i=0; i < json.length; i++){
				result = insertionSort(label, weight, new Date(json[i].date), json[i].weight);
				label = result.lab;	weight = result.wei;
			}

			// 日付を基準にソート
			for(let i=0; i < label.length; i++) {
				label[i] = format_label(label[i]);
			}
			drawBarChart(label, weight);
		}
	});
}

// SpreadSheetへデータを送信
function sendData_GAS(date, weight) {
	var sendData = "date=" + date + "&weight="+weight;
        
    $.ajax({
        type: "POST",
        crossDomain: true,
	url: 'https://script.google.com/macros/s/zzzzzzzz/exec',
        data: sendData
    });
}
```

以下を同フォルダで実行してwebサーバを起動した後、

```
$ python3 -m http.server 8080 --cgi
```

http://localhost:8080/my_weight.html にアクセスしてグラフが表示されればOK
<img width="377" alt="スクリーンショット 2020-05-06 18.02.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344880/f5ec0765-9e83-29a3-3cd2-bcc2f8c23edd.png">

# 参考
[Googleスプレッドシートの内容をjsonデータとして利用する](https://www.koreyome.com/web/make-spreadsheet-to-json-at-google-apps-script)
[Google Apps ScriptのdoPostでJSONなパラメータのPOSTリクエストを受ける](https://qiita.com/shirakiya/items/db22de49f00710478cfc)
[html form not transferring data to google spreadsheets](https://stackoverflow.com/questions/47930230/html-form-not-transferring-data-to-google-spreadsheets)