LoginSignup
4
2

More than 3 years have passed since last update.

世界中の人とミーティング時間を決める時に便利なやつ

Last updated at Posted at 2019-10-19

スクリーンショット

なにはともあれスクリーンショット

image.png

タイトルの通り、時差を確認しながらミーティング時間の候補を選ぶことのできるSPAを作ってみたので、その時に調べたり、考えたりしたことを書いてみることに。

各種ライブラリに頼って簡単に作るつもりでしたが、こんなシンプルなものでも動くものを書くにはそれなりにやることあるねぇ... という感じでした。勉強になった。

デモ

  1. 都市をいくつか選んで
  2. でてくるタイムラインからいくつか時間を選んで
  3. 右下のボタン押したら、ミーティング候補を見れて、コピペもできます

ライブデモ

ライブデモはこちら

やったことをつらつらと

今回調べたり、ハマったりした出来上がるまでの過程をつらつらと書いていきます。

国や都市の情報

都市データ

国名・都市名・規模(人口)の情報は、ここの情報をつかわせていただきました。人口○万人以上みたいな感じで主要な都市だけをフィルタして使っています。

都市の情報
  { city: 'Los Angeles',
   city_ascii: 'Los Angeles',
   lat: 33.98997825,
   lng: -118.1799805,
   pop: 8097410,
   country: 'United States of America',
   iso2: 'US',
   iso3: 'USA',
   province: 'California',
   state_ansi: 'CA',
   timezone: 'America/Los_Angeles' },

国旗

国旗はここのが、こんな感じでURLに country code 入れるだけで取れるので、使いやすかったです。

<img src="https://www.countryflags.io/jp/flat/64.png">

背景画像

背景の都市画像は毎回違う画像が出てます。Unsplash Source という素晴らしいサイトを使っています。かなりいいクオリティーの画像を提供してくれる上に、ランダムとかキーワードに関連する画像だけといったフィルタまでできて、これスゲーわ。

都市を選択するUI

複数の都市を選択するUI部分ですが、入力が tag になる multi-select で決まりです。ここ。選択したものが、Vuedata に入るので、もう、そのまま使ってます。
image.png

時差の計算

最初は上記の都市データから lat, lngを引数に Googleの Time Zone API で時差計算しようかと使おうかとしてましたが、ここspacetimeというライブラリを発見。タイムゾーンをいい感じにいろいろといじることかできる、今回の用途にぴったりなライブラリを見つけてしまい、あっさり寝返りました。これです。

時差計算
<script src="https://unpkg.com/spacetime"></script>
<script>
  // make a new Date in New York
  var d = spacetime('March 1 2012', 'America/New_York')
  d = d.time('4:20pm')
  d = d.goto('America/Los_Angeles')
  d.time()
  //'1:20pm'
</script>

こんな感じで、複数の時間を扱うのが超簡単!ということで、もうバックエンドAPIいらん。全部フロントエンドでやることことに。

タイムラインの配列つくって、ページネーション

タイムラインをつくる

これは、spacetime に頼り切る。こんな感じで、ある DateTime をいろんな場所の時間に変換 (goto)できるんで、らくらく。作者に感謝。

「NYの午後4時20分」は「LAの午後1時20分」
  var d = spacetime('March 1 2012', 'America/New_York')
  d = d.time('4:20pm')
  d = d.goto('America/Los_Angeles')
  d.time()  //'1:20pm'

あとは

d = d.add(1, 'week')
d = d.add(30, 'minutes')

とかで時間を動かせるので、簡単にタイムラインのデータ(今回は配列)は作ることができる。

その日のどのへんの時間かを0.0-1.0で表す
d.progress().day

progress といういけてるメソッドがあって、使って時間帯を0.0-1.0の間の値で返せる(素晴らしい!)。これで(朝・昼・夜)判定して、タイムラインに時間に応じた色つけをやったのだが...描画(処理)が極端に遅くなったために結局、使うの諦めた。

ページネーション

右上の矢印のコントロールでタイムラインを「次の日」とか「次の週」とかにする方法。どうやってページネーションを簡単にできるかなーと調べていて、このサイト見つけた。これで事前に配列の配列を作っておけばいいのではないか。

配列をn個の要素づつの「配列の配列」にする
Array.prototype.divide = function(n) {
  var ary = this;
  var idx = 0;
  var results = [];
  var length = ary.length;

  while (idx + n < length){
    var result = ary.slice(idx,idx+n)
    results.push(result);
    idx = idx + n
  }

  var rest = ary.slice(idx,length+1)
  results.push(rest)
  return results;
}

// 使い方
['1am','2am','3am','4am','5am','6am','7am','8am','9am','10am'].divide(4) 
//=> [['1am','2am','3am','4am'],['5am','6am','7am','8am'],['9am','10am' ]]

['1am','2am','3am','4am','5am','6am','7am','8am','9am','10am'].divide(3) 
//=> [['1am','2am','3am'],['4am','5am','6am'],['7am','8am','9am'],['10am']]


これで、タイムライン全体(数日分)を1日分(24時間)ずつの時間の配列に分割すれば、簡単に次の日や次の週などに移動する(ページネーション)できる

Vue のリアクティブ

今回ほとんどのデータがリアクティブになって欲しかった。Vue 勉強中の身としてはここはいろいろハマる。特にオブジェクトや配列の操作は普通に push とかじゃなくて、適宜 splice()$set で操作しないとリアクティブにはならない。まあ、公式読めという話。

クリップボードにコピー

メールなどに貼り付けて送れるように、モーダルの画面で、ミーティング候補日をクリップボードにコピーするところ。これ、いろいろ試しました(いろいろ方法ある)が、最終的にいい感じに動いたのはこれ。clipboard.js いいわ

クリップボードにコピー

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.4/clipboard.js"></script>

<div id="app">
    <textarea hidden v-model="jsonData" type="text"></textarea>
    <button class="btn" :data-clipboard-text="jsonData">Copy</button>
    <button class="btn" @click="add">Add</button>
</div>

<script>
var clipboard = new ClipboardJS('.btn');

clipboard.on('success', function(e) {
    console.info('Action:', e.action);
    console.info('Text:', e.text);
    console.info('Trigger:', e.trigger);
    e.clearSelection();
});

clipboard.on('error', function(e) {
    console.error('Action:', e.action);
    console.error('Trigger:', e.trigger);
});

var vm = new Vue({
    el: "#app",
    data: {
        jsonData: { id: 1, "name": "taro", "items": ["note", "pen", "eraser"] },
    }
})

YAMLを扱う

クリップボードにコピーしたものはJSONだけど、YAMLの方が可読性がいいので変換する。

JSONをYAMLに

<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/3.13.1/js-yaml.js"></script>

//  { id: 1, "name": "taro", "items": ["note", "pen", "eraser"] }
var json = JSON.stringify(this.jsonData)
var yaml = jsyaml.load(json)
this.yamlData = jsyaml.safeDump(yaml)
console.log(this.yamlData)

アウトプットこんな感じ。

id: 1
name: taro
items:
  - note
  - pen
  - eraser

うん。メール本文に貼り付けるなら、こっちの方がだいぶいい。

細かいUI周り

・タイムラインの為に、CCS Bluma で縦にコンテンツ配置
BlumaHERO の背景に画像を入れる

その他、細かいのはいろいろありますが、また時間のある時にでも書きたい。

シリーズ

Cheers,

4
2
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
4
2