プロクラシスト

今日の寄り道 明日の近道

コピペで(ほぼ)一発!jQueryでオシャレな地図ツールを作ったよ。


スポンサーリンク

こんにちは、ほけきよです!

私のブログにもいくつか旅行記事や都市の紹介記事があります。
それらを一括してはてなブログ上でもおしゃれな地図を表示させたい...!
そう思ってここ数日はずっとjQueryを使った地図作成をしてました。

作る上でのポイントは

  • おしゃれ感がある
  • ユーザーが使いやすい
  • 別ページに誘導できる

ということ。

まだまだ難はあれどある程度の水準まで作ることができたので、コードと一緒に使い方を紹介したいと思います。
また、コードをそのままコピペすると動くようになっていますので、ぜひお試しください。

世界地図






日本地図


コピペで一発!コードと使い方

全体の注意事項

またこちらのコードはgithubにもあげています

github.com

どうぞお使いください

そしてpull-requestお願いします!

世界地図編

コードをみる

  <!--map plugin-->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jvectormap/2.0.4/jquery-jvectormap.css" type="text/css" media="screen"/>
  <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
  <script src="http://jvectormap.com/js/jquery-jvectormap-2.0.3.min.js"></script>
  <script src="http://jvectormap.com/js/jquery-jvectormap-world-merc.js"></script>
  <!--for Japanesemap-->
  <script src="https://rawgit.com/hokekiyoo/jVectormapJP/master/jquery-jvectormap-jp-merc.js"></script>
  <script type="text/javascript" src="https://jqvmap.com/js/vmap/jquery.vmap.sampledata.js?v=1.5.0" charset="utf-8"></script>
  <center>
  <div id="world-map" style="width: 600px; height: 400px"></div>
  </center>


  <script>
    var sample_dataL = {};
    for( var tag in sample_data ){
      sample_dataL[tag.toUpperCase()] = sample_data[tag];
    }
    var pin_black = "https://cdn-ak.f.st-hatena.com/images/fotolife/i/imslotter/20170729/20170729233434.png";
    var pin_red   = "https://cdn-ak.f.st-hatena.com/images/fotolife/i/imslotter/20170729/20170729233449.png";
    var markers = [
      { latLng: [51.160523, 71.470356], country:"Kazakhstan", city: "Astana",
        img : "https://cdn-ak.f.st-hatena.com/images/fotolife/i/imslotter/20170116/20170116013149.png",
        title : "今年はカザフスタンが熱い!日本人だからこそ行くべき『超近未来都市』",
        page:true, url : "http://www.procrasist.com/entry/kazakhstan",
      },
      { latLng: [41.715138, 44.827096], country: "Georgia", city: "Tbilisi", 
        img : "https://cdn-ak.f.st-hatena.com/images/fotolife/i/imslotter/20170121/20170121204324.png",
        title : "【旅好き必見!!】個性的な建築物の宝庫!ジョージア(グルジア)の魅力",
        page:true, url : "http://www.procrasist.com/entry/georgia", },
      { latLng: [35.011636, 135.768029], country: "Japan", city: "Kyoto", 
        img : "https://cdn-ak.f.st-hatena.com/images/fotolife/i/imslotter/20170702/20170702111519.jpg",
        title : "京都の最強パワースポット『三千院』の雰囲気が最高だった",
        page:true, url : "http://www.procrasist.com/entry/3000-temple" },
    ];
    $( () => {
      var map = new jvm.Map({
        container: $("#world-map"),
        map: "world_merc",
        markers: markers,
        series: {
          regions: [{
            values: sample_dataL,
            scale: ["#c8eeff", "#0071a4"],
            normalizeFunction: "polynomial"
          }],
        },
        backgroundColor: "#ffffff",
        enableZoom: false,
        showTooltip: false,
        regionsSelectable: false,
        markersSelectable: true,
        hoverOpacity: 0.7,
        regionStyle: {
          selected: {
            fill: "#666666"
          }
        },
        markerStyle: {
          initial:{
            image:pin_black
          },
          hover:{
            image:pin_red
          }
        },
        onRegionSelected: () => {
          var xs = map.getSelectedRegions();
          console.log( xs.map( x => map.mapData.paths[x].name+" ("+x+")" ) );
        },
        onMarkerTipShow:(e, el, code) =>{
          if(markers[code].page){
            el.html("<div id='marker'>"+
                    "<span style='font-size:15px;font-weigh:bold;'>"+markers[code].title+"</span>"+
                    "<br>Country : "+markers[code].country+
                    "<br>City    : "+markers[code].city+
                    "<center><img width='80%', height='80%' src='"+markers[code].img +"'>"+
                    "</center></div>"+
                    "<style type='text/css'> div#marker{width:240px; height:100%; background-color: #222222;}"
            );
          }
          else{
            el.html("<div id='marker'>"+
                    "<span style='font-size:15px;font-weigh:bold;color:#666666'>"+markers[code].title+
                    "<br>Country : "+markers[code].country+
                    "<br>City    : "+markers[code].city+
                    "<center><img width='80%', height='80%' src='"+markers[code].img +"'>"+"</span>"+
                    "</center></div>"+
                    "<style type='text/css'> div#marker{width:240px; height:100%;}"
            );
          }
        },
        onMarkerClick: (e, code) => {
          if(markers[code].page){
            console.log(markers[code].url); 
            open(markers[code].url,"blank_")
          }
        }
      });
      console.log(map);
    });
  </script>  



