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

相关文章

使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)

《使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)》在现代软件开发中,处理JSON数据是一项非常常见的任务,无论是从API接口获取数据,还是将数据存储为JSON格式,解析... 目录1. 背景介绍1.1 jsON简介1.2 实际案例2. 准备工作2.1 环境搭建2.1.1 添加

如何使用celery进行异步处理和定时任务(django)

《如何使用celery进行异步处理和定时任务(django)》文章介绍了Celery的基本概念、安装方法、如何使用Celery进行异步任务处理以及如何设置定时任务,通过Celery,可以在Web应用中... 目录一、celery的作用二、安装celery三、使用celery 异步执行任务四、使用celery

使用Python绘制蛇年春节祝福艺术图

《使用Python绘制蛇年春节祝福艺术图》:本文主要介绍如何使用Python的Matplotlib库绘制一幅富有创意的“蛇年有福”艺术图,这幅图结合了数字,蛇形,花朵等装饰,需要的可以参考下... 目录1. 绘图的基本概念2. 准备工作3. 实现代码解析3.1 设置绘图画布3.2 绘制数字“2025”3.3

Jsoncpp的安装与使用方式

《Jsoncpp的安装与使用方式》JsonCpp是一个用于解析和生成JSON数据的C++库,它支持解析JSON文件或字符串到C++对象,以及将C++对象序列化回JSON格式,安装JsonCpp可以通过... 目录安装jsoncppJsoncpp的使用Value类构造函数检测保存的数据类型提取数据对json数

python使用watchdog实现文件资源监控

《python使用watchdog实现文件资源监控》watchdog支持跨平台文件资源监控,可以检测指定文件夹下文件及文件夹变动,下面我们来看看Python如何使用watchdog实现文件资源监控吧... python文件监控库watchdogs简介随着Python在各种应用领域中的广泛使用,其生态环境也

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链

springboot整合 xxl-job及使用步骤

《springboot整合xxl-job及使用步骤》XXL-JOB是一个分布式任务调度平台,用于解决分布式系统中的任务调度和管理问题,文章详细介绍了XXL-JOB的架构,包括调度中心、执行器和Web... 目录一、xxl-job是什么二、使用步骤1. 下载并运行管理端代码2. 访问管理页面,确认是否启动成功

使用Nginx来共享文件的详细教程

《使用Nginx来共享文件的详细教程》有时我们想共享电脑上的某些文件,一个比较方便的做法是,开一个HTTP服务,指向文件所在的目录,这次我们用nginx来实现这个需求,本文将通过代码示例一步步教你使用... 在本教程中,我们将向您展示如何使用开源 Web 服务器 Nginx 设置文件共享服务器步骤 0 —

Java中switch-case结构的使用方法举例详解

《Java中switch-case结构的使用方法举例详解》:本文主要介绍Java中switch-case结构使用的相关资料,switch-case结构是Java中处理多个分支条件的一种有效方式,它... 目录前言一、switch-case结构的基本语法二、使用示例三、注意事项四、总结前言对于Java初学者

Golang使用minio替代文件系统的实战教程

《Golang使用minio替代文件系统的实战教程》本文讨论项目开发中直接文件系统的限制或不足,接着介绍Minio对象存储的优势,同时给出Golang的实际示例代码,包括初始化客户端、读取minio对... 目录文件系统 vs Minio文件系统不足:对象存储:miniogolang连接Minio配置Min