ArcGIS API for JavaScript 4.2就学笔记[7] 鹰眼(缩略图的贯彻及异步处理、Promise、回调函数、监听的笔记)

文前表明:关于style就是页面的css暂时不做评价,因为官方给的例证的体制实在太简单了,照抄阅读即可。

这篇小说有着大量AJS
4.x本子添加的情节,如监听watch、Promise对象、回调函数、异步处理等内容,原理性的东西我会在文末解释,各位看官不用操心看不懂,我竭尽用通俗的言语诠释这些。

常规,假设不习惯从头看到尾,可以平素跳到前面看总结。


世家应该看过生意地图的缩略图功效吗?以度娘地图为例,在动用街景地图的时候,左下角会产出一个地址一样的2D小地图:

图片 1

以此就是鹰眼功效的选取,在广大桌面软件中如Erdas、Envi,鹰眼是很广泛的。

//假如以下超链接日后更新了4.3或更高版本,请自行检索4.2的sample配合本经济学习~

这一次就解读2D overview map in
SceneView
这多少个事例。

源代码:点我

事实上就是一个2D的MapView在3D的SceneView的彰显而已,关键就在数码的一块儿,官方建议了watch()方法是着重。

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

图片 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方法看它做了怎么:

图片 3图片 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这多少个艺术再次来到的都是沃特chHandle对象。待将来讨论多了监听后,再仔细看看其余监听方法。

困难就在于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()是这样的:

图片 5

出处:点我

then里头当然是办法,无参的。只有子一层的结果做到的时候,父一层的then才能凭借子一层的结果的回调完成异步。

给一部分自身阅读中以为不错的对异步、回调函数讲解的稿子:

大白话讲解Promise

ECMAScript 6入门

Javascript异步编程的4种方法

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

Javascript异步编程之—异步原理

JS中的回调函数,以及ES6中通过promise处理回调