Fellow Travellers

超图WebGL属性查询

吴伟豪
字数统计: 2.4k阅读时长: 10 min
2019/08/23 Share

超图webGL属性查询

一、 属性查询

  超图webGL属性查询是根据对应发布的iserver服务来进行的查询,通过iServer REST API接口实现数据,分析,三维等资源的获取。
根据目前项目需求经验总结,当前使用到的属性查询主要分为以下三种类型:

  • 点查询,适用于单一图层数据,通过点击获取对象id来进行属性查询。
  • 拉框查询,适用于多图层数据,通过设置查询范围构建查询体,与图层进行空间分析获取对象id来进行属性查询。
  • 通用sql查询,适用于通过设置数据属性字段条件来进行查询的情况。

    二、 属性查询流程

    image

    三、 属性查询实现过程

    3.1 点选初始化
      以点选(buffer)初始化为例,多图层点选采用拉框查询的流程,根据点选位置生成缓冲区来模拟拉框的范围来进行查询。主要初始变量包括:
  • baseUrl:基础服务地址。
  • infos:所有打开的图层信息集合,通过与基础服务地址进行组装来构成查询地址。具体结构如下:

    1
    2
    3
    4
    5
    6
    0:
    caption: "用地规划" //图层标题
    dataName: "BZY_YDGH_PY" //图层所在数据源名称
    dataSource: "aa" //图层所在数据集名称
    dataTitle: "XYZTGH-qxn" //图层所在工作空间服务名称
    layerName: "BZY_YDGH_PY@aa#1" //图层名称
  • isAlias:是否获取中文别名,超图webGL默认无法直接获取到对象的中文别名,所以需要增加一步别名处理。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //点选(buffer)初始化
    setBufferHandler = (baseUrl, infos, isAlias, callBack) => {
    this.baseUrl = baseUrl;
    this.infos = infos;
    this.isAlias = isAlias;
    let actionHandler = ActionHandler.getInstance(this.viewer)
    actionHandler.setHandler(ACTION.POINT, result => {
    actionHandler.drawHandler.clear()
    actionHandler.drawHandler.activate()
    let cartesian3 = result.object.position
    let center = convert.cartesian3ToDegrees(cartesian3)
    this.bottomHeight = center.height
    let points = convert.centerBuffer(center, 0.000150)
    var promise = this._execute("range", points)
    callBack(promise)
    });
    };
3.2 区分查询方式

  由于查询操作中牵涉到多个异步查询,通过构造Promise对象来使用能够很好的解决代码逻辑混乱以及查询结果状态记录的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
_execute(type, points) {
var pri = new Promise((resolve, reject) => {
if (this.infos.length == 0) {
reject("请先打开专题图层")
} else {
if (type == "point") {
this._pointQuery(resolve, reject)
} else if (type == "sql") {
this._sqlQuery(resolve, reject, points)
} else {
this._regionQuery(resolve, reject, points)
}
}
})
return pri
}
3.3 不同数据形式分别处理

  在项目实际使用过程中发现直接根据图层的ID查询模式来进行属性的获取时,无法控制几何信息的返回状态,默认是返回Geometry。但是针对一些精细模型方案,几何点数往往达到千万级别,造成查询速度过慢甚至页面直接崩溃的情况,所以需要根据获取到的图层数据形式来进行区分,采用不同的查询方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 根据 数据形式:MODEL 和REGION 分别处理
