あいつの日誌β

働きながら旅しています。

Gatsby v1.3.0 を試す(1)

あらすじ

React.js と Vue.js のどちらが優れているかはどちらでも良いと思っています。なんですが React.js のエコシステム のほうが一歩先を歩んでいると思っています*1。私が React.js のエコシステムを推す理由に一つになっているツールがめでたくメジャーバージョンをリリースしたのでご紹介したいと思います。

Gatsby とは

Markdown を記述して Static な page を書き出すツールです。いわゆる Static Generator。今回のバージョンから Markdown 以外にも色々なところからデータを集積して Graphql で取り出すインターフェースが採用されました 。

f:id:okamuuu:20170726194358p:plain

私が Gatsby を好む理由ですが、React.js で書いた Compnent をそのまま利用できるところです。react-storybook 上に state less な compnents を集めている人はその財産をそのまま利用できます。

GraphQL とは

このあたりの記事を参考にすると良いのではないでしょうか。

GraphQL の概念とかその辺の記述を読んでいると時間かかると思いますが、最低限自分が必要な場面での使い方を覚える分にはそんなに時間かからないと思います。

GatsbyGraphiQL というツールを使って問い合わせできるので少しだけ紹介します。

github.com

Try GraphQL

やってみます。

npm install -g gatsby
gatsby new personal-blog && cd $_
npm run develop

次のような画面が出てきたら成功です。

 DONE  Compiled successfully in 182ms                                                                      15:27:47

 I  Your site is running at http://localhost:8000
 I  Your graphql debugger is running at http://localhost:8000/___graphql

http://localhost:8000/___graphql を開いてみましょう。これが graphiql の画面です。試しに以下のような Query を書いてみましょう。

query {
    allSitePage(limit:1000) {
      edges {
        node {
          id
        }
      }
    }
  }

そうすると以下のような画面になると思います。

f:id:okamuuu:20170726194216p:plain

Gatsby の Node について

詳しくは下記のドキュメントをご覧下さい。Gatsby は元となるデータをMarkdown であったり、JSON ファイルなどから集積しますが、その単位が以下の Node と呼ばれるものです。

https://www.gatsbyjs.org/docs/node-interface/

Graphql で問い合わせするのはこの node です。Gatsby をカスタマイズしたい場合は、node を作成する ことと Graphql で node を取得 する方法を覚えれば OK です。

Markdown で Node を追加して Grahpql で取得する

とりあえず一通り以下の Blog の通りに作業してみましょう。

www.gatsbyjs.org

手順通りに終わったら以下の Graphql を書いて見ましょう。以下が Markdown で記述された Node 一覧 です

query {
    allMarkdownRemark(filter: {}) {
      edges {
        node {
          id
        }
      }
    }
  }

以下のようなレスポンスが返ってくると思います。以下の例では Markdown のファイルを2個作成しています。

{
  "data": {
    "allMarkdownRemark": {
      "edges": [
        {
          "node": {
            "id": "/Users/okamuuu/personal-blog.bak/src/pages/08-12-2017-getting-next/index.md absPath of file >>> MarkdownRemark"
          }
        },
        {
          "node": {
            "id": "/Users/okamuuu/personal-blog.bak/src/pages/07-12-2017-getting-started/index.md absPath of file >>> MarkdownRemark"
          }
        }
      ]
    }
  }
}

次に Node 詳細 を問い合わせします。

query {
    markdownRemark(frontmatter: {path: {eq: "/hello-world"}}) {
      html
      frontmatter {
        date(formatString: "MMMM DD, YYYY")
        path
        title
      }
    }
  }

以下の結果が表示されると思います。

{
  "data": {
    "markdownRemark": {
      "html": "<p>Oooooh-weeee, my first blog post!</p>",
      "frontmatter": {
        "date": "July 12, 2017",
        "path": "/hello-world",
        "title": "My First Gatsby Post"
      }
    }
  }
}

というわけでなんとなく Gatsby が集積した情報を問い合わせる方法が分かるんじゃないかと思います。

あと Front Matter について

下記に詳しい説明があるのでこの単語に聞き覚えがない方は一度ご一読下さい。

