由于公司有业务要求,要对超图服务做预研,来完善系统功能,主要分为REST服务加载、服务的分页查询以及统计、对地图的加载增加属性过滤
服务加载
服务加载可以参考官方文档示例
如果是非openlayer的原生坐标系,即3857和4526,则需要引入proj4来注册你要用的坐标系
//以4490为例
proj4.defs("EPSG:4490", "+proj=longlat +ellps=GRS80 +no_defs +type=crs");
ol.proj.proj4.register(proj4);
定义好坐标系之后就可以开始加载服务了,首先配置服务地址,超图的服务地址配置到这一层及即可
通过这个界面可以知道服务的四至、以及中心点信息,这些在后面加载底图是需要用到的。
定义加载服务前的基础信息
//服务地址
var url = "https://iserver.supermap.io/iserver/services/map-changchun/rest/maps/长春市区图";
//服务四至
var extent = [48.4, -7668.25, 8958.85, -55.58];
//根据四至定义坐标系
var projection = new ol.proj.Projection({
code: '',
extent: extent,
units: 'm',
getPointResolution: function (resolution, point) {
return resolution
}
});
//创建视图
var view=new ol.View({
center: [5105, -3375],
zoom: 1,
projection: projection,
origin: [48.4, -55.58],
multiWorld: true
})
var map = new ol.Map({
target: 'map',
controls: ol.control.defaults({ attributionOptions: { collapsed: false } })
.extend([new ol.supermap.control.Logo()]),
view
})
var layer = null;
接下来调用超图api提供的方法来叠加地图
//初始化地图信息
new ol.supermap.MapService(url).getMapInfo(function (serviceResult) {
var mapJSONObj = serviceResult.result;
layer = new ol.layer.Tile({
source: new ol.source.TileSuperMapRest(ol.source.TileSuperMapRest.optionsFromMapJSON(url, mapJSONObj))
});
map.addLayer(layer);
});
注意点:如果有自己系统地图的比例尺数组,建议是自己创建TileGrid,创建超图REST服务最主要的是TileGrid,以下是自定义TileGrid参考代码:
var tileGrid = new ol.tilegrid.TileGrid({
resolutions: [34.80645970950213, 17.403229854751064, 8.701614927375532,
4.350807463687766, 2.175403731843883, 1.0877018659219415, 0.5438509329609708,
0.2719254664804854, 0.1359627332402427, 0.06798136662012134, 0.03399068331006067,
0.016995341655030336, 0.008497670827515168, 0.004248835413757584, 0.002124417706878792,
0.001062208853439396, 0.000531104426719698, 0.000265552213359849, 0.0001327761066799245,
0.00006638805333996225, 0.000033194026669981125, 0.000016597013334990563],//你自己系统比例尺数组
origin
});
var layer = new ol.layer.Tile({
source: new ol.source.TileSuperMapRest({
url,
tileGrid,
tileSize: 256,//默认用256
crossOrigin: "anonymous",
})
});
map.addLayer(layer);
以上两种方式都可以正确加载服务
分页查询
分页查询可以参考地图服务queryResults的POST请求
如上图所示,可以通过查询起始记录位置和期望返回记录数目来控制分页
相关代码如下
//超图服务查询的主要参数
var queryParam = {
queryMode: "SqlQuery",//查询类型,主要有SqlQuery(条件查询)和SpatialQuery(空间图形查询)
queryParameters: {
queryParams: [{
name: "单值专题图",//需要查询的图层名称
fields: [],//显示字段
groupBy: "",//分组查询使用的分组字段
attributeFilter: "1=1"//where条件
}],
startRecord: 0,//起始索引
expectCount: 10,//需要查询的数量
},
spatialQueryMode: "INTERSECT",//使用
geometry: null,
}
axios.post(url + "/queryResults.json?returnContent=true", queryParam)//returnContent表示直接返回结果
.then(res => {
//输出查询结果
console.log(res.data)
})
.catch(err => {
console.log('错误' + err)
})
这个时候返回的查询结果就是10条,同事可以通过返回的totalCount来知道总的记录数,方便计算总页数。
统计/分组统计
统计和分组统计做法和查询类似,通过类似于sql语句中的count方法来进行统计、分组就是添加groupby字段
参数设置如下:
//统计参数
queryParam = {
queryMode: "SqlQuery",//查询类型,主要有SqlQuery(条件查询)和SpatialQuery(空间图形查询)
queryParameters: {
queryParams: [{
name: "单值专题图",//需要查询的图层名称
fields:["COUNT(SmX) as COUNT","SUM(SmX) as SUM","AVG(SmX) as AVG",
"MAX(SmX) as MAX","MIN(SmX) as MIN"],//显示字段
groupBy: "",//分组查询使用的分组字段
attributeFilter: "1=1"//where条件
}],
},
spatialQueryMode: "INTERSECT",//使用
geometry: null,
}
返回结果:
分组的话就是添加一个groupBy,下面我们用name字段来进行分组统计
//统计参数
queryParam = {
queryMode: "SqlQuery",//查询类型,主要有SqlQuery(条件查询)和SpatialQuery(空间图形查询)
queryParameters: {
queryParams: [{
name: "单值专题图",//需要查询的图层名称
fields:["COUNT(SmX) as COUNT","SUM(SmX) as SUM","AVG(SmX) as AVG",
"MAX(SmX) as MAX","MIN(SmX) as MIN","name"],//显示字段
groupBy: "name",//分组查询使用的分组字段
attributeFilter: "1=1"//where条件
}],
},
spatialQueryMode: "INTERSECT",//使用
geometry: null,
}
结果如下:
空间过滤显示
空间过滤显示意思就是对服务中的图层显隐过滤、以及对图层中某些符合条件的才显示
通过查看超图官方的帮助文档可以了解到在创建ol.source.TileSuperMapRest是有一个layersID参数,那么这个ID就是我们控制服务的图层显隐以及条件显示的关键了。
打开超图服务界面,可以看到这么一个选项:tempLayersSet
在这个里面可以去勾选这个图层,以及配置图层的sql条件,来请求得到一个ID,最终控制服务的显隐。
那么在代码里面我们也是通过这种逻辑来实现。
首先先直接请求这个接口,得到一个ID,然后再请求这个ID拿到这个服务相关tempLayersSet所需的参数,在进行自定义的配置
var layerParam;
axios.post("url" + "/tempLayersSet.json")
.then(res => {
//首先请求tempLayersSet得到一个结果ID,在根据结果ID拿到基础的参数配置
axios.post(res.newResourceLocation)
.then(res => {
layerParam = res;
console.log(res)
})
.catch(err => {
console.log('错误' + err)
})
console.log(res.data)
})
.catch(err => {
console.log('错误' + err)
})
其中sublayers就是服务中显示的图层定义了,需要显示哪个图层就保留哪个。
接下来我们就以WaterPoly@Changchun这个图层为例,只显示这个图层,
//条件替换初始参数
layerParam[0].subLayers.layers = layerParam[0].subLayers.layers.filter(t => t.name == "WaterPoly@Changchun");
//然后去请求得到一个ID
axios.post("url" + "/tempLayersSet.json", layerParam)
.then(res => {
//首先请求tempLayersSet得到一个结果ID,在根据结果ID拿到基础的参数配置
let id = res.newResourceID;
layer.getSource().tileLoadFunction = function (imageTile, src) {
imageTile.getImage().src = src + "&layersID=" + id;
}
})
.catch(err => {
console.log('错误' + err)
})
效果如下
可以看到和一开始加载的服务不一样了,这个里面只有一个水系的图层了。
接下来通过参数中的displayFilter可以控制水系图层根据条件只显示几个要素。
测试只显示smid<10的要素
//条件替换初始参数
layerParam[0].subLayers.layers = layerParam[0].subLayers.layers.filter(t => t.name == "WaterPoly@Changchun");
layerParam[0].subLayers.layers[0].displayFilter="SmID<10"
//然后去请求得到一个ID
axios.post("url" + "/tempLayersSet.json", layerParam)
.then(res => {
//首先请求tempLayersSet得到一个结果ID,在根据结果ID拿到基础的参数配置
let id = res.newResourceID;
layer.getSource().tileLoadFunction = function (imageTile, src) {
imageTile.getImage().src = src + "&layersID=" + id;
}
})
.catch(err => {
console.log('错误' + err)
})
预研的结果就讲完了,其实关于加载底图、查询、以及空间过滤,超图的iclientAPI都有现成的方法,
这些方法的确方便不少,但是我的想法还是除了地图的调用用它的方法,这些方法到最后其实也是请求这些接口来完成操作,所以我想要搞清他后面最终怎么操作的,然后自己去实现,这样对于系统的功能业务开发也比较灵活。