猫になりたかった人生です。

猫になりたかった人生です。

とある情報系専門学校生の活動記録

GASの作品がちょっとだけ進化した話

GAS(Google Apps Script)から逃れられない。

慣れてくると便利だなと離れられなくなってしまいました。
今年も美味しい食べ物と仕事が増える季節がやってきました。
どうも、猫さんことセンセです。

本記事は、去年4月から作りたいと思いつつもできていなかったGASの天気予報の発展版を見せれる程度にはできたので、紹介記事になります。
前に投稿されていたものから更新を兼ねた書き換えです。
今後も作品について詳しい説明を更新していこうと思います。

成果物

作品URL:天気予報ノート
コード:GitHub

画像


f:id:MI_SAN_CAT:20181024143136p:plain
f:id:MI_SAN_CAT:20181024143139p:plain
f:id:MI_SAN_CAT:20181024143142p:plain
f:id:MI_SAN_CAT:20181024143145p:plain


Ⅰ.f:id:MI_SAN_CAT:20181024145501p:plain
Ⅱ.f:id:MI_SAN_CAT:20181024145458p:plain

関数の説明

調べながら組み合わせて作成したので、あまりよろしくないプログラムになっていると思います。
語彙力が地獄に落ちてしまっているので、説明もざっくりと

doGet

function doGet() {
var htmloutput = HtmlService.createTemplateFromFile('Page').evaluate();
htmloutput.setTitle('天気予報ノート').addMetaTag('viewport', 'width=device-width, initial-scale=1');
return htmloutput;
}

お馴染みのdoGetです。
他の環境で開発する際は他にも長い内容が必要なのが多いですが、GASだと基本これだけで済みます。(だから離れられなくなる)
createTemplateFromFile等の説明はhttps://tonari-it.com/gas-web-application-beginner/:こちらのサイトが分かりやすかったです(/・ω・)/
titleタグやmetaタグ等は、読み込まれない的なめんどくさいことがあるのでsetTitleでタイトル設定しています。
addMetaTagではスマホからの表示に対応させています。

画像のセレクトボックスのonChange

    function areaSet(obj) {
      var check;
      if (obj.id == 'Area') {
        check = 0;
        var areaIndex = obj.selectedIndex;
        google.script.run.withSuccessHandler(setArea).withUserObject(check).areaList(areaIndex);
      } else if (obj.id == 'Point') {
        check = 1;
        var areaName = document.getElementById('Point').value;
        google.script.run.withSuccessHandler(setArea).withUserObject(check).setPoint(areaName);
      }
    }

    function setArea(area_list, check) {
      var setsel;
      var desc_str;
      if (check == 0) {
        setsel = document.getElementById('Point');
        desc_str = '②都道府県を選択してください';
      } else if (check == 1) {
        setsel = document.getElementById('DoArea');
        desc_str = '③観測地点を選択して、「天気取得」ボタンをクリックして下さい';
      }
      setsel.options.length = 0;
      clearChildNodes(setsel);
      for (var key in area_list) {
        // option要素の宣言
        var option = new Option(area_list[key], key);
        // 作成したoption要素をselectに追加
        setsel.appendChild(option);
      }
      document.getElementById('result_area').textContent = desc_str;
    }

選択された地方の都道府県や選択された都道府県の観測地点を連想配列にして返してセレクトボックスのOptionに追加します。
都道府県はswitchで、観測地点はスプレッドシートをDBに見立てて取得しています。
スプレッドシートは、地点一覧の開始と終了位置を別のシートに置いておき二度取得させています。(ⅠとⅡ)

天気取得のonClick