jekyllrb.com

まとめ

GatsbyMarkdown を使って Static Site を作る方法を学びました。 次回は JSON file から Static な Site を生成する方法を紹介します。

*1:React.js と Vue.js との優劣は議論する気はないのですがこれらのエコシスムの一長一短に関しての議論は歓迎します

夏らしさを求めておじさん2人が南伊豆へ旅した記録 2017

あらすじ

夏らしい事をしたいが、7月8月の週末は今回(7月22日の時点)を逃すと今年は最大でも6回しかない。チャンスは少ない。ならば俺たちは今すぐ行かねばならない。

どうしてそうなった?

あんまり覚えてないんですが確かこんな感じの話をしたんだと思います。

  • 夏らしい事をしたいよね
  • 海だよね!
  • シュノーケリングしたいんだよ
  • ところで南伊豆のヒリゾ浜はいい感じなんじゃないか?
  • 行ってみるか!
  • ついでにヒリゾ浜へ向かう途中でいい感じの砂浜を見つけるか!

という訳で南伊豆の海岸(東側と南側)を探索しました。

タイムテーブル

時間はあんまり正確じゃないですがこんな感じだったと思います。

初日

時間 内容
7月22日(土) 12:30 行くぞと決まる
7月22日(土) 13:00 品川へJR山手線で移動開始
7月22日(土) 13:30 熱海へ伊豆特急で移動開始
7月22日(土) 15:00 弓ヶ浜(下田)へレンタカーで移動開始
7月22日(土) 19:00 弓ヶ浜のもき丸で晩御飯
7月22日(土) 22:00 就寝

二日目

時間 内容
7月23日(日) 8:00 起床
7月23日(日) 8:30 弓ヶ浜の青木さざえ店で朝ごはん
7月23日(日) 10:00 チェックアウト
7月23日(日) 10:30 逢ヶ浜でシュノーケリングを楽しむ(素潜り)
7月23日(日) 11:30 ヒリゾ浜へレンタカーで移動開始
7月23日(日) 13:30 ヒリゾ浜シュノーケリングを楽しむ(素潜り)
7月23日(日) 14:30 熱海に向かってレンタカーで移動開始(下田街道を北上)
7月23日(日) 18:00 熱海到着レンタカー返却
7月23日(日) 18:30 解散
7月23日(日) 19:00 熱海 -> 品川へ新幹線で移動開始
7月23日(日) 19:50 品川へ到着

都内 -> 品川

特急踊り子号(伊豆急下田行) で。JR山手線内で移動中にスマホで席を確保します。えきねっとを使いましょう。品川駅で特急券を受け取ります。

品川駅で乗車券を受け取りつつレンタカーを手配します。最初、レンタカーは熱海のレンタリースのHPを見るも全て貸し出し中になっていました。電話したら何故か借りられたので今回はギリギリセーフ。 車借りられないと今回の旅は何もできないんで結構つらいのでちょっと危なかった。どの駅に降りるかは車を借りてから決めるようにすると良いでしょう。

品川 -> 熱海

さて、無事に新幹線に乗りました。さて現時点で我々のステータスは下記の通り。

  • 今回の旅は1泊2日でヒリゾ浜は素敵なんだろうかという調査をする。
  • 熱海で降りて、レンタカーを借りて下田へ移動する

現時点、ほぼ無策です。そんなわけで新幹線の移動時間を使ってスマホを使って情報収集を行います。この時間で計画、実行できた事

  • 南伊豆町にある弓ヶ浜というビーチもあるのでここを初日の目的地に定める
  • 宿泊所施設にチェックインして晩御飯を食べる
  • 翌日ヒリゾ浜へ向かう

熱海 -> 下田

という事でレンタカーを借りて移動開始、車内で楽天トラベルを使って宿泊所施設を予約し移動開始。大体90km ぐらいでしょうか。思った以上に伊豆半島は大きかった。次回ここに遊びに来る場合は下田まで列車で移動した方が良いという学びを得ました。

さていい感じの砂浜ですが、何をもっていい感じなのか決めないと評価できないので、とりあえずこの記事においては「沖縄の砂浜のように白い砂」だといい感じだと思ってください。

