react使用高德地图react-amap:Map、Markers、Circle、ContextMenu、自定义ContextMenu

本文主要是介绍react使用高德地图react-amap:Map、Markers、Circle、ContextMenu、自定义ContextMenu,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

React AMap — 基于 React 的高德地图组件

目录

搜索区域代码

地图区域代码

自定义菜单样式


复杂而且不好口述,直接上代码,后面出视频

搜索区域代码

// ------------------外部资源
import React, { useEffect } from 'react'
import { observer } from 'mobx-react-lite'
import { Form, Button, Input, Select } from 'antd'
const { Option } = Select
// ------------------内部公共
import SearchSelect from "react-antd-search-select";// ------------------内部私有
import store from '../../store'export default observer(() => {const [form] = Form.useForm()const onEmployeeChange = () => {form.setFieldsValue({ customerId: undefined })store.setStore({ customerId: '' })onSearchParamsChange()}// 搜索客户const onSearchParamsChange = () => {const data = form.getFieldsValue(true)data.area = undefineddata.range = undefinedif (data.employeeId) {store.setStore({ employeeId: data.employeeId })store.getCustomerLocationList(data)} else {store.setStore({employeeId: '',customerId: '',visitInfo: {},customerLocationList: []})}}// 客户const onCustomerChange = (value) => {store.setStore({ customerId: value })}// 重置const handleClear = () => {const employeeId = form.getFieldsValue(true).employeeIdform.resetFields()form.setFieldsValue({ employeeId })store.setStore({ customerId: null, range: undefined, area: '' })employeeId && store.getCustomerLocationList({ employeeId })}useEffect(() => {if (store.useInfo?.isSale) {form.setFieldsValue({employeeId: store.useInfo?.employeeId})store.getCustomerLocationList({ employeeId: store.useInfo?.employeeId })}}, [store.useInfo])useEffect(() => {form.setFieldsValue({ range: store.range, area: store.area })}, [store.range, store.area])return (<><div className="search-block"><Formlayout="inline"form={form}><Form.Item label="销售" name="employeeId"><SearchSelecturl="/api/selectEmployee"width={200}onChange={onEmployeeChange}/></Form.Item><Form.Item label="合作状态" name="customerSignType"><Select placeholder="请选择" allowClear onChange={onSearchParamsChange} style={{ width: 100 }}><Option value={0}>未合作</Option><Option value={1}>合作中</Option><Option value={2}>合作结束</Option></Select></Form.Item><Form.Item label="客户" name="customerId"><SearchSelectvalue={store.customerId}width={200}url="/customermap/search-customer.json"ajaxData={{initCondition: 'Init_LptCustomer',queryField: 'name',queryType: 'select_customer',isNeedPerssion: true,extendCondition: JSON.stringify([{"queryField":"creatorId","queryOption":"=","queryValue": store.employeeId}])}}onChange={onCustomerChange}/></Form.Item><Form.Item name="area"><Input placeholder="区域/地点" allowClearonChange={(e) => store.setStore({ area: e.target.value })} /></Form.Item><Form.Item name="range"><Select placeholder="周边" allowClear style={{ width: 100 }}onChange={(value) => store.setStore({ range: value })}><Option value={1}>1公里以内</Option><Option value={2}>2公里以内</Option><Option value={3}>3公里以内</Option><Option value={4}>4公里以内</Option><Option value={5}>5公里以内</Option></Select></Form.Item><Form.Item><Button onClick={handleClear}>清除</Button></Form.Item></Form></div><style jsx>{`.search-block {padding: 10px 20px;}`}</style></>)
})

地图区域代码

