這個就頗有插值分析的樣子了。也可以說是密度分析。做出來就是一個熱力地圖的樣子。
比如,人口密度,降雨分布等。這都可以由這個例子做出來類似的。
由於上一篇已經介紹過Geoprocessor類和ParameterValue類了,所以這節就略去這些內容。想知道的同學可以點擊這里,看上一篇相關內容。
與上一節不同的是,使用的不是execute()方法了,而是submitJob()方法,這是一個異步操作方法。盡管他們返回的類型是類似的。
官方給的解釋很簡潔明了,有了前幾個的基礎幾乎可以瞬間抓住重點,如submitJob的參數的獲取,對熱力圖結果如何獲取和處理等,自行查詢API即可。
我這篇博客則是對這個例子進行重點全解析。如果是老鳥,請直接看:How it works
看看結果


給定一個時間范圍,就能查詢該地區報警的頻率。這里使用了圖例這個widget,對其有讀寫操作。圖中默認的時間按下紅色按鈕后,就可以看到如圖的結果(3-5s)。
最中央紅色區域是報警最頻繁的區域,點狀符號代表報警的時間(星期幾)。
據說這個例子有點長,加油。
給出引用
require([ "esri/Map", "esri/views/MapView", "esri/tasks/Geoprocessor", "esri/widgets/Legend", "esri/widgets/Spinner", "esri/layers/support/ImageParameters", "dijit/form/DateTextBox", "dojo/dom", "dojo/dom-construct", "dojo/on", "dojo/date/locale", "dojo/parser", "dijit/registry", "dojo/domReady!" ], function(Map, MapView, Geoprocessor, Legend, Spinner, ImageParameters, DateTextBox, dom, domConstruct, on, locale, parser, registry) { ... } );
dijit這個東西是第三方控件(貌似),看DateTextBox就知道了。AJS4.x除了dojo也有用dijit(不明白為啥名字那么奇怪)
三個新鮮的玩意兒:Legend、Spinner和ImageParameters。
函數骨架
function(...){ parser.parse();//不知道干啥用的 on(dom.byId("hotspotButton"), "click", findHotspot); var map = new Map({...}); var view = new MapView({...}); //實例化GP var gpUrl = ".../GPServer/XXX";//省略,但是還是GPServer var gp = new Geoprocessor(gpUrl); gp.outSpatialReference = {...} //圖例 var legend = new Legend({...}); spinner = new Spinner({...}); domConstruct.place(spinner.domNode, view.root); //數據處理的重點部分,也是官方How it works主要涉及的部分 function findHotspot(){...} function buildDefinitionQuery(){...} function cleanup(){...} function drawResultData(result){...} //非重點 function progTest(value){...} function errBack(err){...} }
按照官方的套路來,會更容易懂。那么久直接從findHotspot()、buildDefinitionQuery()、cleanup()、drawResultData(result)這四個方法說起吧。
How it works
允許我模仿一回官方的標題~
findHotspot():分析按鈕的click事件,設置gp.submitJob()的參數對象params,並執行分析;在這里,使用了異步操作分析,終於看到了完整的then寫法。
buildDefinitionQuery():gp.submitJob()的參數對象的生成方法,該方法返回了一個Object對象,供submitJob()使用。
cleanup():遍歷map中的layer,如果發現名字全等於"HotspotLayer",移除。
drawResultData(result):繪制分析結果。
findHotspot()
function findHotspot() { var params = { Query: buildDefinitionQuery() }; cleanup(); spinner.viewModel.point = view.center; //經典的完整then()寫法 gp.submitJob(params).then(drawResultData, errBack, progTest); }
通過buildDefinitionQuery()獲取需要的參數。
then寫法,第一個drawResultData()是分析成功時要做的事情:繪制結果;
errBack()是分析失敗要做的事情;
progTest()則是測試分析進展。
后兩個比較簡單,這樣的寫法類似try catch異常處理。
buildDefinitionQuery()
function buildDefinitionQuery() { var defQuery; var startDate = locale.format(registry.byId('fromDate').value, { datePattern: 'yyyy-MM-dd hh:mm:ss', selector: 'date' }); var endDate = locale.format(registry.byId('toDate').value, { datePattern: 'yyyy-MM-dd hh:mm:ss', selector: 'date' }); var def = []; def.push("(Date >= date '" + startDate + "' and Date <= date '" + endDate + "')"); def.push( "(Day = 'SUN' OR Day= 'SAT' OR Day = 'FRI' OR Day ='MON' OR Day='TUE' OR Day='WED' OR Day ='THU')" ); if (def.length > 1) { defQuery = def.join(" AND "); } return defQuery; }
使用locale.format方法獲取時間控件上的時間,分別為startDate和endData兩個Object變量;
然后根據日期范圍,設定一組SQL語句(應該是,語法比較怪異),名為def(裝箱為String[])
最后把數組通過AND來鏈接成一個長字符串,賦值給defQuery這個變量,並返回defQuery變量作為返回值,也即為submitJob()的參數。
drawResultData(result)
function drawResultData(result) { var imageParams = new ImageParameters({ format: "png32", dpi: 300 }); var resultLayer = gp.getResultMapImageLayer(result.jobId); resultLayer.opacity = 0.7; resultLayer.title = "HotspotLayer"; map.layers.add(resultLayer); spinner.viewModel.point = null; }
ImageParameters這個類是什么東西完全不知道...new出來完全沒看懂哪里有用,各位可以試試刪除這個實例再運行。//懷疑是SDK開發人員忘記刪了。
從gp中獲取MapImageLayer,這個getResultMapImageLayer()是個新方法,返回指定id的MapImageLayer實例。這里返回的MapImageLayer實例名為resultLayer。
設置好透明度和名字后,加入到map的layers中。這就算完成了。
最后再上一張邏輯圖:

至於圖例widget和那個啥spinner就不作為重點啦~有興趣的同學可以深究一下,應該在widget章節有詳細的說明的。
再次感嘆then這個東西的強大之處,Promise對異步操作真的太方便了。
總結一下
...???上面那張邏輯圖不就說明了一切嗎???
黑人問號.jpg