熱海サンビーチや伊東オレンジビーチも悪くはなかったのですが白い砂浜は伊豆先端である南伊豆まで行かねば発見できませんでした。

西側に関しては今回未調査です。

弓ヶ浜

f:id:okamuuu:20170725094558j:plain

というわけで弓ヶ浜に到着しました。大体19時ぐらいだったかな?晩御飯を食べたいので宿泊所の人にどこがいいのか聞いたところ「バーベキューガーデン海の家 もき丸」が良さそうでした。「青木さざえ店」も良さげでしたが残念ながら夕方で閉店しているのでどちらにしろ「バーベキューガーデン海の家 もき丸」しか選択肢は無かったんですが。

バーベキューガーデン海の家 もき丸

食べた物と飲んだものは以下の通り。写真はシッタカとトコブシです。

f:id:okamuuu:20170725094621j:plain

  • シッタカ
  • トコブシ
  • ピザ
  • イカの船上干し
  • ビール2杯
  • 白ワインハーフ

この店は店主が漁師でもあるらしいので海産物はとても美味しかったです。なぜかピザも美味しいっていう。夕暮れ時のビーチを眺めながら飲むビールは最高すよねえ。

ただ蚊とアリが少し多かったので虫除けが欲しかったですね。あとウェットティッシュ。淑女と一緒に行かれる予定がある方は必ずご持参ください。

就寝

おやすみなさい

DAY2

f:id:okamuuu:20170725094726j:plain

というわけで翌朝8:00ぐらいから活動開始。昨日行けなかった青木さざえ店で朝ごはん。

弓ヶ浜の駐車場事情

今回は宿泊所の駐車場を利用したので我々は特に料金は発生していないのですが、弓ヶ浜の駐車場事情について報告します。

まず1回1500円必要です。かつ、駐車場スペースが限られています。砂浜近くの駐車場は8時から9時の時点で満車になっていました。

路地を少しはいるとおじいちゃんとおばあちゃんがいて一回1000円の駐車場を案内していました。このお二人は朝ごはんを食べに行くときはいらっしゃいましたが朝ごはんから戻るといなくなっていました。そして1000円の駐車場が満車になっていました。

どうやら一回1000円の駐車場のほうも8時から9時には満車になるようです。 弓が浜へ遊びに行く予定がある皆さまは駐車場がどのあたりにあるのか事前にチェックしたほうが良さそうです。

弓ヶ浜ではなく逢ヶ浜

今回我々はシュノーケリングするスポットを探すほうが優先度が高かったので砂浜ではなく岩場へ行きました。

結構綺麗で海藻もたくさん生えていたので穴場スポットを見つけたのかもしれません。

ちなみに他にもシュノーケリングしている人がいましたがほとんどの人がラッシュガードをつけていました。カインズホームスーパーで買った980円のゴーグルと海パンだけで来ていたのは我々だけでした。この日は曇りだったのものすごく寒かったです。

ヒリゾ浜の駐車場事情

さてヒリゾ浜へ移動したのですがそもそも橋渡しポイントへの駐車場が満杯です。11:30 ごろに到着しのたですが、スタッフから「12:30ぐらいになれば午前中に来たお客様帰るので入れ替わりで駐車場が空くんじゃないかなあ」という説明を受けたのでそのあたりで昼ごはんを食べる事にしました。

つかさ庵

北へ 6km ほど移動して蕎麦屋さんを発見。暖かい鴨南蛮を食べました。まあまあ美味しかったです。同伴したおじさんは蕎麦好きでどうして冷たい蕎麦じゃないんだ!?という顔をしましたが逢ヶ浜で体温を結構失った私にとってはなかなかのご馳走でした。

再びヒリゾ浜

f:id:okamuuu:20170725094756j:plain

無事車を止めて渡し船を利用します。渡し船は1日券1500円です。ヒリゾ浜(岩場)へは船で移動する必要があり、1日に何度も往復しています。実質は1往復しかしない人がほとんどだと思います。