このコードで修正するところは次の箇所です
自分が地図上に乗せたい場所の情報をどんどんと記入していきます.

  var markers = [
    { latLng: [51.160523, 71.470356], country:"Kazakhstan", city: "Astana",
      img : "https://cdn-ak.f.st-hatena.com/images/fotolife/i/imslotter/20170116/20170116013149.png",
      title : "今年はカザフスタンが熱い!日本人だからこそ行くべき『超近未来都市』",
      page:true, url : "http://www.procrasist.com/entry/kazakhstan",
    },
    ...
  ]

以下要素の説明です

  • latLng : その土地の緯度経度を示す。*1
  • country/city : 国名/都市名を表す
  • img : その場所のアイキャッチとなる画像のリンクを貼る
  • title : タイトルを記入する.記事なら記事タイトル
  • page : 記事リンクがあるかどうか.あればtrue/なければfalse
  • url : (記事リンクがあるときに)記事リンクを貼る


また
ピンの画像は私のはてなフォトライフから持っていってるので変えたい人はここをいじってくださいな

  var pin_black = "https://cdn-ak.f.st-hatena.com/images/fotolife/i/imslotter/20170729/20170729233434.png";
  var pin_red   = "https://cdn-ak.f.st-hatena.com/images/fotolife/i/imslotter/20170729/20170729233449.png";

日本地図編

