ReagentでLeafletを試す

こんにちは。analysisチームの河野です。
趣味的な記事が続いたので、今回は業務に関係したことを書きます。

弊社は位置情報を利用したWebサービスを提供しているので、地図ライブラリは避けては通れないものなのですが、私自身はこの分野にものすごく疎いので、個人的な勉強を兼ねて、Leafletを試してみました。業務ではおそらくGoogle Maps APIを使うので、直接的には役に立たないかと思いますが。

Leafletとは

公式ページ: https://leafletjs.com/
詳細は公式ページを見てください。 ざっくり言うと、オープンソースの地図ライブラリです。wikipediaによると、「Leafletを使うと、GISの知識のない開発者でも容易にタイルベースのWeb地図を表示できる。」とのことですが、まさにその通りでした。

今回作ったもの

リポジトリこれです。
Reactも試してみたかったし、Clojureも使いたかったので、Reagentを使いました。 ちなみに、弊社というかanalysisチームのフロントエンドはVueとTypeScriptを使用しております。

解説

ReactとReagentについてはReagentのチュートリアルを見れば雰囲気は掴めます。
私自身、Reactを触るのは初めてでしたが何となく雰囲気は伝わりました。
またReactではLeafletを扱いやすくするReact-Leafletというライブラリがあるので、これを使います。
React界隈はライブラリが色々あって便利そうです。

今回はReact-Leafletの公式ページのトップにある、単にマップを表示するだけのことをしました。

import React from 'react'
import { render } from 'react-dom'
import { Map, Marker, Popup, TileLayer } from 'react-leaflet'

const position = [51.505, -0.09]
const map = (
  <Map center={position} zoom={13}>
    <TileLayer
      url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      attribution="&copy; <a href=&quot;http://osm.org/copyright&quot;>OpenStreetMap</a> contributors"
    />
    <Marker position={position}>
      <Popup>A pretty CSS3 popup.<br />Easily customizable.</Popup>
    </Marker>
  </Map>
)

render(map, document.getElementById('map-container'))

Reagentで書くとこんな感じになります
positionは弊社のお世話になっている東急番町ビルの緯度経度を指定しています。

;; src/leaflet_tutorial/core.cljs

(ns leaflet-tutorial.core
  (:require [reagent.core :as r]
            [react-leaflet :refer [Map TileLayer Marker Popup]]))

(def position [35.689236 139.735744])

;; -------------------------
;; Views
(defn leaflet-map
  []
  [:> Map {:center position :zoom 16}
   [:> TileLayer {:url "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                    :attribution "&copy; <a href=&quot;http://osm.org/copyright&quot;>OpenStreetMap</a> contributors"}]
   [:> Marker {:position position}
    [:> Popup "A pretty CSS3 popup.<br />Easily customizable." ]]])



;; -------------------------
;; Initialize app

(defn mount-root
  []
  (r/render [leaflet-map] (.getElementById js/document "app")))

(defn init!
  []
  (mount-root))

ただ、これだけでは地図が崩れるのでまだ手入れが必要です。
LeafletのスタイルをCDNから取得するようにします。

<!-- public/index.html -->

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta content="width=device-width, initial-scale=1" name="viewport">
    <link href="/css/site.css" rel="stylesheet" type="text/css">
    <!--追加 ここから-->
    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet/1.4.0/leaflet.css" />
    <!--追加 ここまで-->
  </head>
  <body>
    <div id="app">
      <h3>ClojureScript has not been compiled!</h3>
      <p>please run <b>lein figwheel</b> in order to start the compiler</p>
    </div>
    <script src="/js/app.js" type="text/javascript"></script>
  </body>
</html>

CSSにも手を加え、Leafletの描画領域を指定します。
.leaflet-containerheight100%にすると、地図が表示されないので注意してください。

/* public/css/site.css */

body {
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%;
}

#app {
  width: inherit;
  height: inherit;
}

.leaflet-container {
  width: inherit;
  height: 600px;
  margin: 10px;
}

これでlein figwheelすると、下記のような地図が表示されます。
f:id:t-kono0912:20190329124935p:plain

まとめ

Leafletを使うと、本当に簡単に地図の表示ができます。
しかし地図表示はまだ序の口で、ヒートマップやコロプレスマップ等を表示できないと分析ツールとしては使えないので、今度はそのへんのことを試してみたいです。

コネクトムでは地図ライブラリを使用したアプリケーションを一緒に作るエンジニアを募集しています。
https://open.talentio.com/1/c/connectom/requisitions/detail/6956