天天看點

ArcGIS API for JavaScript 4.2學習筆記[24] 【IdentifyTask類】的使用(結合IdentifyParameters類)(第七章完結)

介紹IdentifyTask和IdentifyParameters的使用

好吧,我都要吐了。

接連三個例子都是類似的套路,使用某個查詢參數類的執行個體,結合對應的Task類,對傳回值進行取值、顯示。

這個例子是Identify識别,使用了TileLayer這種圖層,資料來自Server的MapServer。

 結果示範

ArcGIS API for JavaScript 4.2學習筆記[24] 【IdentifyTask類】的使用(結合IdentifyParameters類)(第七章完結)
ArcGIS API for JavaScript 4.2學習筆記[24] 【IdentifyTask類】的使用(結合IdentifyParameters類)(第七章完結)

戳不同的地方會有不同的識别結果。

我對TileLayer不是很了解,這一例僅針對有了解的同學,做一個IdentifyTask的解釋。

 IdentifyTask/IdentifyParameter/IdentifyResult三個類

既然是一樣的套路,那麼先對這三個類有了解的話就會好說很多吧。

ArcGIS API for JavaScript 4.2學習筆記[24] 【IdentifyTask類】的使用(結合IdentifyParameters類)(第七章完結)

IdentifyTask

ArcGIS API for JavaScript 4.2學習筆記[24] 【IdentifyTask類】的使用(結合IdentifyParameters類)(第七章完結)

 目前,IdentifyTask不能在SceneView和dynamic layers中使用。有關Identify是什麼,請【點我】

 其執行成功的傳回值包括有一個IdentifyResult[]。

IdentifyParameters

ArcGIS API for JavaScript 4.2學習筆記[24] 【IdentifyTask類】的使用(結合IdentifyParameters類)(第七章完結)

 本例中用到的屬性有:tolerance(Number)、mapExtent(Extent類)、layerId(Number[])、layerOption(String)、width(Number)、height(Number)、geometry(Geometry類);

分别意義是:螢幕像素與應被識别的幾何體之間的距離;地圖外框;需要被識别的圖層的ID号;哪些圖層需要被識别(預設頂層圖層),是個枚舉量;view的長寬。

IdentifyResult

ArcGIS API for JavaScript 4.2學習筆記[24] 【IdentifyTask類】的使用(結合IdentifyParameters類)(第七章完結)

本例中用到IdentifyResult的屬性有:

layerName(String類)、feature(Geometry類)

後者是識别得到的幾何體,前者是包括後者的圖層的圖層名。

給出引用

require([
  "esri/Map",
  "esri/views/MapView",
  "esri/layers/TileLayer",
  "esri/tasks/IdentifyTask",
  "esri/tasks/support/IdentifyParameters",
  "dojo/_base/array",
  "dojo/on",
  "dojo/dom",
  "dojo/domReady!"
  ], 
  function(
    Map, MapView, TileLayer,
    IdentifyTask, IdentifyParameters,
    arrayUtils, on, dom
  )
}      

不解釋,和前兩篇類似。

函數參數骨架

function(Map, MapView, TileLayer, IdentifyTask, IdentifyParameters, arrayUtils, on, dom){

    var identifyTask, params;
    var soilURL = "https://services.arcgisonline.com/arcgis/rest/services/Specialty/Soil_Survey_Map/MapServer";      
var parcelsLyr = new TileLayer({...});
    var map = new Map({...});
        map.add(parcelsLyr);

    var view = new MapView({...});
    view.then(function(){...});

    //每次點選地圖時,就會處理一次的方法體
    function executeIdentifyTask(event){...}
}      

看起來也不是很複雜的樣子,嗯,時間不早了,先吃個晚飯,晚上回來繼續寫完第七章。

好的我吃完了,咱們繼續學習Identify這個例子。

首先是根據soilURL這個MapServer位址生成一個TileLayer,名為parcelsLyr,把它添加到執行個體化的Map中。

在MapView對象建立完成後,緊接着一個異步操作,下面就對MapView對象的回調函數進行解釋:

view.then(function() {
  on(view, "click", executeIdentifyTask);

  identifyTask = new IdentifyTask(soilURL);
  
  params = new IdentifyParameters();
  params.tolerance = 3;
  params.layerIds = [0, 1, 2];
  params.layerOption = "top";
  params.width = view.width;
  params.height = view.height;
});      

每當點選view的時候,觸發click事件executeIdentifyTask()。