コードをみる

  <!--map plugin-->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jvectormap/2.0.4/jquery-jvectormap.css" type="text/css" media="screen"/>
  <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
  <script src="http://jvectormap.com/js/jquery-jvectormap-2.0.3.min.js"></script>
  <!--for Japanesemap-->
  <script src="https://rawgit.com/hokekiyoo/jVectormapJP/master/jquery-jvectormap-jp-merc.js"></script>
  <center>
  <div id="jp-map" style="width: 600px; height: 350px;"></div>
  </center>
  <script>
    var pin_black = "https://cdn-ak.f.st-hatena.com/images/fotolife/i/imslotter/20170729/20170729233434.png";
    var pin_red   = "https://cdn-ak.f.st-hatena.com/images/fotolife/i/imslotter/20170729/20170729233449.png";
      var sample_dataJ = {"Hokkaido":54.2, "Kyoto":46.3, "Tokyo":35.1, "Okinawa":32.7, "Kanagawa":30.2, "Nara":28.7, "Osaka":24.1, "Nagano":24.0, "Ishikawa":23.3, "Fukuoka":21.4, "Nagasaki":20.0, "Shizuoka":17.6, "Aichi":17.2, "Miyagi":16.8, "Oita":16.5, "Hyogo":16.3, "Aomori":15.8, "Toyama":15.4, "Akita":14.9, "Chiba":14.4, "Kumamoto":14.2, "Kagoshima":14.2, "Hiroshima":14.0, "Miyazaki":13.4, "Ehime":13.1, "Mie":12.6, "Shimane":12.4, "Wakayama":12.0, "Kochi":11.9, "Yamanashi":11.7, "Okayama":11.4, "Yamaguchi":11.3, "Shiga":10.9, "Kagawa":10.8, "Niigata":10.5, "Iwate":10.3, "Yamagata":10.0, "Saga":9.4, "Fukushima":9.2, "Saitama":9.2, "Fukui":9.1, "Gifu":9.0, "Tottori":9.0, "Tokushima":9.0,"Gunma":8.5, "Tochigi":7.8, "Ibaraki":7.7};
    var markersJP = [ 
      { latLng: [35, 135], country: "Japan", city: "Kyoto", 
        img : "https://cdn-ak.f.st-hatena.com/images/fotolife/i/imslotter/20170702/20170702111519.jpg",
        title : "京都の最強パワースポット『三千院』の雰囲気が最高だった",
        page:true, url : "http://www.procrasist.com/entry/3000-temple" },
      { latLng: [35, 140], country: "Japan", city: "Ibaraki", 
        img : "https://cdn-ak.f.st-hatena.com/images/fotolife/i/imslotter/20170426/20170426044454.jpg",
        title : "美しすぎる青の絨毯、ひたち海浜公園の『ネモフィラ』",
        page:true, url : "http://www.procrasist.com/entry/hitachi-nemophila" },
      { latLng: [36.16, 136.5], country: "Japan", city: "Gifu", 
        img : "https://cdn-ak.f.st-hatena.com/images/fotolife/i/imslotter/20170406/20170406232850.jpg",
        title : "【旅と写真】魅惑の岐阜県物語 in 高山・白川郷",
        page:true, url : "http://www.procrasist.com/entry/gifu-1" },
      { latLng: [24.2, 123.5], country: "Japan", city: "Okinawa", 
        img : "https://lh3.googleusercontent.com/AMTniNf0dj3P1xss1J2zOH-fNtOAI6IefqNTUHQ5jpPKG6XpO_0ZXvlzTg9--3S5O1cECYqvsUYvWOQIXuPESHYKB31x4QFcEfoFivCigz5IVEfHeCpz5A065s8LHlh2Lon8sfgngFYVzAvfT0LI4WIn-dUi5iMJCvZQqmNrNITdeiJ10iO2GopmoxW9QgIfh_W4QtlEK-qn5FA1UJI0dFZKdJL7YH7PiUNAv8p2RfpXMMHv2M5NxD733bZLS8qACggux6npmBqMlByl21ZJpAxkNrqJanpfctey2cd4qe6vzOgVLscLSgkwl-cJR_xdkgQ7qJTKQb7VRm0NQ_hh-GLrqXqmbfJ4TaiqVIj7w67ZT5qubdGrX7_PMGXpquosm6mYL721eg9ydIu1AqVIe9H75tbwSXnBnxLhZjflKj8tOhDDC2ZqXTlUjA_lZesX00Sw4ZeERYFtPjyxWv3dAorJBytvdbL6qfdZUr1-3usRHg_cW83aHOphVApx7-o4dzidk0Yz1K5P9mgvu8Rdqt_zMop3tvv_yIWkT1lyLLhZdQgC67h4p2j84AymyE0bhqbeU-E2Bk_kHQDXhWKyDWD47Og8yNl_kO_D7fibaE77X2lg-iE9nVmL=w1690-h1126-no",
        title : "西表の海",
        page:false,
      },
    ];
    $( () => {
      var map2 = new jvm.Map({
        container: $('#jp-map'),
        map: 'jp_merc',
        onRegionTipShow: ( e, el, code ) => {
          el.html( el.html() );
          console.log(code);
        },
        backgroundColor: null,
        enableZoom: false,
        showTooltip: false,
        regionsSelectable: true,
        markersSelectable: true,

        hoverOpacity: 0.7,
        regionStyle: {
          selected: {
            fill: '#666666'
          }
        },
        series: {
          regions: [{
            values: sample_dataJ,
            scale: ["#c8eeff", "#0071a4"],
            normalizeFunction: "polynomial"
          }],
        },
        markerStyle: {
          initial:{
            image:pin_black
          },
          hover:{
            image:pin_red
          }
        },
        markers: markersJP,
        onRegionSelected: () => {
          var xs = map.getSelectedRegions();
          console.log( xs.map( x => map.mapData.paths[x].name+" ("+x+")" ) );
        },
        onMarkerTipShow:(e, el, code) =>{
          if(markersJP[code].page){
            el.html("<div id='marker'>"+
                    "<span style='font-size:15px;font-weigh:bold;'>"+markersJP[code].title+"</span>"+
                    "<br>Country : "+markersJP[code].country+
                    "<br>City    : "+markersJP[code].city+
                    "<center><img width='80%', height='80%' src='"+markersJP[code].img +"'>"+
                    "</center></div>"+
                    "<style type='text/css'> div#marker{width:240px; height:100%; background-color: #222222;}"
            );
          }
          else{
            el.html("<div id='marker'>"+
                    "<span style='font-size:15px;font-weigh:bold;color:#666666'>"+markersJP[code].title+
                    "<br>Country : "+markersJP[code].country+
                    "<br>City    : "+markersJP[code].city+
                    "<center><img width='80%', height='80%' src='"+markersJP[code].img +"'>"+"</span>"+
                    "</center></div>"+
                    "<style type='text/css'> div#marker{width:240px; height:100%;}"
            );
          }
        },
        onMarkerClick: (e, code) => {
          if(markersJP[code].page){
            console.log(markersJP[code].url); 
            open(markersJP[code].url,"blank_")
          }
        }
      });
    });
   </script>