_regionQuery(resolve, reject, points) {
var allPromises = [];
for (let k = 0; k < this.infos.length; k++) {
let info = this.infos[k];
let url =
this.baseUrl +
"data-" +
info.dataTitle +
"/rest/data/datasources/" +
info.dataSource +
"/datasets/" +
info.dataName +
".json";
var promise = fetchGet(url, {})
.then(data => {
let type = data.datasetInfo.type;
if (type == "MODEL") {
return this._queryModel(info, points).then(res => {
return this._featureQuery(res.ids, info, "SQL")
});
} else {
return this._featureQuery(points, info, "SPATIAL");
}
})
.then(res => {
return this._standardInfo(res, info)
})
.then(res => {
return this._getALias(res)
})
allPromises.push(promise)
}
Promise.all(allPromises)
.then(results => {
var r = results.filter(item => item.length!==0)
resolve(r)
})
.catch(err => {
reject(err)
});
}
  • iserver接口为:dataset(数据集)。
  • 对 dataset 资源执行 GET 请求获得该数据集的详细信息(datasetInfo)和子资源列表(childUriList)。
  • 通过datasetInfo中的type属性来判断数据集是否为模型数据集。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    //  featureResult 查询. 目前使用 id,spatial,sql 三种
    _featureQuery(parm, info, type) {
    let infoStr = info.dataSource + ":" + info.dataName;
    let params = {};
    if (type == "Point") {
    params = {
    getFeatureMode: "ID",
    datasetNames: [infoStr],
    ids: parm
    };
    } else if (type == "SPATIAL") {
    let geometry = {
    points: parm,
    type: "REGION",
    parts: [1],
    id: 0
    };
    params = {
    getFeatureMode: "SPATIAL",
    datasetNames: [infoStr],
    toIndex: -1,
    geometry: geometry,
    spatialQueryMode: "INTERSECT"
    };
    } else if (type == "SQL") {
    var sql =""
    for(var i=1;i<parm.length;i++){
    sql = sql + " or "+"SMID=" + parm[i]
    }
    let sqlCondition = "SMID=" + parm[0] + sql
    params = {
    getFeatureMode: "SQL",
    datasetNames: [infoStr],
    maxFeatures: 100,
    queryParameter: {
    attributeFilter: sqlCondition
    },
    hasGeometry: false
    }
    }
    let uri =
    this.baseUrl +
    "data-" +
    info.dataTitle +
    "/rest/data/featureResults.rjson" +
    "?returnContent=true";
    return fetchPost(uri, params)
    }
  • iserver接口为:featureResults(数据查询结果的集合)。

  • 通过对该资源执行 POST 请求,可以对数据源中的数据进行查询,获取符合条件的要素集合。
  • URI 中的参数
名称 含义
returnContent true 表示直接返回查询结果,即元素类型为 Feature 的数组;false 表示返回创建的 featureResult 资源的 URI。默认不传时为 false。
fromIndex 查询结果的最小索引号。默认值是0,如果该值大于查询结果的最大索引号,则查询结果为空。
toIndex 查询结果的最大索引号。如果该值大于查询结果的最大索引号,则以查询结果的最大索引号为终止索引号。
  • 请求体参数(params)
名称 含义
getFeatureMode 数据查询的模式(ID、SPATIAL、SQL等)
datasetNames 数据集名称,由数据源名和数据集名构成
ids 查询资源的 ID 数组。(ID查询模式必选)
geometry 几何对象(SPATIAL查询模型必选)
queryParameter 查询参数(SQL查询必选)
hasGeometry 是否返回几何对象。默认为true。当 getFeatureMode 不为 ID 时,且 URL 参数 returnContent=true 时,hasGeometry 有效。
3.5 查询结果格式化处理

  根据项目的需求总结,将每个图层对象查询结果进行统一的格式化处理。需要注意的是,由于使用了Promise.all的方法,针对多图层中查询没有返回结果的情况,也需要把结果放置进resolve中,再最后进行统一的剔除。不然会直接忽略掉正确结果而返回失败的处理流程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//每一个对应info下的查询结果格式化
