作者:ls
【目录】
- 背景
- 前期准备
- 呈现效果
- 实现过程
- 完整代码
【背景】
几何查询是WebGIS项目中一项比较常用的功能,SuperMap iClient 产品支持的几何对象类型众多,能够满足用户的许多需求。
近期遇到许多小伙伴反应,绘制圆形进行几何查询却得不到预期结果。这是因为 GeoJSON 规范中不支持圆,在主流框架下绘制的圆形并非面对象(Polygon),而是由圆心和半径定义得到的一个圆对象。为了实现圆形查询,就需要将圆对象转化为面对象,接下来让我们看一下实现效果和具体过程:
(1)添加绘制控件;
(2)获取绘制结果并利用插件生成面对象;
(3)将面对象传入几何对象查询,在地图上呈现结果。
【前期准备】
①地图服务:https://iserver.supermap.io/iserver/services/map-world/rest/maps/World
②所需插件:leaflet.draw、leaflet-geoman
【呈现效果】
【实现过程】
(1)引入必要文件
<script type="text/javascript" include="leaflet.draw" src="../../dist/leaflet/include-leaflet.js"></script>
<script src="https://unpkg.com/@geoman-io/leaflet-geoman-free@latest/dist/leaflet-geoman.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@geoman-io/leaflet-geoman-free@latest/dist/leaflet-geoman.css" />
(2)加载地图服务
var map, url = "https://iserver.supermap.io/iserver/services/map-world/rest/maps/World";
map = L.map('map', {
crs: L.CRS.EPSG4326,
center: [0, 0],
maxZoom: 18,
zoom: 1
});
new L.supermap.TiledMapLayer(url).addTo(map);
(3)定义查询功能
function query(lat,lng,r) {
// 利用传入的经纬度和半径值构造一个L.circle对象
var circle = L.circle([lat,lng], {color: 'red',radius:r});
// 借助circleToPolygon()方法,将L.circle转换为L.polygon,其中第二个参数为polygon边的数量
var polygon = L.PM.Utils.circleToPolygon(circle, 600);
var param = new L.supermap.QueryByGeometryParameters({
queryParams: {name: "Capitals@World.1"},
geometry: polygon
});
new L.supermap
.QueryService(url)
.queryByGeometry(param, function (serviceResult) {
var result = serviceResult.result;
var count = result.totalCount;
resultLayer = L.geoJSON(result.recordsets[0].features).addTo(map);
var popup = L.popup().setLatLng([lat,lng]).setContent('半径约为:'+ (r/1000).toFixed(2) +'千米<br/>结果数量:'+count+'个').openOn(map);
});
}
(4)加载绘制工具,仅开启圆形绘制功能
var editableLayers = new L.FeatureGroup();
map.addLayer(editableLayers);
var options = {
position: 'topleft',
draw: {
polyline: false,
polygon: false,
circle: {},
rectangle: false,
marker: false,
remove: false
},
edit: {
featureGroup: editableLayers,
remove: false
}
};
var drawControl = new L.Control.Draw(options);
map.addControl(drawControl);
(5)添加绘制触发事件方法
handleMapEvent(drawControl._container, map);
map.on(L.Draw.Event.CREATED, function (e) {
var type = e.layerType,
layer = e.layer;
if (type === 'marker') {
layer.bindPopup('A popup!');
}
editableLayers.addLayer(layer);
// 获取绘制圆形的半径、圆心经纬度,并传入query()方法
var r = layer._mRadius;
var lat = layer._latlng.lat;
var lng = layer._latlng.lng;
query(lat,lng,r);
});
【完整代码】
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title data-i18n="resources.title_tiledMapLayer4326"></title>
<script type="text/javascript" src="../js/include-web.js"></script>
</head>
<body style=" margin: 0;overflow: hidden;background: #fff;width: 100%;height:100%;position: absolute;top: 0;">
<div id="map" style="margin:0 auto;width: 100%;height: 100%"></div>
<script type="text/javascript" include="leaflet.draw" src="../../dist/leaflet/include-leaflet.js"></script>
<script src="https://unpkg.com/@geoman-io/leaflet-geoman-free@latest/dist/leaflet-geoman.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@geoman-io/leaflet-geoman-free@latest/dist/leaflet-geoman.css" />
<script type="text/javascript">
var map, url = "https://iserver.supermap.io/iserver/services/map-world/rest/maps/World";
map = L.map('map', {
crs: L.CRS.EPSG4326,
center: [0, 0],
maxZoom: 18,
zoom: 1
});
new L.supermap.TiledMapLayer(url).addTo(map);
function query(lat,lng,r) {
// 利用传入的经纬度和半径值构造一个L.circle对象
var circle = L.circle([lat,lng], {color: 'red',radius:r});
// 借助circleToPolygon()方法,将L.circle转换为L.polygon,其中第二个参数为polygon边的数量
var polygon = L.PM.Utils.circleToPolygon(circle, 600);
var param = new L.supermap.QueryByGeometryParameters({
queryParams: {name: "Capitals@World.1"},
geometry: polygon
});
new L.supermap
.QueryService(url)
.queryByGeometry(param, function (serviceResult) {
var result = serviceResult.result;
var count = result.totalCount;
resultLayer = L.geoJSON(result.recordsets[0].features).addTo(map);
var popup = L.popup().setLatLng([lat,lng]).setContent('半径约为:'+ (r/1000).toFixed(2) +'千米<br/>结果数量:'+count+'个').openOn(map);
});
}
var editableLayers = new L.FeatureGroup();
map.addLayer(editableLayers);
var options = {
position: 'topleft',
draw: {
polyline: false,
polygon: false,
circle: {},
rectangle: false,
marker: false,
remove: false
},
edit: {
featureGroup: editableLayers,
remove: false
}
};
var drawControl = new L.Control.Draw(options);
map.addControl(drawControl);
handleMapEvent(drawControl._container, map);
map.on(L.Draw.Event.CREATED, function (e) {
var type = e.layerType,
layer = e.layer;
if (type === 'marker') {
layer.bindPopup('A popup!');
}
editableLayers.addLayer(layer);
// 获取绘制圆形的半径、圆心经纬度,并传入query()方法
var r = layer._mRadius;
var lat = layer._latlng.lat;
var lng = layer._latlng.lng;
query(lat,lng,r);
});
function handleMapEvent(div, map) {
if (!div || !map) {
return;
}
div.addEventListener('mouseover', function () {
map.scrollWheelZoom.disable();
map.doubleClickZoom.disable();
});
div.addEventListener('mouseout', function () {
map.scrollWheelZoom.enable();
map.doubleClickZoom.enable();
});
}
</script>
</body>
</html>
代码运行方式:
①在线编辑器:将完整代码复制到 SuperMap iClient 在线示例中运行;
②本地运行:保存完整代码为html文件,将其放置于iServer安装目录\iClient\forJavaScript\examples\leaflet,然后运行该示例。