日本地図編の場合もほとんど同じです.ただしcountryは必要ないので削除しました

見栄え

こんな感じです

  • ポインタを置いたピンが赤色になり先程設定した必要情報がポップアップ的に出てくるようになります
  • リンクがあるものは白色リンクのないものはグレーで説明文を書いています

ちなみに、この日本地図ですが、読者のid:Ysmr_Ryさんが実装してくれました!!
技術力が強い人、素晴らしい...!ありがたく使わせてもらいます~。


彼のgithub(GitHub - asSqr/jVectormapJP)の、jquery-jvectormap-jp-merc.jsが日本地図に当たる部分なので、
皆さんも是非使ってみてください!

注意点(TODO)

使いやすさのためにいくつかまだ改良しないといけないところもあります。
TODOということで今後の予定を書き記しておきます!

レスポンシブ対応

現在大きさを固定しての提供になっています
速度の兼ね合いもありますが
レスポンシブ対応にしてよしなな大きさで表示されるようにしたいです

スマホでの操作性向上

いかんせんスマホでポインタが触りづらい!とりあえず現在はデスクトップ推奨のマップになっています

ここが直れば良さそう!っていう目星はあるのですがまだ手をつけられていません
そのうちつけてgithubにあげます

そのときは記事の更新とtwitterのアナウンスをするので登録しておいてね!

まとめ


いかがでしたか?
(PCで見ると)割と使い勝手の良い地図ツールができたと思います

htmlを触っているだけなんではてな以外でもおそらく使えます

私自身地図を作るにあたってほとんど初めてjavascriptを勉強してたのですが
なかなか便利ですね!ややこしいけど使えるようになると幅が広がるなって感じです
今後もいろいろ作っていけたらなと思います

私の地図奮闘記は過去記事にもあるのでどうぞ

みなさんも旅の思い出をおしゃれなマップとともに保存しましょう!ではでは

*1:緯度経度の表示にはをこちらを使うととても便利

PROCRASIST