そして渡し船に。ダイビングスーツに身をまとった本格的な人たちがいる中、980円のゴーグルと海パンでやってきたおじさん2人が乗り込みます。

そして案の定海水が冷たい。しかし入らないと何しに来たのか分からない。というわけで頑張って水中へ。逢ヶ浜とは比べ物にならないほどの魚に遭遇。快晴だったらすごく幻想的な風景なんだろうなと思いました。

私はこの日、私は生まれて初めて Go Pro を買いたいと思いました。そして海を堪能して再び渡し船で戻ります。で戻って気づいたのですがウェットスーツとかレンタルしていました...

浄蓮の滝

f:id:okamuuu:20170725094819j:plain

さて無事に任務完了したので熱海へ向かって出発します。途中で河津七滝ループ橋を体験。昔の人は天城越えするのどんだけ大変だったんだろうと思いました。

で下田街道を通るのでしたら道の駅、浄蓮の滝はおすすめです。鮎の塩焼き美味しそうでしたがそこまでお腹空いてなかったので見送りしました。

f:id:okamuuu:20170725094921j:plain

ちなみにわさびのアイスクリームはちょっと微妙かな...ここはわさび作っててわさび田がありました。水綺麗。

そういえば伊豆ではテングサがたくさん取れるらしく、テングサでつくられたところてんは名物のようです。ところてんはおいしかったので機会があればぜひ食べてみてください。

ハムハウス Grimm

そして帰宅途中になんだか美味しそうな自家製ソーセージを作っているお店を発見。もう1人のおじさんが「最近ソーセージにはまっててこれを見逃す事ができない」とおっしゃったので立ち寄りました。保冷する必要があるので私は購入しませんでしたので美味しかったか不明ですが後日ヒアリングして追記しておきます。

熱海着

無事熱海に着いたのですが一方通行の道が多くて熱海をぐるぐる。ガソリンスタンドまでなかなかたどり着けないっていう。

でガソリンを満タンにしたのですが今回の旅は 300km 近く走ったのですが 12.04L しか消費していませんでした。

車種はなんだっけな...

私は車を所有していないのでどれぐらいすごいのか分かってませんがなんかすごいらしいです。

そして何故か人多すぎの熱海。知らない間に熱海が今盛り上がっているのか!?と思ったら熱海海上花火大会でした。

花火を見ながら酒を飲むなかなかの好機でしたがこれ以上体力を消耗すると明日の仕事に影響するだろうという事で見送りました。というわけで解散。

品川着

というわけで品川に到着しました。ちなみに熱海から品川駅までの新幹線のチケットを購入すると 熱海->東京山手線内 みたいな料金になるので品川駅からJR山手線の駅でしたら切符を買わなくても大丈夫です。

旅慣れてる人は知っているんでしょうけど東京とか、大阪とかそういうルールがあるのできになる方はぜひ調べて見てください。

まとめ

というわけで今回の旅で学んだ事

  • 日頃からアクティブに活動し、情報を収集している人々との交流は大事。
  • えきねっとユーザーにはあらかじめなっておきましょう。
  • 運転手を仲間に加えておきましょう。
  • レンタカーは借りられるのか、列車の出発時間はいつなのか日頃から検索する力を養っておきましょう。
  • 伊豆半島は思ったより大きかった。熱海から下田まで車での移動は苦行なので最初から下田まで列車で移動したほうがよいでしょう。
  • 海に行くなら日差しを避ける用のテントが必要
  • 海の家でご飯食べるなら虫除けとウェットティッシュが必要
  • シュノーケリングするならゴーグル、シュノーケル、ラッシュガード、フィンもしくはアクアシューズが必要。浮き輪もあれば尚可。
  • シュノーケリングするなら GoPro を購入しよう
  • 海に行って着替えをするときは大きめのタオルがないと不便

Failed: Cannot create property '__creationTrace__' on string '__zone_symbol__optimizedZoneEventTask'

どうした?

Angular なアプリを開発していたのですが CirlceCI 上でいきなりテストが通らなくなった

あと TypeError: Cannot create property '__creationTrace__' on string '__zone_symbol__optimizedZoneEventTask' とか言われます。

どうする?

調査した過程で、下記の issue にたどり着いた