// ------------------外部资源
import React, { useState, useEffect, useRef } from 'react';
import { observer } from 'mobx-react-lite'
import { toJS } from "mobx";
import {Modal, Spin } from 'antd';
import { Map, Markers, Circle } from 'react-amap';
import { useDebounceFn } from "ahooks";
// ------------------内部公共
import EditVisitPlan from "@components/EditVisitPlan";
import mark_gray from '@static/images/mark_gray.png'
import mark_green from '@static/images/mark_green.png'
// ------------------内部私有
import store from '../../store'
import './index.less'
let currentMarkerData = {}
let markerMap = []
let MapsOption = {}// 自定义菜单
const CustomContextMenu = ({ coverLocations, mapsOption, showRange, addVisit, setCurrentMarkerData }) => {return (<ul className="custom-amap-menu"style={{left: mapsOption.pixel.x + 5,top: mapsOption.pixel.y}}>{coverLocations.map(item => {const row = JSON.parse(item)return <li key={row.customerId}><span>{row.customerName}</span><ul className="customer-menus"><li onClick={() => {setCurrentMarkerData?.(row)showRange?.()}}>显示周边范围</li><li onClick={() => {setCurrentMarkerData?.(row)addVisit?.()}}>增加拜访计划</li><li><a href={`/customer/todetail/?customerId=${row.customerId}&isinfoEdit=1`} target="_blank">重新维护地址</a></li><li><a href={`/customervisitplan/listall/?customer_id=${row.customerId}`} target="_blank">查看拜访记录</a></li><li><a href={`/customer/todetail/?customerId=${row.customerId}`} target="_blank">查看客户详情</a></li></ul></li>})}</ul>)
}export default observer(() => {const mapInstance = useRef(null); // created map 记录map实例instanceconst contextMenu = useRef(null); // 菜单const [zoom, setZoom] = useState(11) // 缩放const [coordinates, setCoordinates] = useState([]) // 当前坐标点const [radius, setRadius] = useState(0) // 半径范围rangeconst [markers, setMarkers] = useState([]) // Markers 数据const [visible, setVisible] = useState(false) // Circle 显示const [editVisitPlanVisible, setEditVisitPlanVisible] = useState(false) // 增加拜访计划显示const [customContextMenuVisible, setCustomContextMenuVisible] = useState(false) // 自定义菜单显示// 监听客户位置列表变化,控制地图显示useEffect(() => {getMarkers()store?.visitInfo?.city && debounceSetAddrLocation.run(store?.visitInfo?.city)}, [store.customerLocationList])// 监听客户变化useEffect(() => {if (markers.length && (store.customerId || store.customerId === 0)) {const customer = markers.find(item => {return item?.extData?.customerId === Number(store.customerId)})console.log('customer', customer);if (customer) {setZoom(16)setCoordinates(customer.position)store.setStore({ range: 3, customer })setVisible(true)setIconRed(customer, 500)} else {store.setStore({ customer: {} })Modal.warning({content: (<div>当前所选客户还没有坐标,<a href={`/customer/todetail/?customerId=${store.customerId}&isinfoEdit=1`} target="_blank">现在去维护</a></div>),okText: '取消'});}} else {setZoom(11)setCoordinates([116.397428, 39.90923])store.setStore({ range: undefined, customer: {} })setVisible(false)}}, [store.customerId])// 标红点const setIconRed = (customer, timeout) => {if (!Object.keys(store.customer).length) returnsetTimeout(() => {// 标红for(const item of markerMap) {if (customer?.extData?.isCover) {if (item?.w?.extData?.position.join() === customer?.position?.join()) {item.render(() => {return <img src='//webapi.amap.com/theme/v1.3/markers/n/mark_r.png' />})}} else {if (item?.w?.extData?.extData.customerId === customer?.extData?.customerId) {item.render(() => {return <img src='//webapi.amap.com/theme/v1.3/markers/n/mark_r.png' />})}}}}, timeout)}// 监听区域、地点变化,获取对应经纬点useEffect(() => {store?.area && debounceSetAddrLocation.run(store?.area);}, [store.area])// 监听周边变化,设置Circle⭕️半径useEffect(() => {setRadius(store.range * 1000)}, [store.range])// 监听经纬坐标、区域变化,控制Circle⭕️显示useEffect(() => {if (coordinates && store.area) {setZoom(16);setVisible(true)} else {setVisible(false)}}, [store.area])// 获取地图 Markersconst getMarkers = () => {const list = []for(const item of toJS(store.customerLocationList)) {const position = item.location?.split(',')if (position.length === 2) {list.push({position,extData: item})}}setMarkers(list)store.setStore({ area: '' })store.setStore({ range: undefined })}// render动态修改标记的外观iconconst renderMarkerFn = (extData) => {let icon = '//webapi.amap.com/theme/v1.3/markers/n/mark_bs.png'if (extData?.extData?.visitPlanStatus === 1) {icon = mark_gray} else if (extData?.extData?.visitPlanStatus === 2) {icon = mark_green}return <img src={icon} />};// 根据城市名做地理/逆地理编码 获取经纬坐标const setAddrLocation = (area) => {window.AMap.plugin('AMap.Geocoder', () => {let geocoder = new window.AMap.Geocoder({// city 指定进行编码查询的城市,支持传入城市名、adcode 和 citycodecity: store?.visitInfo?.city});// 使用geocoder做地理/逆地理编码geocoder.getLocation(area, (status, result) => {if (status === 'complete' && result.info === 'OK') {const location = result.geocodes[0].location;setCoordinates([location.lng, location.lat])if (store.area && result.info === 'OK') store.setStore({ range: 3 })}});});};const debounceSetAddrLocation = useDebounceFn(setAddrLocation);// 显示周边范围const showRange = () => {setZoom(16);setCoordinates(currentMarkerData.location.split(','));store.setStore({ range: 3, customerId: currentMarkerData.customerId })setVisible(true)}// 增加拜访计划const addVisit = () => {setEditVisitPlanVisible(true)}// Markers 事件const events = {created: (markers) => {for (const item of markers) {markerMap.push(item)}},click: (mapsOption, marker) => {currentMarkerData = marker.getExtData().extDatasetCustomContextMenuVisible(false)if (currentMarkerData.isCover === 1) {const customAmapMenu = document.getElementsByClassName('custom-amap-menu')if (customAmapMenu.length === 0) {MapsOption = mapsOptionsetCustomContextMenuVisible(true)}} else {contextMenu.current.open(mapInstance.current, mapsOption.lnglat);}},mouseover: (mapsOption, marker) => {marker.setLabel({offset: new window.AMap.Pixel(20, 20), // 修改label相对于maker的位置content: marker.w.extData.extData.showName})marker.setTop(true);},mouseout: (mapsOption, marker) => {marker.setLabel({content: null});marker.setTop(false);}}// 地图事件const mapEvents = {created: (instance) => {mapInstance.current = instance;contextMenu.current = new window.AMap.ContextMenu();contextMenu.current.addItem("显示周边范围", showRange, 0);contextMenu.current.addItem("增加拜访计划", addVisit, 1);contextMenu.current.addItem("重新维护地址", function() {window.open(`/customer/todetail/?customerId=${currentMarkerData.customerId}&isinfoEdit=1`);}, 2);contextMenu.current.addItem("查看拜访记录", function() {window.open(`/customervisitplan/listall/?customer_id=${currentMarkerData.customerId}`);}, 3);contextMenu.current.addItem("查看客户详情", function() {window.open(`/customer/todetail/?customerId=${currentMarkerData.customerId}`);}, 4);},click: () => setCustomContextMenuVisible(false),mapmove: () => setCustomContextMenuVisible(false),zoomchange: () => {const list = [...markers]console.log('mapInstance.current.getZoom()', mapInstance.current.getZoom());setZoom(mapInstance.current.getZoom());if (mapInstance.current.getZoom() > 12) {for(const item of list) {item.label = {content: item.extData.showName,offset: new window.AMap.Pixel(20, 20)}}} else {for(const item of list) {item.label = undefined}}setMarkers(list)console.log('keys', );setIconRed(store.customer)setCustomContextMenuVisible(false)},};return (<Spin spinning={store.loading} ><div id="customer-maps" style={{width: '100%', height: 'calc(100vh - 184px)'}}><div style={{ display: store.customerLocationList.length ? 'block' : 'none', height: '100%', width: '100%' }}><Mapamapkey="0fe0e92d23dc183b6384d51515676b81"version="1.4.0"plugins={['Scale', 'ToolBar']}center={coordinates}isHotspot={true}zoom={zoom}events={mapEvents}><Markersmarkers={markers}events={events}render={renderMarkerFn}/><Circlecenter={ coordinates }radius={ radius }visible={ visible }style={{strokeColor: "#F33", // 线颜色strokeOpacity: 1, // 线透明度strokeWeight: 3, // 线粗细度fillColor: "#ee2200", // 填充颜色fillOpacity: 0.15 // 填充透明度}}draggable={ false }bubble/></Map></div>{/* 增加拜访计划 */}{editVisitPlanVisible &&<EditVisitPlanvisible={editVisitPlanVisible}params={{customerId: currentMarkerData.customerId,customerName: currentMarkerData.customerName,title: '增加拜访计划',isEdit: false,isPhone: true,onSave: () => setEditVisitPlanVisible(false),onCancel: () => setEditVisitPlanVisible(false)}}/>}{/* 重复坐标点的自定义菜单 */}{customContextMenuVisible &&<CustomContextMenumapsOption={MapsOption}coverLocations={ currentMarkerData.coverLocations }showRange={showRange}addVisit={addVisit}setCurrentMarkerData={(data) => currentMarkerData = data}/>}</div></Spin>)
})

