Vue.jsで簡単地図マッピング - その2 マーカー表示編

さて、前回記事に引き続き、 Vue.jsで簡単地図マッピングです。

マーカーの地図上での表示

今度は、マーカーを表示してみましょう。

すでにここまでインストールしたモジュールでマーカーの表示はできますので、あとは タグやスクリプトを書いていけば…というところなのですが、一つ注意点があります。 どうやらこのLeafletには少しバグがあるらしくて、マーカーの画像がうまく表示されません。 そこで、

my-app-test/src/main.js

というファイルに、以下のものを追記します。

import L from 'leaflet';
delete L.Icon.Default.prototype._getIconUrl;

L.Icon.Default.mergeOptions({
  iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
  iconUrl: require('leaflet/dist/images/marker-icon.png'),
  shadowUrl: require('leaflet/dist/images/marker-shadow.png')
});

筆者の main.js は、全体としては以下のようになっています。

さて、マーカーを表示するための準備が整いましたので、次に、App.vueの方に戻りましょう。 <v-main></v-main>内に<template>~</template>を以下のように追記します。この部分が マーカーとそのポップアップを記述するためのタグ部分です。(ここでは、最後に残った「hello world」も消してしまいました。)

    <v-main>
      <v-btn @click="testfunc">Push</v-btn>
      <l-map ref="map" style="height: 600px;" :zoom="zoom" :center="center">
      <l-tile-layer :url="url"></l-tile-layer>
      <template>
        <l-marker v-for="(marker,index) in markerPlaces"
        :key="marker.id+index"
        :lat-lng="marker.latlon">
          <l-popup>
            <div class="primary--text">{{marker.name}}</div>
            <div v-for="(title, index) in marker.titles"
            :key="'tit-'+index">
              <a :href="title.uri" target="_blank">{{title.title}}</a>
            </div>
          </l-popup>  
        </l-marker>
      </template>          
    </l-map>
    <ul v-for="eachdata in testdata" :key="eachdata.id">
      <li>{{ eachdata.name }}</li>
    </ul>
    </v-main>

ここでも v-for が出てきていることに注目してください。この場合、マーカーのデータが複数あればマーカーを複数プロットできるようにしています。

次に、これに対応すべく、importの箇所も少し追記修正する必要があります。今回のApp.vueのimportの箇所は 全体としては以下のようになっていれば大丈夫です。

<script>
import 'leaflet/dist/leaflet.css'
import { latLng } from "leaflet";
import { LMap, LTileLayer, LMarker, LPopup } from "vue2-leaflet";

要するに、Leafletのコンポーネントをいくつか追加しています。

それから、これに対応するために、componentsの箇所にも追記します。全体としては以下のようになります。

export default {
  name: 'App',
  components: {
    LMap, LTileLayer,
    LMarker,
    LPopup,
  },

さらに、 data: () => ({ }) のところも追記する必要がありますね。 とりあえず、自動的に書くのはちょっとはやいので、以下のように、まずは手動でマーカー二つ分を書いてみます。

  data: () => ({
    url: "http://{s}.tile.osm.org/{z}/{x}/{y}.png",
    zoom: 8,
    center: [34, 137],
    testdata:[],
    markerPlaces:[
      {name:'ここ',latlon:latLng(35,135),
      titles:{title:'タイトル',
        uri:'https://www.google.com/'},id:1
      }, 
      {name:'あそこ',latlon:latLng(35,136),
      titles:{title:'タイトル2',
        uri:'https://www.google.com/'},id:2
      }
    ],
  }),

これは、今回の、<template>内に書き込んだ<l-marker v-for="(marker,index) in markerPlaces" 以下の箇所に対応したものです。 このようにしてdata: () => ({ のところにデータを書き込んでおくと、Web頁読み込み時に表示してくれます。

というわけで、うまくいっていると、以下のようにマーカーが2カ所表示されたマップが表示されるはずです。

マーカーの複数表示

ここまでくればもう大丈夫、という人も多いと思いますが、念のためもう少しだけやっておきましょう。 Pushを押すと別の箇所にマーカーをいくつか表示してくれるものを作ってみます。

これはもう、testfunc関数を書き換えてやってしまいましょう。以下のように書けばOKです。 西から東へ1度ずつずらして5つのマーカーを表示させるように、 test.markerPlacesに値を 入れていく処理です。

なお、現在のマーカーの数もtest.markerPlacesの要素数を数えれば確認できますが、 今回は、最初に2つのマーカーを表示していますし、繰り返し処理のときは5つ表示しますので、 if (this.markerPlaces.length < 3){という風に、3未満かどうか、で判定しています。

      if (this.markerPlaces.length < 3){
        let datalist = []
        let datatext = {}
        let titdict = {}
        let lon = 134
        for (let n=0;n<5;n++){
          datatext['id'] = n
          datatext['name'] = '名前:'+n
          datatext['latlon'] = latLng(35,lon+n)
          titdict = {}
          titdict['title'] = 'タイトル'+n
          titdict['uri'] = 'https://www.google.com/'
          datatext['titles'] = []
          datatext['titles'].push(titdict)
          datalist.push(datatext)
          datatext = {}
        }
        this.markerPlaces = datalist
      }
      else{
        this.markerPlaces = []
      }

これがうまくいくと、以下のように、Pushボタンを押した時に東西に5つのマーカーが並ぶことになります。 マーカーをクリックするとポップアップが表示されることも確認できますね。また、 グーグルへのリンクも表示されているはずです。

というような感じで、地図上に複数のマーカーをプロットできました。 あとは、データを増やしたければ、外部のJSONデータを うまく取り込むなどしていただくとよいのですが、それもまたもう少ししたらご紹介しましょう。

公開するために:静的なファイル群に変換

最後に、このようにして作ったものを、HTML/Javascript/CSSファイルとして公開できる形にしてみましょう。

ここまで、 $ npm run serve というコマンドを打って以下のような状態になっている ウインドウがあるはずです。

このウインドウを、 Ctrl-c で抜けて、コマンドプロンプトに戻ってから、

$ npm run build

としてください。そうしますと、これも少し時間がかかりますが、処理が終わると、 このディレクトリに 「 dist 」というフォルダができていて、その中に index.html や、いくつかのディレクトリができているはずです。この dist の中にあるファイルを すべてまとめてサーバにアップロードすると、それが使えるようになります。

それだけでなく、これは面白いことに、サーバを立ち上げなくても、 パソコン上の単なるHTMLファイルとしても動作してくれます。エクスプローラーで この dist フォルダの中にある index.html をWebブラウザで開いてみてください。 そうすると、先ほどと同じように開いて、Pushボタンを押すと同じように 5つのマーカーが表示されるはずです。Vue.jsで書く場合、基本的に クライアント側(パソコン側)のJavascriptしか使わないので、このように、 パソコン単体で動くことを利用して、パソコン用アプリケーションを 作ることも可能です。

ここまで、原理的な解説はほとんどせずに進んできてしまいましたが、 Vue.jsの公式サイトやあちこちのブログなどで Vue.jsの解説は書いてありますので ここは筆者が敢えて書くまでもないと思います。Webで色々見ていただければと思います。 (ではなぜ、ここまで、どこにでも書いてありそうなことをわざわざ書いている のかと言われそうですが、実は、ここまで一貫して書いてある良い記事になかなか 巡り会えず、あちこちの記事や公式サイトの記述を参照しながらなんとか 書くことができたので、この手のことをやってみたい方々が同じ苦労(かなりムダが多いので)を しなくて済むように、その経験をまとめているのがこの記事になります。)