_standardInfo(res, info) {
return new Promise((resolve, reject) => {
if (res.features.length == 0) {
resolve([])
} else {
let finalResult = {
info: info,
features: []
};
for (var i in res.features) {
let feature = res.features[i]
let dealedFeature = {}
dealedFeature.bounds = {};
dealedFeature.attributes = [];
dealedFeature.geometry = feature.geometry
for (var k = 0; k < feature.fieldNames.length; k++) {
let field = feature.fieldNames[k];
let value = feature.fieldValues[k];
switch (field) {
case "SMSDRIW":
dealedFeature.bounds.west = value;
break;
case "SMSDRIN":
dealedFeature.bounds.north = value;
break;
case "SMSDRIE":
dealedFeature.bounds.east = value;
break;
case "SMSDRIS":
dealedFeature.bounds.south = value;
break;
case "SMID":
dealedFeature.id = value;
break;
default:
let attribute = {
field: field,
value: value
};
dealedFeature.attributes.push(attribute);
}
if (k == feature.fieldNames.length - 1) {
finalResult.features.push(dealedFeature)
}
}
}
resolve(finalResult)
}
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// 获取中文别名
_getALias(origin) {
return new Promise((resolve, reject) => {
if(this.isAlias){
if(origin.features == undefined){
resolve([])
}else{
let fieldUrl =
this.baseUrl +
"data-" +
origin.info.dataTitle +
"/rest/data/datasources/" +
origin.info.dataSource +
"/datasets/" +
origin.info.dataName;


for (let k = 0; k < origin.features.length; k++) {
let feature = origin.features[k];
let attributes = feature.attributes
var allPromises = [];
for (let m = 0; m < attributes.length; m++) {
let originAtt = attributes[m];
let field = originAtt.field;
var pros = fetchGet(fieldUrl + "/fields/" + field + ".json");
allPromises.push(pros);
}
Promise.all(allPromises)
.then(respons => {
for (var p in respons) {
let alias = respons[p].fieldInfo.caption;
if (escape(alias).indexOf("%u") >= 0) {
attributes[p].field = alias
}
}
var i = attributes.length;
while(i--){
let alias = attributes[i].field;
if(escape(alias).indexOf("%u") < 0){
attributes.splice(i,1);
}
}
resolve(origin)
}).catch(err => {
reject(err)
})
}
}
}else{
resolve(origin)
}
})
}
  • iserver接口为:field(表示一个数据集中的一个字段)。
  • 通过GET请求获取字段信息。字段的信息包括:字段名称,字段类型,字段别名,字段默认值,字段是否允许为空,字段最大长度,是否允许长度为零等。
3.6 最终查询结果格式

最终查询结果主要包含内容为:

  • attributes:查询对象属性信息,包含属性名称和属性值。
  • bounds:属性对象范围信息,主要针对查询定位使用。
  • geometry:属性对象几何信息,如不返回默认为空。
  • id:属性对象id。
  • info:属性对象图层相关信息,主要用来组装查询体的URL。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
attributes: (19) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, 
bounds:
east: "104.91437"
north: "25.10888"
south: "25.108274"
west: "104.913704"
geometry: null
id: "2"
info:
caption: "XYZXA@XYZX1"
dataName: "XYZXA"
dataSource: "XYZX1"
dataTitle: "XYZXA"
layerName: "XYZXA@XYZX1"

总结  

    属性查询在GIS系统中属于比较基础但又十分重要的模块,目前总结的三种情况基本满足在超图webGL开发中的使用。当然,在使用中也要根据实际情况采取更加合适的方法来实现。例如文中提到的针对一些比较精细复杂的三维模型对象,就要使用能够控制几何信息返回状态的方式来实现更快的查询。
    目前属性查询也同样的存在着一些问题,比如针对同一个数据集中所有的对象进行遍历获取,查询速度十分缓慢,并且会造成服务器内存的飙升。期待超图以后对这方面的优化,也期待大家的方法补充。

CATALOG
  1. 1. 超图webGL属性查询
    1. 1.1. 一、 属性查询
    2. 1.2. 二、 属性查询流程
    3. 1.3. 三、 属性查询实现过程
      1. 1.3.0.0.1. 3.1 点选初始化
      2. 1.3.0.0.2. 3.2 区分查询方式
      3. 1.3.0.0.3. 3.3 不同数据形式分别处理
      4. 1.3.0.0.4. 3.5 查询结果格式化处理
      5. 1.3.0.0.5. 3.6 最终查询结果格式
  • 1.4. 总结