C++ArcGIS API for JavaScript 4.2上学笔记[7] 鹰眼(缩略图的落实同异步处理、Promise、回调函数、监听的记)

文前征:关于style就是页面的css暂时未做褒贬,因为官方给的事例的体裁实在太简单了,照抄阅读即可。

顿时首文章有大量AJS
4.x本子添加的情节,如监听watch、Promise对象、回调函数、异步处理等情节,原理性的物我会在文末解释,各位看官不用顾虑看无亮,我尽量用通俗的语言说这些。

惯例,如果不习惯从头看到尾,可以一直跨越到尾看总结。


世家该看了商业地图的缩略图功能吧?以度娘地图呢条例,在行使街景地图的时段,左下比赛会起一个地方一样的2D微地图:

C++ 1

是就是是鹰眼功能的利用,在无数桌面软件面临一经Erdas、Envi,鹰眼是死常见的。

//如果以下超链接日后更新了4.3还是再胜似版本,请自行检索4.2之sample配合本文学习~

这次就解读2D overview map in
SceneView此例子。

源代码:点我

事实上就是是一个2D底MapView在3D的SceneView的来得而已,关键就于数额的共同,官方指出了watch()方法是任重而道远。

话不多说,先上最后效果图:

C++ 2

组织大体上就是是,大的DIV里放SceneView,小之DIV里放MapView。

稍许的DIV里而起一个黑色的区域来标识当前SceneView的区域。小的DIV的widgets被移除。

html代码为:

<body>
  <div id="viewDiv"></div>
  <div id="overviewDiv">
    <div id="extentDiv"></div>
  </div>
</body>

老样子,require给起引用(以前都被第一只字符串数组参数,为了方便,以后直接给引用了)

require(
    [
      "esri/Map",
      "esri/views/SceneView",
      "esri/views/MapView",
      "esri/core/watchUtils",
      "dojo/dom",
      "dojo/promise/all",
      "dojo/domReady!"
    ],
    function(Map, SceneView, MapView, watchUtils, dom, all){
        //你的代码
    }
);

要应该是:

view的watch()方法、watchUtils的when方法、view的toScreen方法、view的extent属性、view的then方法。


 

既是生个别只view(DIV),那么势必要有零星卖map(数据)。

所以亚参数(以前的章于函数参数,之后还被第二参数)先将map和view定义如下:

      var mainMap = new Map({
        basemap: "hybrid",
        ground: "world-elevation"
      });
      var overviewMap = new Map({
        basemap: "osm"
      });
      var mainView = new SceneView({
        container: "viewDiv",
        map: mainMap
      });
      var mapView = new MapView({
        container: "overviewDiv",
        map: overviewMap
      });

mainMap、mainView是3D的,overviewMap、mapView是2D的。

当,我们视底2D之稍地图是从来不放缩小那些控件的,只待1行代码,就可以置空那些控件。

      mapView.ui.components = [];

查API,可以知道ui属性是DefaultUI类,DefaultUI继承自UI类。components是字符串数组,若赋值为空数组则清空。相应的,DefaultUI类有remove和empty方法可打消控件,就无密切说了。

为便于操作,把当下区域之DIV“extendDiv”的DOM元素得到为变量:

var extentDiv = dom.byId("extentDiv");

 

如上就是完了了备选部分。

对接下,数据加载成功后,就设对2D底地形图和3D的地形图进行“同步”了,需要用到个别只view的then方法。

then()方法是Promise对象的故意方法,而Promise是什么暂时无需了解,只要知道在AJS
4.x中Promise是一个异常重点之事物。

又,MapView和SceneView类都蝉联了Promise类。不仅如此,AJS
4.x中很多方返回的还是Promise对象。

优先看看mainView(3D视图)的then方法看看它举行了呀:

mainView.then(function() {
  mainView.goTo({
    center: [7, 46],
    scale: 200000,
    heading: 35,
    tilt: 60
  },
 {
    animate: true,
    duration: 100000
  })
});

老好,它承受了一个参数,类型是方法。这个匿名方式干了啊呢?这不纵是上同一首文章里说之缩放动画嘛!(goTo)跳过,看mapView(2D视图)的then方法看她做了啊:

C++ 3C++ 4

mapView.then(function() {
  mainView.watch("extent", updateOverviewExtent);
  mapView.watch("extent", updateOverviewExtent);

  watchUtils.when(mainView, "stationary", updateOverview);

  function updateOverview() {
    mapView.goTo({
      center: mainView.center,
      scale: mainView.scale * 2 * Math.max(mainView.width /
        mapView.width,
        mainView.height / mapView.height)
    });
  }

  function updateOverviewExtent() {
    var extent = mainView.extent;

    var bottomLeft = mapView.toScreen(extent.xmin, extent.ymin);
    var topRight = mapView.toScreen(extent.xmax, extent.ymax);

    extentDiv.style.top = topRight.y + "px";
    extentDiv.style.left = bottomLeft.x + "px";

    extentDiv.style.height = (bottomLeft.y - topRight.y) + "px";
    extentDiv.style.width = (topRight.x - bottomLeft.x) + "px";
  }
});