github.com

とりあえず zone.js を v0.8.13 から v0.8.12 にダウングレードしました。おしまい。

Can't bind to 'ngModel' since it isn't a known property of 'input'. ("">

もう何度も同じメッセージを目撃し、時間を無駄にしているのでメモ

src/app/app.module.ts に FormsModule を追加する

 import { BrowserModule } from '@angular/platform-browser';
 import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
 
 import { AppRoutingModule } from './app-routing.module';
 import { AppComponent } from './app.component';
@@ -10,7 +11,8 @@ import { AppComponent } from './app.component';
   ],
   imports: [
     BrowserModule,
-    AppRoutingModule
+    AppRoutingModule,
+    FormsModule
   ],
   providers: [],
   bootstrap: [AppComponent]

qs v6.5.0 以降からちょっと便利になったのでメモ

addQueryPrefix と ignoreQueryPrefix が使えるようになりました。

assert.equal(qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true }), '?a=b&c=d');
var prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true });
assert.deepEqual(prefixed, { a: 'b', c: 'd' });

chart.js v2.6.0 の tooltip を React.js でカスタマイズして使う

追記

そういえば tootlitp のデザインは下記URL から拝借しています。書き忘れていたので追記します。ちなみにこの CSS にドロップシャドウを追加したらシャレオツな感じになった気がします。

【5パターン】画像を使わず CSS3 のみで作れる吹き出しを作ってみた – Pure CSS3 Balloons | Stronghold Archive

あらすじ

Chart.js の tooltip をカスタマイズする必要があったので、その勉強した結果をメモしておきます。

どんなの?

こんなの

f:id:okamuuu:20170704222524p:plain

準備

react-storybook 上で演習します

create-react-app practice-react-chartjs && cd $_
getstorybook
npm run storybook

open http://localhost:6006 して以下の画面が表示されれば準備完了です

演習開始

chart.js をinstlall

npm install --save chart.js

シンプルな Bar Chart を作成します。

create src/components/bar-chart.js

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { Chart } from 'chart.js'

class BarChart extends Component {

  componentDidMount() {
    const ctx = this.node.getContext('2d')
    const chart = new Chart(ctx, {
      type: "bar",
      data: {
        labels: ["好き", "嫌い", "どちらでもない"],
        datasets: [{
          label: "りんご",
          data: [ 5, 1, 4]
        },
        {
          label: "なし",
          data: [ 8, 1, 1]
        },
        {
          label: "みかん",
          data: [ 2, 1, 7]
        }],
      },
      options: {
        scales: {
          yAxes: [{
            display: true,
            ticks: {
              beginAtZero: true,
              max: 10,
            },
          }],
        }
      }
    })
  }

  render() {
    return (
      <div>
        <canvas ref={(node) => this.node = node}></canvas>
      </div>
    )
  }
}

export default BarChart

edit stories/index.js

import React from 'react';
import { storiesOf, action, linkTo } from '@kadira/storybook';
import BarChart from '../src/components/bar-chart'

storiesOf('Welcome', module)
  .add('BarChart', () => (
    <BarChart />
  )); 

tooltip component を作成する

css in js にします。content に空文字を設定する時は "' '" のようにしましょう。

npm install glamor --save

create src/components/tooltip.js

import React, { Component } from 'react'
import { css } from 'glamor'

let rule = css({
  position: "relative",
  display: "inline-block",
  padding: "0 15px",
  width: "auto",
  minWidth: "115px",
  height: "40px",
  lineHeight: "34px",
  color: "#19283C",
  textAlign: "center",
  background: "#F6F6F6",
  border: "3px solid #19283C",
  boxShadow: "2px 1px 8px 0 rgba(0,0,0,0.3)",
  zIndex: 0,
  ":before": {
    content: "' '",
    position: "absolute",
    bottom: "-8px",
    left: "50%",
    marginLeft: "-9px",
    width: "0px",
    height: "0px",
    borderStyle: "solid",
    borderWidth: "9px 9px 0 9px",
    borderColor: "#F6F6F6 transparent transparent transparent",
    zIndex: 0
  },
  ":after": {
    content: "' '",
    position: "absolute",
    bottom: "-12px",
    left: "50%",
    marginLeft: "-10px",
    width: "0px",
    height: "0px",
    borderStyle: "solid",
    borderWidth: "10px 10px 0 10px",
    borderColor: "#19283C transparent transparent transparent",
    zIndex: -1
  }
})