自定义菜单样式

#customer-maps {position: relative;.custom-amap-menu {position: absolute;top: 100px;left: 300px;border: 1px solid #ccc;background: #fff;z-index: 111;padding: 0;ul, li {padding: 0;margin: 0;list-style:none}li {height: 30px;line-height: 30px;padding: 0 10px;position: relative;}li:hover {background: #eee;}li:hover ul {display: block;}ul {width: 100px;position: absolute;top: 0;right: -100px;display: none;background: #fff;border: 1px solid #ccc;z-index: 111;}ul li {height: 30px;line-height: 30px;padding: 0 10px;text-align: center;cursor: pointer;}ul li:hover {background: #eee;}a {color: #5f6d80;}a:hover {text-decoration: none;}ul li a {display: block;}}
}

这篇关于react使用高德地图react-amap:Map、Markers、Circle、ContextMenu、自定义ContextMenu的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/240316

相关文章

Spring StateMachine实现状态机使用示例详解

《SpringStateMachine实现状态机使用示例详解》本文介绍SpringStateMachine实现状态机的步骤,包括依赖导入、枚举定义、状态转移规则配置、上下文管理及服务调用示例,重点解... 目录什么是状态机使用示例什么是状态机状态机是计算机科学中的​​核心建模工具​​,用于描述对象在其生命