mapView的then方法

杀丰富的金科玉律。

自渐渐讲。

还是是奉一个措施作为参数(为什么then接受的参数那么奇怪?文末会说的)

//题外话:在javascript里头传函数/方法是老大广泛的,函数/方法是js的等同种植变量类型,在C/C++里头可以传递函数指针,在C#里头可以传递委托变量。

本条方式里有零星只措施,命名吧 updateOverview
和 updateOverviewExtent,我们根据当时点儿个方式将此then方法的代码拆起来羁押,发现watch和watchUtils.when是同这有限独办法配对的。

即:

//两个视图都与updateOverviewExtent方法绑定
mainView.watch("extent", updateOverviewExtent);
mapView.watch("extent", updateOverviewExtent);

function updateOverviewExtent() {
  var extent = mainView.extent;

  var bottomLeft = mapView.toScreen(extent.xmin, extent.ymin);
  var topRight = mapView.toScreen(extent.xmax, extent.ymax);

  extentDiv.style.top = topRight.y + "px";
  extentDiv.style.left = bottomLeft.x + "px";

  extentDiv.style.height = (bottomLeft.y - topRight.y) + "px";
  extentDiv.style.width = (topRight.x - bottomLeft.x) + "px";
}

翻开API,得知视图的父类Accessor就支持watch方法了。值得一提的凡,为了兑现监听变化,AJS4.x版本专门供了watch方法代替了原先的原办法。

watch的用法是:

本着象.watch(“该待监听的性质名”,
属性变化后用实施之回调函数);

style=”font-size: 13px”>即某目标监听了它的某部属性后,这个特性一旦闹转移,就见面去实施某些代码。

在本例中,需要监听的是片独view对象的extent(范围)属性,一旦extent发生变化,那么updateOverviewExtent()方法就见面被执行。

updateOverviewExtent()方法的大体意思就是是:获取3D视图的限定->获取2D视图的指向角线两只角点->更改2D视图上方的区域约的DOM元素的尺寸属性(top、left、height、width)

才改变区域框是不行的,还要反2D地形图的限量。

watchUtils.when(mainView, "stationary", updateOverview);

function updateOverview() {
  mapView.goTo({
    center: mainView.center,
    scale: mainView.scale * 2 * Math.max(mainView.width /
      mapView.width,
      mainView.height / mapView.height)
  });
}

watchUtils这个目标,是身处esri/core/watchUtils模块下的一个类。

她代表的意思是:监听某个对象,当以此目标的有属性是true时,执行给定的计。

翻看API得知,这个类似提供了when这个静态方法,when方法的含义是:

据此,在本例中,意思就是是:

当mainView这个3D视图对象的”stationary”属性是true时,刷新mapView这个2D视图对象。

刷新2D视图对象主要为此的是齐一样首被说及的goTo()方法,本例只指定了center和scale这点儿独特性组成的Object匿名对象。

SceneView类的stationary属性是布尔路的,意义是眼前视图是否业已稳步(一般视图会由鼠标拖拽或者goTo()方法来动态效果,一旦停止下来,stationary就见面成为true)

 

小结一下。

此事例大概思路就是是:

·先实例化两单map和片单view,对3D的mainView在开创好后下then()方法缩放到指定位置。

·其中,对2D的mapView创建好后以then()方法,分别监听两个view的extent属性,还监听3D视图的stationary属性。

·当extent属性发生变化时,2D视图上方范围框先进行转移,然后2D地形图紧按转。

·当3D视图静止下来后,刷新2D视图。

 

监听还算比较好掌握,需要注意的免多,注意到watch和watchUtils.when这有限独办法返回的都是WatchHandle对象。待下研究多了监听后,再仔细看别的监听方法。

困难就是在于then方法。


 

难点。

then()方法怎么来之?这只要从ES6(全名ECMAScript 2015)的新规范Promise对象说自。ECMAScript是JavaScript的正规,JS是ES的实现。

Promise是什么?这个事物说复杂呢特别复杂,它是:

以处理异步操作多重合回调函数的写法枯燥、难以阅读维护而生的,由CommonJS社区发起的一个新规范的好像。

极端显的特征是它们实例化的目标都发then()和catch()方法(PromiseA+规范?好像是)

在AJS中,继承了Promise的类有:

全部的Layers

MapView、SceneView、LayerView

ViewAnimation

能回Promise对象的类数不胜数。

故说,为什么而因此Promise?

当时又使自异步操作说于了。