function getWeather() {
      var strset = document.getElementById('result_area');
      var val = document.getElementById('DoArea').value;
      strset.textContent = '天気取得中';
      google.script.run
        .withSuccessHandler(setWeather)
        .withFailureHandler(dontset)
        .getJson(val);
    }

    function setWeather(strBox) {
      var titlis = [
        ['today_date', 'today_weather', 'today_high', 'today_low'],
        ['tommorow_date', 'tommorow_weather', 'tommorow_high', 'tommorow_low'],
        ['tommorows_date', 'tommorows_weather', 'tommorows_high', 'tommorows_low']
      ];
      var idlist = ['today', 'tommorow', 'tommorows'];

      document.getElementById('result_area').innerHTML = strBox['location'];

      for (var i = 0; i < 3; i++) {
        var cls = document.getElementById(idlist[i]);
        if (cls.hasChildNodes()) {
          for (let i = cls.childNodes.length - 1; i >= 0; i--) {
            cls.removeChild(cls.childNodes[i]);
          }
        }
        var pTag = document.createElement('pre');
        pTag.setAttribute('class', 'pre');
        for (var j = 0; j < 4; j++) {
          pTag.textContent += strBox[titlis[i][j]];
          pTag.textContent += '\n';
        }
        cls.appendChild(pTag);
      }
      var txt = document.createElement('pre');
      txt.setAttribute('id', 'text');
      txt.setAttribute('class', 'pre');
      txt.innerHTML = strBox['text'].split('】').join('】\n');
      document.getElementById('tommorows').insertAdjacentElement('afterend', txt);
      document.getElementById('weather_announce').innerHTML = strBox['announce'];
      document.getElementById('weather_link').href = strBox['link'];
      document.getElementById('weather_link').textContent = '天気予報取得元';
    }

    function dontset() {
      document.getElementById('result_area').textContent = '天気取得失敗';
    }
  function getJson(point) {
    point = '' + point;

    var data = UrlFetchApp.fetch('http://weather.livedoor.com/forecast/webservice/json/v1?city=' + point);
    var json = JSON.parse(data.getContentText());
    Logger.log(json);
    var text = makeText(json);
    return text;
  }

  function makeText(json) {
    var titlis = [
      ['today_date', 'today_weather', 'today_high', 'today_low'],
      ['tommorow_date', 'tommorow_weather', 'tommorow_high', 'tommorow_low'],
      ['tommorows_date', 'tommorows_weather', 'tommorows_high', 'tommorows_low']
    ];
    var strBox = {};
    var hightem;
    var lowtem;
    //天気取得位置
    strBox['location'] = json['title'];

    for (var i = 0; i < 3; i++) {
      for (var j = 0; j < 4; j++) {
        switch (j) {
          case 0: //日付
            strBox[titlis[i][j]] = json['forecasts'][i]['date'];
            break;
          case 1: //天気
            strBox[titlis[i][j]] = '天気:' + json['forecasts'][i]['telop'];
            break;
          case 2: //最高気温
            if (json['forecasts'][i]['temperature']['max'] == null)
              hightem = 'データ無し';
            else
              hightem = json['forecasts'][i]['temperature']['max']['celsius'];
            strBox[titlis[i][j]] = '最高気温:' + hightem;
            break;
          case 3: //最低気温
            if (json['forecasts'][i]['temperature']['min'] == null)
              lowtem = 'データ無し';
            else
              lowtem = json['forecasts'][i]['temperature']['min']['celsius'];
            strBox[titlis[i][j]] = '最低気温:' + lowtem;
            break;
        }
      }
    }
    strBox['text'] = json['description']['text'];
    //発表日時
    strBox['announce'] = '発表日時:' + json['description']['publicTime'];
    //サイトのリンク
    strBox['link'] = json['link'];
    return strBox;
  }

前の処理で③のセレクトボックスの選択項目のvalueに地点のIDをセットしておき、そのIDをgetJsonに投げて天気予報のJSONを取得してきます。
取得したJSONをmakeTextに投げて一つの連想配列にしてsetWeatherに投げてpreタグに追加して表示しています。

去年からの進化

授業でHTMLを少し勉強したので一気にかっこよくなった()
onChangeで実装出来たので地点の選択項目一覧が少なめになっている。
GitHubでコード管理をできるようにした。Chrome拡張機能で便利に!
CSSってすごいね!未だによく分かってないけど自分の描きたいデザインが沢山ある(お借りした)
SNS共有できるようになりました(TwitterとLINE)

その他

相変わらずスプレッドシートをDBに見立てて使用しているが、改善しないと動作が遅いかもしれないと思っています。

当日の最低気温が出ないのが少し残念なので、別のAPIの使用を考慮するか天気予報系からの卒業をする予定です。

メール送信機能が実装できていないので、いつか本文の見た目を弄って実装しておきます。

時間ごとの自動ツイートもアプリ連携でユーザごとに変えたり出来たらいいなと思います。

エディターの色を変えるとあら不思議、失いかけていたモチベが復活したではありませんか。(Chromeの拡張です)