GIS奮闘記

現役GISエンジニアの技術紹介ブログ。主にPythonを使用。

スポンサーリンク

ArcGIS API for JavaScript で標高 API を使ってみよう

さて、本日も ArcGIS API for JavaScript について書いてみようと思います。標高 API は以下のエントリーで紹介しているのですが、Python と C# での呼び出しについてでした。今回は JavaScript を使って処理を書いてみようと思います。

www.gis-py.com

www.gis-py.com

www.gis-py.com

今回やろうとしていること

ArcGIS API for JavaScript を使用して、マップをクリックしたら標高を表示する、というような処理を書いてみようと思います。

今回使用するソース

前回のエントリーをベースに今回使用する処理を書き足そうと思います。

www.gis-py.com

前回の完成イメージです。

f:id:sanvarie:20191012150629p:plain

今回は以下のように「レイヤー一覧」ボタンの隣に「標高」ボタンを追加しようと思います。

f:id:sanvarie:20191019134913p:plain

環境

ArcGIS API for JavaScript 4.12
Chrome

マップクリック時に何か処理を走らせたい場合

View クラスの on() メソッドを使用します。

view.on("click", function(event){
  console.log(event.mapPoint);
});

標高API を使用してみる

以下のように実装してみました。リクエストを投げて受け取ったJSONをパースするだけなので、すごく簡単にできますね。

view.on("click", function (event) {  
  if(elevation==1){ 

    var data = { 'lon': event.mapPoint.longitude , 'lat': event.mapPoint.latitude  };
    var querystring = encodeQueryData(data);            
    var url = "http://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?" + querystring + "&outtype=JSON"

    // リクエストなげる
    var request = new XMLHttpRequest();
    request.open('GET', url);
    request.onreadystatechange = function () {
        var result = JSON.parse(request.responseText);
        view.popup.open({
          title: result.elevation,
          content : result.elevation,
          location: event.mapPoint 
        });
    };
    request.send(null);
  }
}); 

function encodeQueryData(data) {
  let ret = [];
  for (let d in data)
    ret.push(encodeURIComponent(d) + '=' + encodeURIComponent(data[d]));
  return ret.join('&');
}

if(elevation==1) の部分ですが、これは「標高」ボタンを押したら標高 API を使用するモードを切り替える処理を以下のように入れているためです。

// 標高ボタンを押して標高を取得できるモードを切り替える
var elevation = 0;
function getElevation(){
  if(elevation==1){
    elevation = 0;
  }else{
    elevation = 1;
  }
}    

HTMLの部分を除いてですが、今回追加した処理はこれだけです。

サンプルコード

全コードを以下に記載します。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
  <title>レイヤ一覧表示</title>
  <link rel="stylesheet" href="https://js.arcgis.com/4.12/esri/css/main.css">
  <script src="https://js.arcgis.com/4.12/"></script>
  <style>
    html,
    body,
    #viewDiv {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
    }
    #layerToggle {
      display: none;
      top: 80px;
      right: 20px;
      position: absolute;
      z-index: 99;
      background-color: white;
      border-radius: 8px;
      padding: 10px;
      opacity: 0.75;
    }
    #menu{
      padding: 0;
      margin: 0;
      height:42px; 
      background-color:#eeeeee;
      font-weight:bold;
    }
    #menu li {
      height:42px;
      margin-right: 2px;
      display: inline-block;
    }
    #button,#buttonElevation {
      left:0px;
      width:164px; 
      height:42px;
    }

  </style>
  <script>
    require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/VectorTileLayer",
        "esri/layers/FeatureLayer",
        "esri/layers/MapImageLayer",
        "dojo/on",
        "dojo/domReady!"
      ],
      function(
        Map, 
        MapView, 
        VectorTileLayer,
        FeatureLayer, 
        MapImageLayer,
        on
      ) {
        
        var map = new Map({
            basemap: "gray-vector"
        });

        var vectorTileLayer = new VectorTileLayer({
          url:
            "https://www.arcgis.com/sharing/rest/content/items/92c551c9f07b4147846aae273e822714/resources/styles/root.json",
            id:"vectorTile"
        });
        
        var mapImageLayer = new MapImageLayer({
            url: "https://content.esrij.com/arcgis/rest/services/Dosyasaigai/Dosyasaigai_Tile/MapServer",
            id:"mapImage"
        });

        var boundary = new FeatureLayer({
          url:"https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/JPN_Boundaries_ECM/FeatureServer",
          id:"boundary",
          opacity:0.5,
          minScale:1500000,
          maxScale:50000
        });
          
        map.add(vectorTileLayer);
        map.add(mapImageLayer);
        map.add(boundary);

        var view = new MapView({  
          container: "viewDiv",
          map: map,
          center: [139.740286, 35.678601],
          zoom: 15
        });

        var vectorTileToggle = document.getElementById("vectorTileLayer");
        var mapImageToggle = document.getElementById("mapImageLayer");
        var boundaryToggle = document.getElementById("boundary");

        on(vectorTileToggle, "change", function() {
          vectorTileLayer.visible = vectorTileToggle.checked;
        });
        on(mapImageToggle, "change", function() {
            mapImageLayer.visible = mapImageToggle.checked;
        });
        on(boundaryToggle, "change", function() {
          boundary.visible = boundaryToggle.checked;
        });

        view.on("click", function (event) {  
          if(elevation==1){ 

            var data = { 'lon': event.mapPoint.longitude , 'lat': event.mapPoint.latitude  };
            var querystring = encodeQueryData(data);            
            var url = "http://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?" + querystring + "&outtype=JSON"

            // リクエストなげる
            var request = new XMLHttpRequest();
            request.open('GET', url);
            request.onreadystatechange = function () {
                var result = JSON.parse(request.responseText);
                view.popup.open({
                  title: result.elevation,
                  content : result.elevation,
                  location: event.mapPoint 
                });
            };
            request.send(null);
          }
        }); 

        function encodeQueryData(data) {
          let ret = [];
          for (let d in data)
            ret.push(encodeURIComponent(d) + '=' + encodeURIComponent(data[d]));
          return ret.join('&');
        }
      }); 

      function displayLayerList(){
          var toggle = document.getElementById("layerToggle");
          if(toggle.style.display=="block"){
            // 非表示
            toggle.style.display ="none";
          }else{
            // 表示
            toggle.style.display ="block";
          }
        }

        // 標高ボタンを押して標高を取得できるモードを切り替える
        var elevation = 0;
        function getElevation(){
          if(elevation==1){
            elevation = 0;
          }else{
            elevation = 1;
          }
        }    
  </script>
</head>
<body>
    <ul id="menu">
      <li id="menu">
        <button id="button" type="button" onClick="displayLayerList()">レイヤー一覧</button>
      </li>
      <li>
        <button id="buttonElevation" type="button" onClick="getElevation()">標高</button>
      </li>
    </ul>
  <div id="viewDiv"></div>
  <div id="layerToggle">
    <input type="checkbox" id="vectorTileLayer" checked/>背景<br>
    <input type="checkbox" id="mapImageLayer" checked/>国土数値情報 災害情報<br>
    <input type="checkbox" id="boundary" checked />平成 27 年国勢調査 都道府県界<br>
  </div>
</body>
</html>

このようにマップをクリックすると標高を取得することができました。皇居周辺は大体標高が20数メートルということがわかりました!

f:id:sanvarie:20191019134517p:plain

今回は簡単にポップアップで標高を表示してみましたが、グラフィックか何かで標高を表示しても面白そうですね。その辺の実装も機会があれば紹介できればと思います。今回は以上です。