然後就執行個體化一個IdentifyTask對象和一個IdentifyParameters對象,并對IdentifyParameters對象指派(屬性)。

于是這個例子最大頭的executeIdentifyTask()方法體就是核心了,先把它骨架化:

function executeIdentifyTask(event) {
  params.geometry = event.mapPoint;
  params.mapExtent = view.extent;
  dom.byId("viewDiv").style.cursor = "wait";

  identifyTask.execute(params)
  .then(function(response) {..這裡很長..})
  .then(showPopup);

  function showPopup(response){...}
}      

首先呢,擷取一些必要的參數,傳遞給IdentifyParameters(geometry屬性和mapExtent屬性)

然後執行IdentifyTask的execute()方法,這個方法有兩個異步操作,第一個異步操作的回調函數非常的長,還得繼續往下拆。

第二個回調函數待第一個回調函數完成後,顯示一個彈窗。

那麼【第一個回調函數】繼續拆解如下:

.then(function(response) {

  var results = response.results;

  return arrayUtils.map(results, function(result) {

    var feature = result.feature;
    var layerName = result.layerName;

    feature.attributes.layerName = layerName;
    if (layerName === 'Soil Survey Geographic') {
      feature.popupTemplate = {...};
    }
    else if (layerName === 'State Soil Geographic') {
      feature.popupTemplate = {...};
    }
    else if (layerName === 'Global Soil Regions') {
      feature.popupTemplate = {...};
    }
    return feature;
  });
})      

從response中擷取results屬性,該屬性為Object數組,裝箱為IdentifyResult類型的數組。(同上例)

緊接着傳回arrayUtils.map方法周遊results(IdentifyResult數組)得到的feature集合(Geometry類型)。

arrayUtils.map()方法周遊得到的是Geometry數組。

這個map()方法裡做了什麼呢?

首先,擷取IdentifyResult數組其中的IdentifyResult元素中的一個屬性——feature(Graphic類型),然後對不同的IdentifyResult對象的LayerName,設定feature不同的彈窗模闆。

————是不是很亂?

1. 周遊IdentifyResult[]中的每一個IdentifyResult;//别問我IdentifyResult[]怎麼來的,從response中來的。見上一篇部落格。

2. 對于每一個IdentifyResult,它有兩個屬性:feature(Graphic類型)和layerName(String類型);

3. 對于每一個IdentifyResult,如果layerName不同,那麼對應的feature的彈窗資訊格式(即popupTemplate)肯定不同;

4. 三個分支,對不同layerName的IdentifyResult,其feature就設定不同的popupTemplate;

5. 傳回此IdentifyResult的feature。

這一層回調函數就算OK了。因為feature是Graphic類型的,是以map傳回的就是Graphic[]類型的。

題外話,其實ESRI這樣寫很繞,雖然充分利用了JS的靈活和強大,但是代碼解讀起來就非常困難,函數能作為變量到處嵌套。

【第二個回調函數】

.then(showPopup);

function showPopup(response) {
  if (response.length > 0) {
    view.popup.open({
      features: response,
      location: event.mapPoint
    });
  }
  dom.byId("viewDiv").style.cursor = "auto";
}      

這回終于把回調函數寫出來了。

第二層回調函數的response參數是什麼呢?

可以看到,把response賦給了popup的features屬性了,可知response是Graphic[]類型的,這與上一個then傳回的值一緻。

這樣,就能利用第一個回調函數中設定好的popupTemplate進行不同格式的彈窗了。

關于第一個回調函數的彈窗popupTemplate不作詳細解釋了,因為這已經夠繞了。我在文末給出整個js代碼以供需要的同學參考。

總結一下

本例,仍然是對某某Result中的Graphic或者Geometry的屬性進行讀取或者操作。

和上兩篇是類似的,空間查詢的重點就是某某Task和某某Parameters和某某Result的交叉使用:

某某Task.execute(某某Parameters)

.then(回調函數處理某某Result)

.then(..)....

至于怎麼處理這個Result中的feature,官方的例子寫的很明确了,但是值類型就很隐晦。

因為JS的弱類型性,導緻這些值類型十分模糊,是以繞、暈也是正常的,我已經盡我所能把每個關鍵的地方的值類型進行解釋和說明了,希望大家能看懂我的胡言亂語。

好了,第七章空間查詢的内容并不是很多,這幾個Task肯定很有用,我在寫完第八章空間查詢後會對其進行一個比較全面的解釋。

