接着上篇的ArcGIS4Js重要概念3:编程模式1,进行捋一捋异步(Async Data)和使用 fromJSON (Using fromJSON)。
Async Data(异步)
在ArcGIS API for JavaScript中常用的异步模式有两种:Promises
和Loading
。
Promises
Promises
是API中非常重要的一个概念,使用它可以很简洁的写出异步操作代码,同时多个Promises
的顺序执行,是支持链式代码。 每个Promises
执行状态都是pending(正在进行)
、resolved(正常完成)
、rejected(报错)
三种状态中的一个。Promises
执行完成可以通过then(callback, errorCallback)
方法监听,其中callback
为执行成功的回调,
errorCallback
为失败回调,是可选参数。
someAsyncFunction()
.then(function(resolveValue) { //成功回调
console.log(resolvedValue);
}, function(error) { //失败回调
console.log(error);
});
执行错误的回调,我们还可以使用catch()
方法进行捕捉,这个在链式代码中非常有用,可以统计处理异常。
someAsyncFunction()
.then(function(resolveValue) {//成功回调
console.log(resolvedValue);
}, function(error) {//捕捉
console.log(error);
});
下面我们来看个使用GeometryService
类中的project()
方法,将已知点进行投影转换的例子:
require([
"esri/tasks/GeometryService",
"esri/tasks/support/ProjectParameters",
], function(GeometryService, ProjectParameters) {
var geoService = new GeometryService( "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/Geometry/GeometryServer" );
var projectParams = new ProjectParameters({
geometries: [points], //需要转换的点集合
outSR: outSR,//转换至的坐标系
transformation = transformation //转换模型
});
geoService.project(projectParams)
.then(function(projectedGeoms){
console.log("投影转换之后的点: ", projectedGeoms);
}, function(error){
console.error(error);
});
});
Promises
还支持链式代码,可以通过多个then(callback)
方法进行连接,上一个回调返回值,可以作为下一个回调的参数。例如下面的例子的执行顺序,对输入点投影转换 -> 对转换好点进行缓冲区分析 -> 将缓冲区分析结果面添加到图层中 -> 计算各个缓存面的面积 -> 计算所有缓存面面积和
var bufferLayer = new GraphicsLayer();
//缓冲区分析
function bufferPoints(points) {
return geometryEngine.geodesicBuffer(points, 1000, "feet");
}
//缓冲面添加到图层
function addGraphicsToBufferLayer(buffers) {
buffers.forEach(function(buffer) {
bufferLayer.add(new Graphic(buffer));
});
return buffers;
}
//计算单个缓冲面面积
function calculateArea(buffer) {
return geometryEngine.geodesicArea(buffer, "square-feet");
}
//分别计算缓冲面面积
function calculateAreas(buffers) {
return buffers.map(calculateArea);
}
//计算面积和
function sumArea(areas) {
for (var i = 0, total = 0; i < areas.length; i++) {
total += areas[i];
}
return total;
}
geoService.project(projectParams)
.then(bufferPoints)
.then(addGraphicsToBufferLayer)
.then(calculateAreas)
.then(sumArea)
.catch(function(error) { //统一处理异常
console.error("出错啦! Message:", error);
});
Loadable
API中的layer
、map
、portal item
等资源加载都是要异步远程服务或本地数据,Loadable
模式就是为了方便的监听它们的加载状态,而这些资源都称作可加载资源
。
可加载资源
都有如下只读属性:
- loaded -> Boolean :资源是否加载完成
- loadError -> Error :资源加载失败的错误对象
- loadStatus -> String :资源加载状态,只可能为:not-loaded(还没开始加载)、loading(加载中)、loaded(加载成功)、failed(加载失败)
可加载资源
都有如下方法:
- cancelLoad():取消加载,只有当资源处于
loading
状态是才有效 - load() —> Promises :触发加载,并返回
Promises
,可用于监听加载状态
可加载资源
加载流程图如下:
Loadable
模式可以自动处理级联依赖(Cascading load dependencies),如下代码,加载webmap
就会触发portalItem
加载,继而触发portal
加载。
var view = new MapView({
container: "viewDiv"
});
var portal = new Portal({
url: "https://myportal/"
});
var webmap = new WebMap({
portalItem: {
portal: portal,
id: "f2e9b762544945f390ca4ac3671cfa72"
}
});
webmap.load()
.then(function() { view.map = webmap; })
.catch(function(error) {
console.error("加载出错啦:", error);
});
使用 fromJSON
API中的很多类,如Camera
,Viewpoint
, Color
都提供了fromJSON()
静态方法。该方法可将ArcGIS各个平台(ArcGIS Server等) ArcGIS REST API或生成的JSON对象转为ArcGIS API for Javascript中的对象。
如下代码将ArcGIS REST API查询返回的SimpleMarkerSymbol
Json对象转为ArcGIS API for Javascript中的SimpleMarkerSymbol
对象:
require(["esri/symbols/SimpleMarkerSymbol"], function(SimpleMarkerSymbol){
// 由ArcGIS API for Javascript 产生的Json对象
var smsJson = {
"type": "esriSMS",
"style": "esriSMSSquare",
"color": [ 76,115,0,255 ],
"size": 8,
"angle": 0,
"xoffset": 0,
"yoffset": 0,
"outline":
{
"color": [ 152,230,0,255 ],
"width": 1
}
};
var sms = SimpleMarkerSymbol.fromJSON(smsJson);
});
注意: fromJSON()
接收的Json对象看上去和构造函数接收Json对象非常像,但他们两是不一样的东西,千万不要混了。fromJSON()
接收的Json对象是ArcGIS平台中通用的格式,而构造函数中接收的Json对象只能在JS API中使用,他们有很多不同的地方。所以如果是ArcGIS平台返回的JSON对象,必须通过fromJSON()
进行转换。
使用jsonUtils
除了使用fromJSON()
可将Json对象转为API对象,API中还提供多个jsonUtils
可将Json对象转为API对象,例如:
- esri/geometry/support/jsonUtils
- esri/renderers/support/jsonUtils
- esri/symbols/support/jsonUtils
通过jsonUtils
转换出来的对象是不确定,而通过fromJSON()
转换出来是确定的对象。例如我们知道一个ArcGIS REST API返回的是一个Renderer
对象,但我们不知道它返回是UniqueValueRenderer
或其他Rednerer,这时候我们就可以通过jsonUtils
进行转换。
require([ "esri/renderers/support/jsonUtils",
"esri/layers/FeatureLayer"
], function( rendererJsonUtils, FeatureLayer ){
var rendererJSON = {// 由REST API生成
"authoringInfo":null,
"type":"uniqueValue",
"field1":"CLASS",
"field2":null,
"field3":null,
"expression":null,
"fieldDelimiter":null,
"defaultSymbol":{
"color":[
235,
235,
235,
255
],
"type":"esriSLS",
"width":3,
"style":"esriSLSShortDot"
},
"defaultLabel":"Other major roads",
"uniqueValueInfos":[
{
"value":"I",
"symbol":{
"color":[
255,
170,
0,
255
],
"type":"esriSLS",
"width":10,
"style":"esriSLSSolid"
},
"label":"Interstate"
},
{
"value":"U",
"symbol":{
"color":[
223,
115,
255,
255
],
"type":"esriSLS",
"width":7,
"style":"esriSLSSolid"
},
"label":"US Highway"
}
]
};
// 将JSON对象转为API对象
var flRenderer = rendererJsonUtils.fromJSON(rendererJSON);
// 将renderer设置给图层
var layer = new FeatureLayer({
renderer: flRenderer
});
});
最后,重要概念中的编程模式,到这就结束啦,合理利用这些模式,代码将会更加简洁,可读性更高。