任务准备
- 安装AntD并实现按需加载
- 安装esri-leaflet和leaflet
具体任务
- 主组件中加载一个矢量地图并确定三个功能按钮:
- 清除选区:移除在当前地图上已经绘制的选区
- 圈选查询:在地图上以鼠标交互方式绘制圆形选区,并利用绘制结果进行空间查询
- 多变形查询:在地图上以鼠标交互方式绘制多边形选区,并利用绘制结果进行空间查询
- 查询结果以AntD-drawer组件为容器,展示结果的属性表
运行效果
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/8817156a940353226b39d463e74fa5c8.png#pic_center)
基本代码
组件css
#map_interactspatialquerytask {
width: 100%;
height: 800px;
position: relative;
}
.toolbar {
position: absolute;
top: 50px;
right: 50px;
}
组件jsx
import React, { useEffect, useState } from 'react';
import L from "leaflet";
import * as esri from "esri-leaflet"
import { Button } from 'antd';
import PropertiesTable from "../testPopup/PropertiesTable";
import DrawCircleGraphHandler from './DrawCircleGraphHandler';
import DrawPolygonGraphHandler from "./DrawPolygonGraphHandler";
import "./InteractSpatialQueryTask.css"
function InteractSpatialQueryTask(props) {
const [layer, setLayer] = useState(undefined);
const [tablevisuable, setTablevisuale] = useState(undefined);
const [features,setFeatures] = useState(undefined);
const [circleHandler, setCircleHandler] = useState(undefined);
const [polygonHandler, setPolygonHandler] = useState(undefined);
useEffect(()=>{
let map = L.map("map_interactspatialquerytask", {crs : L.CRS.EPSG3395}).setView([29.779, 106.384],12)
let layer = esri.featureLayer({url: "http://localhost:6080/arcgis/rest/services/02_Tky_GDCGK/FeatureServer/4",
pointToLayer: (geojson, latlng)=> {
return L.circleMarker(latlng, {radius : 5, color:"#567495"})
}})
layer.addTo(map)
setLayer(layer)
let circleHandler = new DrawCircleGraphHandler(map)
setCircleHandler(circleHandler)
let polygonHandler = new DrawPolygonGraphHandler(map)
setPolygonHandler(polygonHandler);
},[])
const _clear_selection = () => {
if(circleHandler)
circleHandler.clearCircle()
if(polygonHandler)
polygonHandler.clearPolygon()
}
const _draw_cricle = () => {
_clear_selection();
circleHandler.drawCircle({color: '#ff0000', fillColor: '#558800', fillOpacity: 0.5}, (center,radius,circle)=>{
layer.query().nearby(center, radius).run((error,results) => {
if(results.features){
setFeatures(results.features)
setTablevisuale(true)
}
})
})
}
const _draw_ploygon = () => {
_clear_selection();
polygonHandler.drawPolygon({color: '#ff0000', fillColor: '#558800', fillOpacity: 0.5}, (vertex,polygon)=>{
layer.query().within(polygon).run((error,results) => {
if(results.features){
setFeatures(results.features)
setTablevisuale(true)
}
})
})
}
const onTableClose = () => {
setTablevisuale(false);
}
return (
<div id = "map_interactspatialquerytask">
<Button.Group className = "toolbar">
<Button type = "dashed" onClick = {_clear_selection}>清除选择</Button>
<Button type = "primary" onClick = {_draw_cricle}>圆形选择区</Button>
<Button type = "primary" onClick = {_draw_ploygon}>多边形选择区</Button>
</Button.Group>
<PropertiesTable
visible = {tablevisuable}
features = {features}
closeCallback = {onTableClose}>
</PropertiesTable>
</div>
);
}
export default InteractSpatialQueryTask;
AntD_Drawer实现的查询结果列表展示组件
import React from 'react';
import { Drawer, Table, Card } from 'antd';
function PropertiesTable(props) {
const _generateColumns = (props) => {
return Object.keys(props.features[0].properties).map((value, index) => {
return {
title: value,
key: value,
dataIndex: value,
}
})
}
const _generateContext = (props) => {
return props.features.map((value, index) => { return { ...value.properties, key: index } })
}
const _drawTable = (props) => {
if (props.features && props.features.length > 0) {
return (
<Table
size="small"
dataSource={_generateContext(props)}
columns={_generateColumns(props)}>
</Table>
)
}
else
return <Card size="default" style={{ width: "100%" }}><p>没有数据</p></Card>
}
return (
<Drawer
onClose={() => { props.closeCallback() }}
visible={props.visible}
title="属性表"
getContainer={true}
placement="bottom">
{_drawTable(props)}
</Drawer>
);
}
export default PropertiesTable;
点选查询帮助类
import L from "leaflet";
export default class DrawCircleGraphHandler {
constructor(map) {
this.map = map
this.resultAOI = undefined;
}
onmouseDown = (e, style) => {
this.clearCircle();
this.resultAOI = L.circle(e.latlng, style).addTo(this.map);
}
onmouseUp = (e, callback) => {
this.resultAOI.setRadius(L.latLng(e.latlng).distanceTo(this.resultAOI.getLatLng()))
callback(this.resultAOI.getLatLng(), this.resultAOI.getRadius(), this.resultAOI)
this.map.dragging.enable();
this.map.off('mousedown', this.onmouseDownDecore);
this.map.off('mouseup', this.onmouseUpDecore);
this.map.off('mousemove', this.onmouseMove)
}
onmouseMove = (e) => {
if (this.resultAOI) {
this.resultAOI.setRadius(L.latLng(e.latlng).distanceTo(this.resultAOI.getLatLng()))
}
}
clearCircle() {
if (this.resultAOI) {
this.resultAOI.remove();
this.resultAOI = undefined;
}
}
drawCircle(style, callback) {
this.onmouseUpDecore = (e) => { this.onmouseUp(e, callback) }
this.onmouseDownDecore = (e) => { this.onmouseDown(e, style) }
this.map.dragging.disable();
this.map.on('mousedown', this.onmouseDownDecore);
this.map.on('mouseup', this.onmouseUpDecore);
this.map.on('mousemove', this.onmouseMove)
}
}
多边形查询帮助类
import L from "leaflet";
export default class DrawPolygonGraphHandler {
constructor(map) {
this.map = map;
this.resultAOI = undefined;
this.tempGraphLayer = undefined;
this.timer = undefined;
}
onClick = (e, style) => {
clearTimeout(this.timer)
this.timer = setTimeout(() => {
if (this.map.hasLayer(this.resultAOI))
this.resultAOI.addLatLng([e.latlng.lat, e.latlng.lng])
else
this.resultAOI = L.polygon([[e.latlng.lat, e.latlng.lng]], style).addTo(this.map)
})
}
onDblclick = (e, callback) => {
if (this.tempGraphLayer) {
this.map.removeLayer(this.tempGraphLayer)
this.tempGraphLayer = undefined;
}
callback(this.resultAOI.getLatLngs()[0], this.resultAOI)
this.map.dragging.enable();
this.map.off('click', this.onClickDecorate);
this.map.off('dblclick', this.onmouseUpDecore);
this.map.off('mousemove', this.onMoveDecorate)
}
onMove = (e, style) => {
if (this.resultAOI && this.resultAOI.getLatLngs() && this.resultAOI.getLatLngs().length > 0) {
let tempVertex = [...this.resultAOI.getLatLngs()[0], e.latlng]
if (this.map.hasLayer(this.tempGraphLayer))
this.tempGraphLayer.setLatLngs(tempVertex)
else
this.tempGraphLayer = L.polygon(tempVertex, style).addTo(this.map)
}
}
clearPolygon() {
if (this.resultAOI) {
this.resultAOI.remove();
this.resultAOI = null;
}
}
drawPolygon(style, callback) {
this.onDblclickDecorate = (e) => { this.onDblclick(e, callback) }
this.onClickDecorate = (e) => { this.onClick(e, style) }
this.onMoveDecorate = (e) => { this.onMove(e, style) }
this.map.dragging.disable();
this.map.on('click', this.onClickDecorate);
this.map.on('dblclick', this.onDblclickDecorate);
this.map.on('mousemove', this.onMoveDecorate)
}
}