class Tooltip extends Component {

  componentDidMount() {
  }

  render() {
    return (
      <div className={`${rule}`}>{this.props.children}</div>
    )
  }
}

export default Tooltip

storybook に追加する edit: story/index.js

import React from 'react';
import { storiesOf, action, linkTo } from '@kadira/storybook';
import BarChart from '../src/components/bar-chart'
import Tooltip from '../src/components/tooltip'

storiesOf('Welcome', module)
  .add('BarChart', () => (
    <BarChart />
  ))  
  .add('Tooltip', () => (
    <Tooltip>test</Tooltip>
  ));

Chart.js の tooltip option で挙動を確認

試しに Chart.js に以下のオプションを追加してマウスをグラフに hover させると tooltip のイベントが発生します。ここで取得した情報を先ほどの Tooltip に渡します。

+++ b/src/components/bar-chart.js
@@ -32,7 +32,17 @@ class BarChart extends Component {
               max: 10,
             },
           }],
-        }
+        },
+        tooltips: {
+          enabled: false,
+          mode: 'nearest',
+          position: 'nearest',
+          intersect: false,
+          custom: function(tooltip) {
+            console.log(this._chart, tooltip)
+          }
+        },
       }
     })

tooltip の表示、非表示については tooltip.opacity で判定できます。

tooltip の位置については tooltip.caretXthis.tooltip.caretY で相対的な位置がわかります。 これらと this._chart.canvas.getBoundingClientRect() を組み合わせることで計算することができます。

tooltip の表示位置を position: absolute にして以下の style を操作することで実現させます。

  • el.styleopacity
  • el.style.left
  • el.style.top

tooltip に表示する要素は tooltip.body[0].lines を参照すれば取得できます。

tooltip component をカスタマイズ

というわけで tooltip component に対して以下の props を渡せるようにします。

el.style.opacity el.style.left el.style.top text

動作確認をする際、 react-storybook には Knobs という便利な Addon があるのでこれを使います。が、使い方は割愛します。

edit src/components/tooltip.js

   render() {
+    const { opacity, top, left, children } = this.props;
     return (
-      <div className={`${rule}`}>{this.props.children}</div>
+      <div style={{position: "absolute", opacity, top, left}}>
+        <div className={`${tooltip}`}>{children}</div>
+      </div>
     )

位置情報を計算する

公式サイトに計算方法が載ってあるのでこの計算式を流用します。

http://www.chartjs.org/docs/latest/configuration/tooltip.html

例えば以下のようにします。chart.canvas.getBoundingClientRect() を実行すると canvas の位置がとれるのでそれを使用します。ただし、scroll するとずれるので注意。

正直ここの計算式はどれが正しいのかわかってないのですがたぶんこの計算式でまあまあ良い感じになると思います。

function customTooltip(canvas, tooltipModel) {
  if (tooltipModel.opacity === 0) {
    return {opacity: 0, left: 0, top: 0, text: ""} 
  }
  // const position = chart.canvas.getBoundingClientRect()
  // console.log(position.left, position.right)
  return {
    opacity: 1,
    // left: caret - tooltip の幅 / 2 + potion.left
    // top: caret - tooltip の高さ + potion.top
    left: tooltipModel.caretX - 151 / 2 + 8,
    top: tooltipModel.caretY - tooltipModel.height - 8,
    text: tooltipModel.body[0].lines.join("")
  }
}

あとは BarChart Compnent に onTooltipFire というイベントハンドラを仕込んで受け取った情報を Tooltip に渡せば良いです。

疲れてきたので後は github に上げておきます。興味がある方はご覧頂き、宜しければ⭐️でも付けてやってください

ソースコード

https://github.com/okamuuu/react-chart.js-example

storybook

https://okamuuu.github.io/react-chart.js-example/