————

于AJS
4.x中,数据(Map类)和视图(View类)是分别的,3.x版本绘图渲染是Map自己就的。

鉴于View视图类被分手开,绘图逻辑就是成了其的重要性成效。当然,绘图不会见快速,往往时有发生一个过程,尤其是重特大数据量的绘图的时节会来一个比较丰富的等候过程。

于是,在JS里,较丰富的拍卖会丢给异步处理(就是同时展开一些独操作)

不过只是,我们知晓JS是单线程的,它是怎处理异步处理的也罢?简单说说,JS的异步处理其实是单“伪异步”,是先得联合代码才行异步代码的。

常备,异步代码会举行片计算量比较异常之政工,而同步代码则举行有不怎么吃时间之初始化工作。就是说

一路代码花少量的时光去初始化一些事情,其间发生n个异步任务丢给异步队列。当一头代码完成初始化后(时间少),异步代码开始遵循顺序执行。

按照:界面的构建交给同步代码,而其间有n个后台数据交换、处理、计算的任务,就丢弃给异步队列去准备。当界面构造好(时间往往非常短缺,几乎是秒速),异步代码就在后面开始实施。

旋即先瞧底界面会叫经验好广大,如果异步代码(就是耗时比老的任务)放在同代码里推行,那么由一起的性能,必须待这些耗时大之任务尽到位才能延续向下移动(js的特性,单线程)

【在本例中】

初始化view,我未明了在云端是怎运行的(因为自身为此底是CDN来运转AJS程序),但是我晓得view的实例化肯定是为此了异步操作。

先行就网页的加载(出现3D地球和2D地形图,同步),再拓展视图的渲染(山体拔高等,异步)。

sometimes,异步操作自会生出一个结实,比如异步在背后花好长时间算有个矩阵,但是共同代码已经结束了,异步任务丢过去的下结果还尚无出,怎么抱其?

我们可以为此一个艺术去得其。这个法,古时候叫回调函数。

以没Promise类的当儿,通常用回调函数这种方法落实(也克就此事件、监听)异步是十分健康的同一栽。

而当回调函数本身为是个异步操作的时候,就会显示晕头转向。

异步第一重合,有结果如果因此回调函数返回给同步代码->回调函数是次重叠,这个回调函数里头要为此二级回调函数返回结果受第一层->……

推个例子:

自家是管理者,我现发生星星点点件事:有个事而举行,和饮茶。

就简单宗事不闯,虽然此事很低俗,耗时大(如文录入)。

就此我将这事抛给经理(异步第一重合),我继续喝茶(同步)

异步第一叠就是经要召开这事,但是这个工作绝大部分凡是低俗之,最后之整比较简单。

用经就将这无聊的有的丢给干部(异步第二层),等待职员把当时部分举行扫尾的以,也去喝茶(同步)。

遂,职员的结果就是是二级回调函数,职员把结果好后,“回调”给经。

营拿在干部的结果整理好,“回调”给领导。(第二叠异步完成)

这领导茶已经喝了了(同步到位),而任务吗到位了(第一重叠异步完成)。

此地要就此一味的写法将会晤好之辛苦,如果用Promise的then写法即是

领导要工作儿.then(function(){让经去开})

.then(function(){让职工举行});

链式写法,简单,容易看,也易于保障。

then里面的function就是回调函数,告诉异步任务就后,要怎么处理异步结果的一律截代码。

末尾看看then方法的语法:

then(function resolve, function rejected);

咱俩一般但所以前一个参数,即异步成功使怎么处理。而继一个参数是异步任务处理失败后要做呀。

竟然AJS官方还叫起了处理着一经开呀的老三独参数…这个就算未说那基本上了。

——

约莫知道是如此个过程后,我们理解View对象是Promise对象(继承),而且发生异步操作的经过。

故而,mainView.then(function(){…});的含义就是

当3D视图在服务器端异步操作成后,使用goTo()缩放到指定的岗位。

 

文末,我还想说说监听,监听在AJS 3.x版本里是经波就的,而AJS
4.x全新使用了watch一派写法。有关这些可以参考AJS 4.2的Guide文档。

末段之末段,关于异步和回调函数部分自己呢是仿了同龙后才让起底歪曲定义,希望大家能够看明白吧…我耶不是蛮能了解,官方给的多层then()是如此的:

C++ 5

出处:点我

then里头当然是方法,无参的。只有子一层的结果就的下,父同重合的then才会管借子一交汇的结果的回调完成异步。

受有己看中觉得不错的针对性异步、回调函数讲解的文章:

大白话讲解Promise

ECMAScript 6入门

Javascript异步编程的4栽办法

百度知道-JS中回调函数怎么知道

Javascript异步编程的—异步原理

JS中之回调函数,以及ES6中经过promise处理回调