天天看點

ArcGIS API for JavaScript 4.2學習筆記[29] 熱點(密度)分析——以報警頻率為例【使用Geoprocessor類】

依舊是使用Geoprocessor來分析熱點(密度),不過使用了submitJob()這個異步操作方法,有别于execute()這個同步操作方法。

這個就頗有插值分析的樣子了。也可以說是密度分析。做出來就是一個熱力地圖的樣子。

比如,人口密度,降雨分布等。這都可以由這個例子做出來類似的。

由于上一篇已經介紹過Geoprocessor類和ParameterValue類了,是以這節就略去這些内容。想知道的同學可以點選這裡,看上一篇相關内容。

與上一節不同的是,使用的不是execute()方法了,而是submitJob()方法,這是一個異步操作方法。盡管他們傳回的類型是類似的。

官方給的解釋很簡潔明了,有了前幾個的基礎幾乎可以瞬間抓住重點,如submitJob的參數的擷取,對熱力圖結果如何擷取和處理等,自行查詢API即可。

我這篇部落格則是對這個例子進行重點全解析。如果是老鳥,請直接看:How it works

看看結果

ArcGIS API for JavaScript 4.2學習筆記[29] 熱點(密度)分析——以報警頻率為例【使用Geoprocessor類】
ArcGIS API for JavaScript 4.2學習筆記[29] 熱點(密度)分析——以報警頻率為例【使用Geoprocessor類】

給定一個時間範圍,就能查詢該地區報警的頻率。這裡使用了圖例這個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()

ArcGIS API for JavaScript 4.2學習筆記[29] 熱點(密度)分析——以報警頻率為例【使用Geoprocessor類】
ArcGIS API for JavaScript 4.2學習筆記[29] 熱點(密度)分析——以報警頻率為例【使用Geoprocessor類】
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;
}      

buildDefinitionQuery()方法

使用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中。這就算完成了。

最後再上一張邏輯圖:

ArcGIS API for JavaScript 4.2學習筆記[29] 熱點(密度)分析——以報警頻率為例【使用Geoprocessor類】

至于圖例widget和那個啥spinner就不作為重點啦~有興趣的同學可以深究一下,應該在widget章節有詳細的說明的。

再次感歎then這個東西的強大之處,Promise對異步操作真的太友善了。

總結一下

...???上面那張邏輯圖不就說明了一切嗎???

黑人問号.jpg

繼續閱讀