起因
项目原有的二维数据很多,需要针对用户注册的二维服务在 Cesium 上进行属性查询的功能(注意这些二维服务都是 Arcgis 的 MapServer)
PS:这种查询方法也适用于所有不是 Arcgis for JS API 框架的其他地图框架
思路
1、通过 info/iteminfo 获取数据的 extend(这里需要留意数据的坐标系,如果坐标系不对,还需要通过其他方法进行坐标系转换,这里就不赘述了)
2、获取到数据的 extent 后就可以进行查询了,查询的方法主要有两种 Query 和 Identify(图查属性)
若是需要属性查找则使用 find(这里暂时不赘述)
Query
Arcgis 中的 query 是精确查询,可以通过输入图形(几何)、属性(字符串)进行精确查询,但是缺点是只能针对单个图层进行查询
必传字段
- geometry
- 这里是把你进行查询的图形要素进行传入
- geometryType
- 传入的图形类型
- 语法下方有,这里不赘述
- inSR
- 输入几何体的空间参考。
4326
- spatialRel
- 在执行查询时要应用在输入几何体上的空间关系。支持的空间关系包括相交、包含、包络相交、内部等。默认的空间关系是相交
esriSpatialRelIntersects | esriSpatialRelContains | esriSpatialRelCrosses | esriSpatialRelEnvelopeIntersects | esriSpatialRelIndexIntersects | esriSpatialRelOverlaps | esriSpatialRelTouches | esriSpatialRelWithin | esriSpatialRelRelation
- where
- 一个用于查询过滤器的 where 子句。任何合法的 SQL where 子句都可以对层中的字段进行操作
1=1
--查找全部POP2000 > 350000
--POP2000 是该图层中其中的字段
- outFields
- 返回的结果集中包含的字段列表。
*
返回所有POP2000
只返回 POP2000 这个字段的信息
- outSR
- 返回几何体的空间参考。
4326
Identify
Arcgis 中 Identify 是可以进行多图层查询的,是模糊查询,用户需要传入 Geometry 图形数据进行查询
必传字段
- geometry
- 这里是把你进行查询的图形要素进行传入
- geometryType
- 传入的图形类型
- 语法下方有,这里不赘述
- sr
- 传入数据的坐标系
{wkid:4326}
- layers
- 要查询的图层
[top | visible | all]:layerId1,layerId2
- tolerance
- 以屏幕像素为单位的距离,在此范围内应进行识别的指定几何体。容差的值是一个整数。
2
- mapExtent
- 当前正在查看的地图的范围或边界框,一般直接传 info 中的 extent 即可
-104,35.6,-94.32,41
- returnGeometry
- 是否返回几何要素
true
- imageDisplay
- 目前正在查看的地图的屏幕图像显示参数(宽度、高度和 DPI)
- PS: mapExtent 和 imageDisplay 参数被服务器用来确定在当前范围内可见的层。它们还被用来计算地图上的距离,以便根据屏幕像素的公差进行搜索。
1920,1080,96
共同踩坑点
这里每次都会忘记要怎么传 Geometry,这里记录一下 ArcGIs 网站参考
- geometryType=esriGeometryEnvelope(范围)
{xmin: -104, ymin: 35.6, xmax: -94.32, ymax: 41}
- geometryType=esriGeometryPoint(点的三种方式都可以)
-104,35.6
{x: -104, y: 35.6}
{ "x": -118.15, "y": 33.80, "spatialReference": { "wkid": 4326 } }
- esriGeometryMultipoint(多点)
{ "points": [ [ -97.06138, 32.837 ], [ -97.06133, 32.836 ], [ -97.06124, 32.834 ], [ -97.06127, 32.832 ] ], "spatialReference": { "wkid": 4326 } }
- esriGeometryPolyline
{ "paths": [ [ [-97.06138,32.837], [-97.06133,32.836], [-97.06124,32.834], [-97.06127,32.832] ], [ [-97.06326,32.759], [-97.06298,32.755] ] ], "spatialReference": {"wkid": 4326} }
- esriGeometryPolygon (面)
{ "rings": [ [ [-97.06138,32.837], [-97.06133,32.836], [-97.06124,32.834], [-97.06127,32.832], [-97.06138,32.837] ], [ [-97.06326,32.759], [-97.06298,32.755], [-97.06153,32.749], [-97.06326,32.759] ] ], "spatialReference": { "wkid": 4326 } }
{ "rings" : [ [ [ -96.929599633999942, 38.52426809800005 ], [ -96.929602437999961, 38.522448437000037 ], [ -96.92959118999994, 38.529723252000053 ], [ -96.929594022999936, 38.527905578000059 ], [ -96.929596839999988, 38.526087119000067 ], [ -96.929599633999942, 38.52426809800005 ] ] ] }
案例代码
在发起查询请求的时候,建议都用 post 请求,因为如果直接用 get 请求,url 的长度是有限制的,而且直接用 get 请求相对来说也不是很安全,因此建议直接都用 post 请求
jsx
//案例
// 思路很简单,先获取服务的extent,再根据这个txtent去进行identify获取识别到的多图层要素
const item.url = 'xxx/xxx/xxx/MapServer'
const getExtenUrl = `${item.url}/info/iteminfo?f=pjson`;
fetch(getExtenUrl)
.then((response) => response.json())
.then((res) => {
const extent = res.extent[0][0] + ',' + res.extent[0][1] + ',' + res.extent[1][0] + ',' + res.extent[1][1];
const requestUrl = `${item.url}/identify`;
const params = {
f: 'pjson',
tolerance: 2,
returnGeometry: false,
geometry: JSON.stringify(
{
x: degreePosition.longitude,
y: degreePosition.latitude,
spatialReference: {
wkid: 4326,
},
}
),
geometryType: 'esriGeometryPoint',
mapExtent: extent,
imageDisplay: '1920,1080,96',
sr: 4326,
layers: 'all',
};
// post数据以表单形式存储
const formData = new FormData();
Object.keys(params).forEach((key) => {
formData.append(key, params[key]);
});
fetch(requestUrl, {
method: 'POST',
body: formData,
})
.then((response) => response.json())
.then((res) => {
console.log('res1111111111', res);
if (res.results.length > 0) {
const featureList = res.results.map((item) => {
const feature = {
layerName: item.layerName,
attributes: item.attributes,
};
return feature;
});
console.log('featureList', featureList);
// 这里可以根据自己的需求进行处理
// 例如:弹出一个弹窗,展示查询到的要素信息
}
});
})