一.开发环境:MapGIS IGServer10.0、OpenLayers3
二.需求分析:前端界面的道路网通过捕捉周边的点要素个数,以此作为权重来对道路网进行颜色带的渲染。
三.思路:1.由于路网的线要素较长,故首先要将线要素进行划分,合理来说,应该是按照距离划分的。2.对新的道路做缓冲区分析,缓冲区半径自定义。3.通过缓冲区与周围点要素进行空间查询,得到每个缓冲区查询到的点要素个数。4.将所有的点个数进行数据标准化,设置阈值,进行颜色的渲染。
四.实现:
1.获取道路。通过Zondy.Service.QueryDocFeature()的属性查询方法进行查询,得到发布的mapx文件中所有的线要素,回调函数返回值是个数组,这是中地的要素,要使用var format = new Zondy.Format.PolygonJSON(); var linesFeatureArr= format.read(result);得到ol的feature。
2.生成新道路。通过遍历线要素数组,通过getGeometry()得到线要素的geometry,再通过getCoordinates()得到geometry的节点坐标。通过自己写个小方法去对线要素进行截取,最后得到的是很多个点坐标的数组。
var gLine=new Zondy.Object.GLine(
new Zondy.Object.AnyLine([new Zondy.Object.Arc(zondy_pointArr2)])
);
var LinGeom=new Zondy.Object.FeatureGeometry({
LinGeom:[gLine]
});
通过上面这个方法去得到中地的FeatureGeometry,用于做缓冲区。再通过下面这个得到ol的feature,用于添加到地图上。现在,我就得到了两个数组,一个是中地的线要素数组zondyRoadFeatureArr,一个是ol的线要素数组olRoadFeatureArr。
var roadSub_feature=new ol.Feature({
type: 'route',
geometry:new ol.geom.LineString(ol_pointArr2)
});
3.生成缓冲区。通过Zondy.Service.FeatureBuffBySingleRing()和zondyRoadFeatureArr生成缓冲区,该缓冲区作为面要素存在hdf里面,返回值里面含有这个面要素的url,url=data.results[0].Value,将所有的缓冲区的url放在一个数组里,bufferUrlArr。
4.查询缓冲区。通过Zondy.Service.QueryLayerFeature和bufferUrlArr查询出缓冲区要素,这个返回值是一个中地的FeatureGeometry。因为要用它作为一个浏览器上绘制的多边形进行查询点要素,所以要将其转换为Zondy.Object.Polygon()。如何转换?
//将中地的要素转换为ol的
var format = new Zondy.Format.PolygonJSON();
var bufferFeature = format.read(result);
//将ol的要素转换为中地的polygon
var bufferPolygon=new Zondy.Object.Polygon();
bufferPolygon.setByOL(bufferFeature[0].values_.geometry);
得到了一个缓冲区的要素,放到一个数组里,就有了一个缓冲区要素的数组bufferFeatureArr。
5.查询点要素。通过Zondy.Service.QueryDocFeature()和bufferFeatureArr进行查询,返回结果result.TotalCount即是点要素的个数,将其放在一个数组里,就会有一个存到点要素个数的数组ptNumberArr。
4、5.修正!这个时候思路错了!
需求是为了得到各个缓冲区内捕捉到的点的个数,原来的方法是通过矢量图层查询到缓冲区,将其作为几何多边形去向IG Server发送请求,去查询点的个数。这样太笨了!
正确的方法:通过查询,能够得到所有的缓冲区和点的个数,全部转换为ol类型的,然后将缓冲区存到ol的ol.source.Vector里,而该类有个方法叫getFeatureInExtent(extent),即在ol里面,也是支持空间查询的。这样就不需要去请求服务器了,就会快得多,并且后面的密度分析里面同样是这个道理,能够大大提高效率!不过学到的Promise和async function(){await Promise}还是很有用的,虽然走了一些弯路,但是却看到了不一样的风景!
至此,共有5个数组。分别是zondyRoadFeatureArr,olRoadFeatureArr,bufferUrlArr,bufferFeatureArr,ptNumberArr。其中关系是这样的:zondyRoadFeatureArr→bufferUrlArr→bufferFeatureArr→ptNumberArr,而olRoadFeatureArr还没有用上,那么就通过ptNumberArr的索引与olRoadFeatureArr索引一一对应的关系,将其渲染出不同的颜色。
五.遇到的坑:
1.缓存区生产失败。原因:缓冲区执行时候的参数写法错误,注意格式是下面这个样子的,点线面生产缓冲区都要使用Zondy.Object.FeatureGeometry这个类,但是Zondy.Object.GLine、Zondy.Object.GPoint、Zondy.Object.Region这些的格式要注意一下,而这些跟Zondy.Object.PolyLine、Zondy.Object.Polygon是不一样的,前者是复杂的,是里面有很多内容,后者是简单的,只是一个多边形。而在生成缓冲区的时候,需要用前者,在作为绘制多边形查询的时候,比如拉框查询的这个“矩形”,要转换为后者。
var gLine=new Zondy.Object.GLine(
new Zondy.Object.AnyLine([new Zondy.Object.Arc(zondy_pointArr2)])
);
var LinGeom=new Zondy.Object.FeatureGeometry({
LinGeom:[gLine]
});
2.生成的缓冲区只要少数个成功。打印出缓冲区的url,发现有的url是打印不出来的,也就是说缓冲区执行失败了。原因:缓冲区在生成的时候,需要对其命名,而命名的函数是通过getCurrentTime函数得到当前的时间来避免名字一样,而这个命名函数原先写的只能达到秒级,而一秒可能执行多个缓冲区,故达到了毫秒,结果发现毫秒也可能出现错误,那么就毫秒+Math.random()来实现。
3.js中浅拷贝与深拷贝的问题。
var a=[1,2];
var b=a;
a.pop();
console.log(b);
比如说,上面这个打印出来的是[1]。解释:Javascript有五种基本数据类型(也就是简单数据类型),它们分别是:Undefined,Null,Boolean,Number和String。还含有一种复杂的数据类型(也叫引用类型),就是对象。基本数据类型存储在栈中,对象存在堆中,栈中的变量保存的是这个值本身,通过“=”是来创建副本;而堆中的变量保存并不是这个对象本身,而是指向这个对象的指针,故通过“=”复制到的只不过是一个变量的指针地址而已,因此,两个变量最终指向的都是一个对象。详见下一篇转载的博客。而es6的解决办法如下所示,即通过[...a]来实现深拷贝。
var a=[1,2];
var b=[...a];
a.pop();
console.log(b);
4.同样的数据每次生成的结果都不一样。原因:
var test=[1,2,3,4,5];
$.each(test,function (index,value) {
setTimeout(function () {
console.log(value);
},Math.random()*1000);
})
这个代码打印出来的是1-5,但是顺序每次都不同。因为setTimeout是个异步方法,而异步的时间随机,谁时间短就先运行谁,而不是谁排在前面先运行谁。而我们的的代码中,从得到zondyRoadFeatureArr这一刻起,zondyRoadFeatureArr的索引和olRoadFeatureArr的索引是一一对应的,而zondyRoadFeatureArr要经过多次异步方法处理,首先是缓冲区分析,其次是查询缓冲区,然后查询点要素。即zondyRoadFeatureArr经过了三次异步处理最后得到ptNumberArr,而这些异步处理的时间是不确定的,故zondyRoadFeatureArr的索引早已和ptNumberArr的索引发生了偏差,也就导致了ptNumberArr和olRoadFeatureArr的索引不能一一对应。
注意:若把代码改为这样,是不会打印出1-5的,而是5个undefined。
var test = [1, 2, 3, 4, 5];
for (var i = 1; i < 6; i++) {
setTimeout(function () {
console.log(test[i]);
}, Math.random() * 1000);
}
原因:var是全局变量,最后打印的是5个test[6],所以为undefined。而将其var i改为let i就可以达到$.each这个效果了,let只在块级作用域有效。
对于上面4中的问题怎么办呢?以生存缓冲区为例。
首先在执行缓存区分析的时候,这个回调函数要这样写:
function generateBuffer(){
return new Promise(function (resolve,reject) {
bufferService.execute(function (data) {
resolve(data);
},"post", false, "json", function (err) {
resolve(err);
})
})
}
其次在调用生成缓存区函数的时候这样写:
const promises=newZondyRoadFeature.map(function (value) {
return generateBuffer(value)
});
Promise.all(promises).then(function (results) {
results.forEach(function (result) {
layerBufferSuccess(result);
})
});
而之前是这样写的:
生成缓冲区:
function generateBuffer() {
bufferService.execute(success(data) {
...
})
}
调用的时候:
newZondyRoadFeature.map(function (value) {
generateBuffer(value)
});