介紹IdentifyTask和IdentifyParameters的使用
好吧,我都要吐了。
接連三個例子都是類似的套路,使用某個查詢參數類的執行個體,結合對應的Task類,對傳回值進行取值、顯示。
這個例子是Identify識别,使用了TileLayer這種圖層,資料來自Server的MapServer。
結果示範
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLygTM0czM0ITMx0yM2gjNzcTM4EzNwQDM3EDMy0CN3AzN5ATMvwFNwcTMwIzLcRzNwcTOwEzLcd2bsJ2Lc12bj5ycn9Gbi52YuUTMwIzcldWYtl2Lc9CX6MHc0RHaiojIsJye.png)
戳不同的地方會有不同的識别結果。
我對TileLayer不是很了解,這一例僅針對有了解的同學,做一個IdentifyTask的解釋。
IdentifyTask/IdentifyParameter/IdentifyResult三個類
既然是一樣的套路,那麼先對這三個類有了解的話就會好說很多吧。
IdentifyTask
目前,IdentifyTask不能在SceneView和dynamic layers中使用。有關Identify是什麼,請【點我】
其執行成功的傳回值包括有一個IdentifyResult[]。
IdentifyParameters
本例中用到的屬性有:tolerance(Number)、mapExtent(Extent類)、layerId(Number[])、layerOption(String)、width(Number)、height(Number)、geometry(Geometry類);
分别意義是:螢幕像素與應被識别的幾何體之間的距離;地圖外框;需要被識别的圖層的ID号;哪些圖層需要被識别(預設頂層圖層),是個枚舉量;view的長寬。
IdentifyResult
本例中用到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肯定很有用,我在寫完第八章空間查詢後會對其進行一個比較全面的解釋。
第八章見!
附上這例子的全代碼:
<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标簽