地图服务中点数据的导出
1.为什么要导出地图服务中的数据
有这个想法的起因是前端时间在做一个demo的时候,用到了一份ArcGIS Online的要素服务。做完之后觉得这份数据挺不错的,想着以后可以用到其他地方,但考虑到总联网不太方便,那个时候就想着有没有简便的方法可以把人家服务的数据离线下来。现在重新整理了下思路,找了一个更简洁的方法来实现。
2.导出实现思路
导出的主要思路是调用地图服务的query查询功能,将查询结果输出到控制台来实现。但需要注意的是,ArcGIS Server发布服务的时候,默认设置的最大返回记录数是1000,什么意思?意思是query查询只会返回1000条结果。这不是我导出的本意,我要的是全部数据,所以我们首先要解决这个1000的限制问题。详细的实现步骤如下:
- 创建网格
这里为了解决1000条限制的问题,采用的是分块的思路,即将地图划分成规则的网格,保证网格中包含的地图服务的数据量不会超过限制。关于如何保证不超限的问题,请看后面解释。 - 按每个格子执行query查询
划分好格子之后,下一步就是按格子范围来执行query查询了。为了解决前面说的保证不超限问题,将query查询结果总数打印出来就知道了,总数如果超过了地图服务设置的限制数,重新调整网格大小就行了。不知道如何查询地图服务设置的限制数的请脑补ArcGIS在线帮助。 - 将查询结果按逗号隔开输出到控制台
将query查询结果逐条输出,每条结果对应的就是数据表中的一行记录,当然还需要将x、y坐标也输出。属性值与属性值间用逗号隔开,是方便将结果保存为CSV文件。 - 将CSV文件转换成空间格式
有了CSV文件就好说了,ArcMap能将其转成空间格式,Portal还能直接发服务。
3.导出功能实现
(1)创建网格
//生成规则的网格
function createGrids(minx,miny,maxx,maxy,cellCount){
var stepX = (maxx - minx)/cellCount;
var stepY = (maxy - miny)/cellCount;
var extents = [];
for(var i=0;i<cellCount;i++){
var newMinx = minx + i*stepX;
var newMaxx = minx + (i+1)*stepX;
for(var j=0;j<cellCount;j++){
var newMiny = miny + j*stepY;
var newMaxy = miny + (j+1)*stepY;
var extent = new Extent(newMinx,newMiny,newMaxx,newMaxy);
extents.push(extent);
}
}
return extents;
}
(2)执行query查询
function queryBtnHandler(){
var queryUrl = dom.byId("mapserviceUrl").value;
allFeatures = [];
numCounts = [];
map.graphics.clear();
//创建网格
var gridNum = parseInt(dom.byId("gridNum").value);
var extents = createGrids(map.extent.xmin,map.extent.ymin,map.extent.xmax,map.extent.ymax,gridNum);
var sls = new SimpleLineSymbol("solid", [128,128,128], 1.5);
var sfs = new SimpleFillSymbol("solid", sls, null);
//每个网格执行一个query查询
for(var i=0;i<extents.length;i++){
var gp = new Graphic(extents[i],sfs);
map.graphics.add(gp);
var query = new Query();
query.outFields = ["*"];
query.where = "1=1";
query.returnGeometry = true;
query.geometry = extents[i];
var queryTask = new QueryTask(queryUrl);
queryTask.execute(query, function (featureSet) {
console.log("query查询条数:"+featureSet.features.length);
numCounts.push(featureSet.features.length);
for(var j=0;j<featureSet.features.length;j++){
var feature = featureSet.features[j];
allFeatures.push(feature);
}
});
}
}
(3)输出结果
function exportAllFeaturesBtnHandler(){
var sum=0;
for(var k=0;k<numCounts.length;k++){
sum += numCounts[k];
}
console.log("query返回的总个数:"+sum);
console.log("返回的feature是总数:"+allFeatures.length);
if(allFeatures.length>0){
//输出key值
var keyNames = "x,y,";
for(var keyName in allFeatures[0].attributes){
keyNames += keyName+",";
}
console.log(keyNames.substr(0,keyNames.length-1));
}
//输出所有的要素信息
for(var j=0;j<allFeatures.length;j++){
var ptStrs = allFeatures[j].geometry.x+","+allFeatures[j].geometry.y+",";
for(var key in allFeatures[j].attributes){
ptStrs += allFeatures[j].attributes[key]+",";
}
console.log(ptStrs.substr(0,ptStrs.length-1));
}
}
4.小结
- 由于query是异步执行的,所以需要为每个格子查询创建单独的Query和QueryTask,才不会导致相互干扰。
- 也正由于query是异步执行的,所有查询功能是按类似多线程在运行。
网友评论