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

相关文章

Python使用Pandas对比两列数据取最大值的五种方法

《Python使用Pandas对比两列数据取最大值的五种方法》本文主要介绍使用Pandas对比两列数据取最大值的五种方法,包括使用max方法、apply方法结合lambda函数、函数、clip方法、w... 目录引言一、使用max方法二、使用apply方法结合lambda函数三、使用np.maximum函数

Qt 中集成mqtt协议的使用方法

《Qt中集成mqtt协议的使用方法》文章介绍了如何在工程中引入qmqtt库,并通过声明一个单例类来暴露订阅到的主题数据,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录一,引入qmqtt 库二,使用一,引入qmqtt 库我是将整个头文件/源文件都添加到了工程中进行编译,这样 跨平台

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本