第八章見!

附上這例子的全代碼:

ArcGIS API for JavaScript 4.2學習筆記[24] 【IdentifyTask類】的使用(結合IdentifyParameters類)(第七章完結)
ArcGIS API for JavaScript 4.2學習筆記[24] 【IdentifyTask類】的使用(結合IdentifyParameters類)(第七章完結)
<script>
    require([
      "esri/Map",
      "esri/views/MapView",
      "esri/layers/TileLayer",
      "esri/tasks/IdentifyTask",
      "esri/tasks/support/IdentifyParameters",
      "dojo/_base/array",
      "dojo/on",
      "dojo/dom",
      "dojo/domReady!"
    ], function(
      Map, MapView, TileLayer,
      IdentifyTask, IdentifyParameters,
      arrayUtils, on, dom
    ) {

      var identifyTask, params;

      // URL to the map service where the identify will be performed
      var soilURL =
        "https://services.arcgisonline.com/arcgis/rest/services/Specialty/Soil_Survey_Map/MapServer";

      // Add the map service as a TileLayer for fast rendering
      // Tile layers are composed of non-interactive images. For that reason we'll
      // use IdentifyTask to query the service to add interactivity to the app
      var parcelsLyr = new TileLayer({
        url: soilURL,
        opacity: 0.85
      });

      var map = new Map({
        basemap: "osm"
      });
      map.add(parcelsLyr);

      var view = new MapView({
        map: map,
        container: "viewDiv",
        center: [-120.174, 47.255],
        zoom: 7
      });

      view.then(function() {
        // executeIdentifyTask() is called each time the view is clicked
        on(view, "click", executeIdentifyTask);

        // Create identify task for the specified map service
        identifyTask = new IdentifyTask(soilURL);

        // Set the parameters for the Identify
        params = new IdentifyParameters();
        params.tolerance = 3;
        params.layerIds = [0, 1, 2];
        params.layerOption = "top";
        params.width = view.width;
        params.height = view.height;
      });

      // Executes each time the view is clicked
      function executeIdentifyTask(event) {
        // Set the geometry to the location of the view click
        params.geometry = event.mapPoint;
        params.mapExtent = view.extent;
        dom.byId("viewDiv").style.cursor = "wait";

        // This function returns a promise that resolves to an array of features
        // A custom popupTemplate is set for each feature based on the layer it
        // originates from
        identifyTask.execute(params).then(function(response) {

          var results = response.results;

          return arrayUtils.map(results, function(result) {

            var feature = result.feature;
            var layerName = result.layerName;

            feature.attributes.layerName = layerName;
            if (layerName === 'Soil Survey Geographic') {
              feature.popupTemplate = { // autocasts as new PopupTemplate()
                title: "{Map Unit Name}",
                content: "<b>Dominant order:</b> {Dominant Order} ({Dom. Cond. Order %}%)" +
                  "<br><b>Dominant sub-order:</b> {Dominant Sub-Order} ({Dom. Cond. Suborder %}%)" +
                  "<br><b>Dominant Drainage Class:</b> {Dom. Cond. Drainage Class} ({Dom. Cond. Drainage Class %}%)" +
                  "<br><b>Farmland Class:</b> {Farmland Class}"
              };
            }
            else if (layerName === 'State Soil Geographic') {
              feature.popupTemplate = { // autocasts as new PopupTemplate()
                title: "{Map Unit Name}",
                content: "<b>Dominant order:</b> {Dominant Order} ({Dominant %}%)" +
                  "<br><b>Dominant sub-order:</b> {Dominant Sub-Order} ({Dominant Sub-Order %}%)"
              };
            }
            else if (layerName === 'Global Soil Regions') {
              feature.popupTemplate = { // autocasts as new PopupTemplate()
                title: layerName,
                content: "<b>Dominant order:</b> {Dominant Order}" +
                  "<br><b>Dominant sub-order:</b> {Dominant Sub-Order}"
              };
            }
            return feature;
          });
        }).then(showPopup); // Send the array of features to showPopup()

        // Shows the results of the Identify in a popup once the promise is resolved
        function showPopup(response) {
          if (response.length > 0) {
            view.popup.open({
              features: response,
              location: event.mapPoint
            });
          }
          dom.byId("viewDiv").style.cursor = "auto";
        }
      }
    });
  </script>      

script标簽

繼續閱讀