使用Python删除Excel中的行列和单元格示例详解

《使用Python删除Excel中的行列和单元格示例详解》在处理Excel数据时,删除不需要的行、列或单元格是一项常见且必要的操作,本文将使用Python脚本实现对Excel表格的高效自动化处理,感兴... 目录开发环境准备使用 python 删除 Excphpel 表格中的行删除特定行删除空白行删除含指定

深入理解Go语言中二维切片的使用

《深入理解Go语言中二维切片的使用》本文深入讲解了Go语言中二维切片的概念与应用,用于表示矩阵、表格等二维数据结构,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录引言二维切片的基本概念定义创建二维切片二维切片的操作访问元素修改元素遍历二维切片二维切片的动态调整追加行动态

prometheus如何使用pushgateway监控网路丢包

《prometheus如何使用pushgateway监控网路丢包》:本文主要介绍prometheus如何使用pushgateway监控网路丢包问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录监控网路丢包脚本数据图表总结监控网路丢包脚本[root@gtcq-gt-monitor-prome

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数

SpringBoot中如何使用Assert进行断言校验

《SpringBoot中如何使用Assert进行断言校验》Java提供了内置的assert机制,而Spring框架也提供了更强大的Assert工具类来帮助开发者进行参数校验和状态检查,下... 目录前言一、Java 原生assert简介1.1 使用方式1.2 示例代码1.3 优缺点分析二、Spring Fr

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件

SpringBoot线程池配置使用示例详解

《SpringBoot线程池配置使用示例详解》SpringBoot集成@Async注解,支持线程池参数配置(核心数、队列容量、拒绝策略等)及生命周期管理,结合监控与任务装饰器,提升异步处理效率与系统... 目录一、核心特性二、添加依赖三、参数详解四、配置线程池五、应用实践代码说明拒绝策略(Rejected