はじめに
Elm+Leafletをしようとした場合、下記のリポジトリのようにWeb-componentsとして操作する、という手があります。
https://github.com/cbenz/elm-leaflet-maps
このやり方だとElmコードだけで完結するという利点がありますが、例えば「マーカーを表示→それを消して別のマーカーを出す」などの操作をすると、期待した動きにならないことがあります。Leaflet の全機能を使うためには、portsを使ってJavaScriptでの操作が必要なようです。
私はwebpackをちゃんと理解しているわけではないので、これが最適かどうかはわからないですが、ひとまずworkaroundのメモとして書きます。
前提
Elmアプリのプロジェクトはcreate-elm-appで作成するものとします。通常なら「elm-app start」でコーディングし始めることも多いでしょうが、npmでLeafletをインストールするため、create-elm-appしたらすぐに「elm-app eject」しておきます。Leafletはnpmでインストールするのが一番手間が小さいかと思いますが、他の手段でもElmでの利用は可能です(bowerあるいは手動でのダウンロードなど)。
Leafletのインストール
上述した「elm-app eject」が済んでいると、packages.jsonが既にあるはずなので、コマンドラインで下記を実行します。
$ npm install leaflet --save
npmでインストールされたleafletを読み込むために、index.jsに下記を追記します。こうすることで、index.jsにて「L.map()」等のメソッドが利用できるようになります。
import '../node_modules/leaflet/dist/leaflet.css';
import '../node_modules/leaflet/dist/leaflet.js';
Leafletの使い方
ここまで済めば、LeafletはJavaScriptとして操作することになるので、Elmとして注意する点はほとんどありません。
Mapの初期化はこんな感じになるでしょう(Leaflet関連の部分だけ記載)。修正:コメントで「Leafletの操作はDOMができてから実行するのが安全」という話をいただきましたので、反映させました。(参考:[Elm] DOM更新後にJSコードを実行する)
var mymap;
app.ports.initMap.subscribe(function(args) {
requestAnimationFrame(function () {
var lat = args[0];
var lng = args[1];
var mag = args[2];
mymap = L.map("mymap").setView([lat, lng], mag);
L.tileLayer(
'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
{
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a>',
maxZoom: 18
}
).addTo(mymap);
});
});
port initMap : (Float, Float, Int) -> Cmd msg
init : ( Model, Cmd Msg )
init = ( {}, initMap (24.20578, 124.08943, 9) )
view : Html msg
view = div [id "mymap"] []
注意点
マップにマーカーを出す歳に、カスタムアイコンを画像ファイルで指定することもあるでしょう。その時に、elm-package.jsonでproxy機能を使っている場合、画像ファイルの読み込みがこのproxyに流れてしまいます。理由はよくわかっていません。これは、もちろんdev環境のみの話で、prod-buildの際は関係ありません。
私はたまたま逃げ道がありましたが、proxyの設定によってはちょっと面倒なことになるかもしれません。