Openlayers 教程 - 基于 Openlayers api 实现空间查询(客户端):点选、范围查询
- 客户端空间查询
- 核心代码
- 在线示例
客户端空间查询
在地理信息系统中,空间查询有的非常重要的作用,几乎所有地图相关的业务系统都需要空间查询。
空间查询一般指:基于空间数据的查询,一般包括点选、线段查询、多边形查询、缓冲分析、范围查询等。
由于空间数据的特殊原因,空间查询往往基于服务端系统,通过数据库进行查询,构建索引之后,查询速度会有很大的提升。
但是对于一些简易的地图业务系统,不依赖空间数据库,因此不能使用服务端的空间查询。
在之前的业务系统中,遇到过类似的空间查询场景,解决办法一般是使用 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':// getFeaturesAtCoordinateconst 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