客户端空间查询
在地理信息系统中,空间查询有的非常重要的作用,几乎所有地图相关的业务系统都需要空间查询。
空间查询一般指:基于空间数据的查询,一般包括点选、线段查询、多边形查询、缓冲分析、范围查询等。
由于空间数据的特殊原因,空间查询往往基于服务端系统,通过数据库进行查询,构建索引之后,查询速度会有很大的提升。
但是对于一些简易的地图业务系统,不依赖空间数据库,因此不能使用服务端的空间查询。
在之前的业务系统中,遇到过类似的空间查询场景,解决办法一般是使用 turf
或者 jsts
来实现客户端空间查询;
昨天偶然发现 Openlayers
的矢量图层(VectorSource
)自带一些空间查询方法,可以实现简单的空间查询。
Openlayers 可以实现的空间查询:点选查询和范围查询。
本文包括两部分。
核心代码
1. 应用函数
2. 创建随机数据,包括点线面数据。
// 默认范围
const bbox = [115.44400430633583, 39.20776490257249, 117.44351602508583, 40.84472779319749];
let number = 30;
// 模拟随机点数据
const points = turf.randomPoint(
// 模拟数量
number,
{
// 范围
bbox: bbox
})
// 模拟随机线段数据
const lineStrings = turf.randomLineString(
// 模拟数量
number,
{
// 范围
bbox: bbox,
// 顶点数量
num_vertices: 10,
// 最大长度
max_length: 0.1,
// 最大角度
max_rotation: Math.PI / 8
})
// 模拟随机多边形
const polygons = turf.randomPolygon(
// 模拟数量
number,
{
// 范围
bbox: bbox,
// 最大辐射长度
max_radial_length: 0.1,
// 顶点数量
num_vertices: 10
})
const randomObject = {
'Point': points,
'LineString': lineStrings,
'Polygon': polygons,
}
// 清空数据,添加数据
layerQuery.getSource().clear();
layerQuery.getSource().addFeatures(getFeatureByGeoJson(randomObject.Point));
layerQuery.getSource().addFeatures(getFeatureByGeoJson(randomObject.LineString));
layerQuery.getSource().addFeatures(getFeatureByGeoJson(randomObject.Polygon));
- 创建标绘事件。
注意:这里的事件类型只有 Point
和 Extent
,并且 Extent
需要 Circle
和 ol.interaction.Draw.createBox(4)
let geometryFunction = ol.interaction.Draw.createBox(4);
drawObject = new ol.interaction.Draw({
source: layer.getSource(),
type: type,
geometryFunction: type === 'Circle' ? geometryFunction : undefined,
});
3. 判断是否相交。
这里需要注意的是,由于点选是点数据的原因,选中点数据和线段数据的难度比较大,因此这里使用的是获取最近的数据。
而且,判断只留下 200
米以内的数据;这里的判断也可以根据 zoom
值来调整,比如地图等级 10 级的时候设置 500 米以内。
// 确定容差范围:200米
function available(feature1, feature2) {
const line = new ol.geom.LineString(
[feature1.getGeometry().getCoordinates(),
feature2 instanceof Array ? feature2 : feature2.getGeometry().getCoordinates()]);
const len = ol.sphere.getLength(line, {projection: 'EPSG:4326'});
return len <= 200;
}
// 点选查询
if (e.feature.getGeometry().getType() === 'Point') {
// 获取最近的图形要素,这里给的范围为 200米以内的数据
feature = layerQuery.getSource().getClosestFeatureToCoordinate(
e.feature.getGeometry().getCoordinates());
// 点和线可以允许容差,多边形需要再内部才认为查询到
switch (feature.getGeometry().getType()) {
case 'Point':
if (!available(e.feature, feature)) {
feature = undefined;
}
break;
case 'LineString':
// getFeaturesAtCoordinate
const point = feature.getGeometry().getClosestPoint(e.feature.getGeometry().getCoordinates());
if (!available(e.feature, point)) {
feature = undefined;
}
break;
case 'Polygon':
if (!feature.getGeometry().intersectsCoordinate(e.feature.getGeometry().getCoordinates())) {
feature = undefined;
}
break;
}
// 改变样式
feature && feature.setStyle(selectedStyle);
// 范围查询
} else {
// 查询范围内数据
feature = layerQuery.getSource().getFeaturesInExtent(e.feature.getGeometry().getExtent());
}
在线示例
专门为地图开发人员准备的地图工具:在线地图工具
Openlayers api 实现空间查询:OpenLayers space query