当前位置: 首页 > news >正文

react-amap海量点优化

前言:高版本的react-amap 支持MassMarkers 组件用于一次性添加大量的标记点。本次优化的海量点是在低版本react-amap的基础上。官方推荐使用聚合useCluster属性来优化海量点的渲染。

直接附上代码:

import React, { Component } from "react";
import { Map, Markers, Polygon, InfoWindow } from 'react-amap'
import {Form,Switch,message,
} from "antd";
import ActionsForm from "components/RoutePanel/ActionsForm";
import { MAP_AMAP_KEY, MAP_AMAP_VERSION } from 'constants/config'
import {API_FETCH_ZONES_DEPT_POINT,
} from 'constants/api'
import fetch from 'common/fetch'
import styles from "./amap.css";
import { debounce } from 'lodash';const polygonType = {main: 'main',adjacent: 'adjacent',normal: 'normal',
}// 获取区域样式
const getPolygonStyle = (pt) => {switch (pt) {case polygonType.main: return {fillColor: '#DC2626',fillOpacity: 0.5,strokeOpacity: 0.5,strokeWeight: 2,strokeColor: '#DC2626',}case polygonType.adjacent:return {fillColor: '#34D399',fillOpacity: 0.5,strokeOpacity: 1,strokeWeight: 1,strokeColor: '#34D399',}case polygonType.normal:default:return {fillColor: '#333333',fillOpacity: 0.3,strokeOpacity: 0.5,strokeWeight: 1,strokeColor: '#333333',}}
}export class ZoneNeighborhoodMap extends Component {constructor(props) {super(props)this.map = null; // 地图实例this.mapEvents = {created: (mapInstance) => {this.map = mapInstance;this.map.on('zoomend', this.handleZoom);},close: () => {this.map = null;if (this.map) {this.map.off('zoomend', this.handleZoom);}}};this.state = {infoWindowPosition: null,infoWindowTitle: '',polygonActive: false,pointReferShow: true, //运输点参考pointReferData: [],areaReferShow: true, //已绘制参考areaReferData: [],locTypes: [],data: props.data,// infoWindowPosition: {//   longitude: 120,//   latitude: 30,// },infoWindowVisible: false,infoWindowData: {id: "",desc: "",},infoWindow: {position: {longitude: 120,latitude: 30,},visible: false,data: null,},useCluster:false}this.markerEvents = {created: (e) => {},mouseover: (e) => {const position = e.target.getPosition();this.setState({infoWindow: {position: {longitude: position.lng,latitude: position.lat,},visible: true,data: e.target.getExtData(),},});},mouseout: (e) => {this.setState({infoWindow: {position: {longitude: 120,latitude: 30,},visible: false,data: null,},});},};}componentWillUnmount() {if (this.map) {this.map.destroy();}}componentWillUnmount() {if (this.map) {this.map.destroy()}}// 缩放事件处理函数handleZoom = () => {const zoomLevel = this.map.getZoom();console.log('zoomLevel',zoomLevel)if (zoomLevel > 8) {this.setState({ useCluster: false });} else {this.setState({ useCluster: true });}};setFitViewWithZoneId(zoneId) {const fitOverlays = []this.map.getAllOverlays().forEach(polygon => {if (polygon.getExtData().zoneId === zoneId) {fitOverlays.push(polygon)}})if (fitOverlays.length) {this.map.setFitView(fitOverlays, false, undefined, this.map.getZoom())}}renderPolygons() {const { mainZoneId, polygons, toggleAdjacentZone, adjacentZoneIds } = this.propsconst l = polygons.lengthconst _polygons = []for (let i = 0; i < l; i++) {const detail = polygons[i]if (detail.geoArea && detail.geoArea.length) {let _polygonType = polygonType.normalif (detail.zoneId === mainZoneId) {_polygonType = polygonType.main} else if (adjacentZoneIds.includes(detail.zoneId)) {_polygonType = polygonType.adjacent}detail.geoArea.forEach((path, pathId) => {_polygons.push(<Polygon path={path}key={`${detail.id}:${pathId}`}style={getPolygonStyle(_polygonType)}events={{click: () => {if (detail.zoneId === mainZoneId) {return}toggleAdjacentZone(detail.zoneId)},mousemove: (e) => {this.setState(() => ({infoWindowPosition: e.lnglat,infoWindowTitle: detail.zoneDesc}))},mouseout: () => {this.setState(() => ({infoWindowPosition: null}))}}}extData={{ zoneId: detail.zoneId }}/>)})}}return _polygons}renderInfoWindow() {const { infoWindowPosition, infoWindowTitle } = this.stateif (!infoWindowPosition) {return null}return <InfoWindowposition={{longitude: infoWindowPosition.lng,latitude: infoWindowPosition.lat,}}isCustom={true}content={`<div style="pointer-events: none;background: #fff;border:1px solid silver;padding: 4px 8px;">${infoWindowTitle}</div>`}offset={[2,-10]}visible/>}getPoint = ()=>{fetch(API_FETCH_ZONES_DEPT_POINT, {method: 'POST',headers: {'Accept': 'application/json','Content-Type': 'application/json'},body: JSON.stringify({ deptId:this.props.deptId })}).then((response) => {if (response.ok) {return response.json();}throw new Error("Bad response from server");}).then((json) => {if(json.data instanceof Array){if (!json.data.length) {message.info("没有可显示的运输地点");}else{if(json.data.length > 500){this.setState({useCluster: true,})}json.data.forEach(d=>d.position= { longitude: d.longitude, latitude: d.latitude })this.setState({pointReferData:json.data},()=>{if (!this.map) return; // 如果地图实例未初始化,则不执行this.map.setFitView();})}}}).catch(e=>{})}renderInfo = () => {const { position, visible, data } = this.state.infoWindow;const {locTypes} = this.stateif (!data) {return null;}const locTypeItem = locTypes.find(t=>t.domVal==data.locType)const tds = (<div  className={styles.info}><div className='inforow'><span>运输地点代码</span><span>{data.locId}</span></div><div className='inforow'><span>运输地点描述</span><span>{data.locDesc}</span></div><div className='inforow'><span>类型</span><span>{locTypeItem?locTypeItem.domValDesc:data.locType}</span></div><div className='inforow'><span>城市</span><span>{data.city}</span></div><div className='inforow'><span>省份</span><span>{data.province}</span></div><div className='inforow'><span>国家</span><span>{data.country}</span></div><div className='inforow'><span>经度</span><span>{data.longitude}</span></div><div className='inforow'><span>纬度</span><span>{data.latitude}</span></div><div className='inforow'><span>地址</span><span>{data.addr}</span></div><div className='inforow'><span>限行区域</span><span>{data.udzDesc1}({data.udz1})</span></div><div className='inforow'><span>业务区域</span><span>{data.udzDesc2}({data.udz2})</span></div></div>);return (<InfoWindowposition={position}visible={visible}isCustom={true}offset={[2, 2]}>{tds}</InfoWindow>);};pointRender = (extData) => {return (<divstyle={{color: "#4e72b8",width: "8px",height: "8px",borderRadius: "50%",background: "#4169E1",textAlign: "center",}}/>);};initPointReferData = () => {if (!this.state.pointReferShow) {this.setState({pointReferData: [],});} else {this.getPoint()}};componentDidMount() {this.initPointReferData();}// 运输点参考// changePointReferShow = (checked) => {//   this.setState({ pointReferShow: checked }, () => {//     this.initPointReferData();//   });// };changePointReferShow = debounce((checked) => {this.setState({ pointReferShow: checked }, () => {this.initPointReferData();});}, 300); // 300ms 的防抖延迟render() {const {polygonActive,pointReferShow,data,pointReferData,areaReferData,areaReferShow,} = this.state;const option = {amapkey: MAP_AMAP_KEY,version: MAP_AMAP_VERSION,mapStyle: 'amap://styles/whitesmoke',// loading: this.renderLoading(),status: {resizeEnable: true,},plugins: ['ToolBar', 'Scale'],events: this.mapEvents,}return (<div style={{ width: "100%", height: "100vh", position: "relative" }}><ActionsForm><Form layout="inline"><Form.Item><SwitchcheckedChildren="显示地点"unCheckedChildren="显示地点"checked={pointReferShow}onChange={this.changePointReferShow}/></Form.Item></Form></ActionsForm><Map {...option}><Markersmarkers={pointReferData}offset={[0,0]}render={this.pointRender}events={this.markerEvents}useCluster={this.state.useCluster}/>{this.renderPolygons()}{this.renderInfoWindow()}{this.renderInfo()}</Map></div>);}
}

希望点的数量少于1000时直接展示所有点,不聚合

import React, { Component } from "react";
import PropTypes from "prop-types";
import Immutable from 'seamless-immutable';
import {Map,Polygon,Markers,PolyEditor,MouseTool,InfoWindow,
} from "react-amap";
import {Form,Button,Switch,Tooltip,Modal,message,Menu,Dropdown,Popconfirm,Icon,
} from "antd";
import isomorphicFetch from "isomorphic-fetch";
import {API_FETCH_DOMAIN,API_FETCH_ZONES_DEPT_POINT,API_FETCH_ZONES_GROUP
} from 'constants/api'
import fetch from 'common/fetch'import {MAP_AMAP_KEY,MAP_AMAP_DRIVING_KEY,MAP_AMAP_VERSION,
} from "constants/config";
import ActionsForm from "components/RoutePanel/ActionsForm";
import ZoneCascader from "components/PcaCascader/ZoneCascader";
import pstyles from "./polygons.scss";// 获取封闭polygon(首尾点坐标一致)
const _getClosedPolygon = (paths) => {if (Array.isArray(paths) && paths.length > 2) {const firstLocation = paths[0];const lastLocation = paths[paths.length - 1];if (firstLocation[0] === lastLocation[0] &&firstLocation[1] === lastLocation[1]) {return paths;} else {return [...paths, firstLocation];}} else {return [];}
};class PolygonEdit extends Component {constructor(props) {super(props);this.state = {polygonActive: false,pointReferShow: true, //运输点参考pointReferData: [],areaReferShow: false, //已绘制参考areaReferData: [],locTypes: [],data: props.data,mapEditable: props.mapEditable,deleteMenuVisible: false,hoverItemData: [],adcode: "",province: "",provinceCode:"",city: "",cityCode:"",area: "",street: "",polyline: "",infoWindowPosition: {longitude: 120,latitude: 30,},infoWindowVisible: false,infoWindowData: {id: "",desc: "",},infoWindow: {position: {longitude: 120,latitude: 30,},visible: false,data: null,},showLabels: true, // 默认显示悬浮名称useCluster:false};const _this = this;this.amap = null; // 地图this.mouseTool = null; // 鼠标工具this.amapEvents = {created: (mapInstance) => {_this.amap = mapInstance;_this.amap.on('zoomend', this.handleZoom);},close: () => {_this.amap = null;if (_this.amap) {_this.amap.off('zoomend', this.handleZoom);}},};this.polyEditorEvents = {created: (ins) => {_this.amap.setFitView();},addnode: () => {},adjust: ({ lnglat, pixel, type, target } = option) => {},removenode: () => {},end: ({ type, target }) => {this.polyEditorEnd(target, type);},};this.polygonEvents = {created: (ins) => {_this.amap.setFitView();},};this.toolEvents = {created: (tool) => {_this.mouseTool = tool;},draw({ obj }) {_this.drawWhat(obj);},};this.markerEvents = {created: (e) => {},mouseover: (e) => {const position = e.target.getPosition();this.setState({infoWindow: {position: {longitude: position.lng,latitude: position.lat,},visible: true,data: e.target.getExtData(),},});},mouseout: (e) => {this.setState({infoWindow: {position: {longitude: 120,latitude: 30,},visible: false,data: null,},});},};}componentWillUnmount() {if (this.amap) {this.amap.destroy();}}componentDidMount() {if(this.props.isGroup){this.initPointReferData();this.initAreaReferData()}this.getLocType()}// 缩放事件处理函数handleZoom = () => {const zoomLevel = this.amap.getZoom();console.log('zoomLevel', zoomLevel);console.log('this.state.pointReferData.length', this.state.pointReferData.length);// 判断点的数量是否小于1000,以及当前缩放等级if (this.state.pointReferData.length > 1000 && zoomLevel < 10) {this.setState({ useCluster: true });} else {this.setState({ useCluster: false });}};getPoint = ()=>{fetch(API_FETCH_ZONES_DEPT_POINT, {method: 'POST',headers: {'Accept': 'application/json','Content-Type': 'application/json'},body: JSON.stringify({ deptId:this.props.deptId })}).then((response) => {if (response.ok) {return response.json();}throw new Error("Bad response from server");}).then((json) => {if(json.data instanceof Array){if (!json.data.length) {message.info("没有可显示的运输地点");}else{json.data.forEach(d=>d.position= { longitude: d.longitude, latitude: d.latitude })this.setState({pointReferData:json.data},()=>{if (!this.amap) return; // 如果地图实例未初始化,则不执行this.amap.setFitView();})}}}).catch(e=>{})}renderPolygons = () => {const { areaReferShow, areaReferData } = this.state;const GROUP_KEY = {unConfiguredGroups: 'unConfiguredGroups',configuredGroups: 'configuredGroups'}const prepareGroups = (groups) => {const _groups = Immutable.asMutable(groups, { deep: true }).map(group => ({...group,zoneDetail: (group.zoneDetail || []).map(detail => {return {...detail,geoArea: JSON.parse(detail.geoArea)}})}))return {groups,[GROUP_KEY.unConfiguredGroups]: _groups.filter(group => !group.lines.length).map(group => ({...group,lines: []})),[GROUP_KEY.configuredGroups]: _groups.filter(group => group.lines.length),zoneOptions: _groups.map(group => ({value: group.zoneId,label: group.zoneDesc,})),polygons: _groups.reduce((polygons, group) => {polygons.push(...group.zoneDetail.map(zoneDetail => ({ ...zoneDetail, zoneDesc: group.zoneDesc }))) // flat zoneDetailreturn polygons}, [])}}const newData = prepareGroups(areaReferData)const polygons = newData.polygonsconst l = polygons.lengthconst _polygons = []for (let i = 0; i < l; i++) {const detail = polygons[i]if (detail.geoArea && Array.isArray(detail.geoArea) && detail.geoArea.length) {detail.geoArea.forEach((path, pathId) => {_polygons.push(<Polygon path={path}key={`${detail.id}:${pathId}`}style={{fillColor: '#333333',fillOpacity: 0.3,strokeOpacity: 0.5,strokeWeight: 1,strokeColor: '#333333',}}events={{mousemove: (e) => {this.setState(() => ({infoWindowPosition: e.lnglat,infoWindowTitle: detail.zoneDesc}))},mouseout: () => {this.setState(() => ({infoWindowPosition: null}))}}}extData={{ zoneId: detail.zoneId }}/>)})}else{console.log('detail.geoArea',detail.geoArea)}}return _polygons}getArea = ()=>{fetch(API_FETCH_ZONES_GROUP, {method: 'POST',credentials: 'include',headers: {'Accept': 'application/json','Content-Type': 'application/json'},body: JSON.stringify({ branchId:this.props.branchId,deptId:this.props.deptId})}).then((response) => {if (response.ok) {return response.json();}throw new Error("Bad response from server");}).then((json) => {if(json.data && json.data.data instanceof Array){if (!json.data.data.length) {message.info("没有可显示的区域");}else{this.setState({areaReferData:json.data.data})}}}).catch(e=>{console.log('e',e)})}renderInfoWindow() {const { infoWindowPosition, infoWindowTitle, showLabels } = this.stateif(showLabels){if (!infoWindowPosition) {return null}return <InfoWindowposition={{longitude: infoWindowPosition.lng,latitude: infoWindowPosition.lat,}}isCustom={true}content={`<div style="pointer-events: none;background: #fff;border:1px solid silver;padding: 4px 8px;">${infoWindowTitle}</div>`}offset={[2,2]}visible/>}}initPointReferData = () => {if (!this.state.pointReferShow) {this.setState({pointReferData: [],});} else {this.getPoint()}};initAreaReferData = () => {if (!this.state.areaReferShow) {this.setState({areaReferData: [],});} else {this.getArea()}};renderLoading = () => {const loadingStyle = {position: "relative",height: "100%",width: "100%",display: "flex",justifyContent: "center",alignItems: "center",};return <div style={loadingStyle}>Loading Map...</div>;};// 运输点参考changePointReferShow = (checked) => {this.setState({ pointReferShow: checked }, () => {this.initPointReferData();});};// 已绘制区域参考changeAreaReferShow = (checked) => {this.setState({ areaReferShow: checked }, () => {this.initAreaReferData();});};// 是否悬浮显示名称toggleLabels = (checked) => {this.setState({ showLabels: checked });};pointRender = (extData) => {return (<divstyle={{color: "#4e72b8",width: "8px",height: "8px",borderRadius: "50%",background: "#4169E1",textAlign: "center",}}/>);};getLocType=()=>{fetch(`${API_FETCH_DOMAIN}LOCATION_TYPE`,{credentials: 'include'}).then((response) => {if (response.ok) {return response.json();}throw new Error("Bad response from server");}).then((json) => {if(json.data instanceof Array){this.setState({locTypes:json.data})}}).catch(e=>{})}renderInfo = () => {const { position, visible, data } = this.state.infoWindow;const {locTypes} = this.stateif (!data) {return null;}const locTypeItem = locTypes.find(t=>t.domVal==data.locType)const tds = (<div  className={pstyles.pinfo}><div className='inforow'><span>运输地点代码</span><span>{data.locId}</span></div><div className='inforow'><span>运输地点描述</span><span>{data.locDesc}</span></div><div className='inforow'><span>类型</span><span>{locTypeItem?locTypeItem.domValDesc:data.locType}</span></div><div className='inforow'><span>城市</span><span>{data.city}</span></div><div className='inforow'><span>省份</span><span>{data.province}</span></div><div className='inforow'><span>国家</span><span>{data.country}</span></div><div className='inforow'><span>经度</span><span>{data.longitude}</span></div><div className='inforow'><span>纬度</span><span>{data.latitude}</span></div><div className='inforow'><span>地址</span><span>{data.addr}</span></div><div className='inforow'><span>限行区域</span><span>{data.udzDesc1}({data.udz1})</span></div><div className='inforow'><span>业务区域</span><span>{data.udzDesc2}({data.udz2})</span></div></div>);return (<InfoWindowposition={position}visible={visible}isCustom={true}offset={[2, 2]}>{tds}</InfoWindow>);};// polygon edit switchtogglePolygon = (checked, e) => {if (checked) {// open edit and close add if it is drawingif (this.mouseTool) {this.mouseTool.close();}this.setState({ polygonActive: true, isDrawingPolygon: false });} else {// close editthis.setState({ polygonActive: false });}};// polygon add switchtoggleDrawPolygon = (checked, e) => {if (checked) {if (this.mouseTool) {this.mouseTool.polygon();this.setState({ isDrawingPolygon: true });message.success("鼠标左键双击或右键单击完成当前多边形!");}} else {if (this.mouseTool) {this.mouseTool.close();this.setState({ isDrawingPolygon: false });}}};// finish polygon drawdrawWhat = (obj) => {const paths = obj.getPath();let data = this.state.data.slice();const pathData = paths.map((item) => [item.lng, item.lat]);if (pathData.length > 2) {if (this.amap) {this.amap.remove(obj);}data.push(_getClosedPolygon(pathData));this.setState({ data });message.success(`您成功绘制了一个${paths.length}边形,可继续绘制或点击结束多边形绘制按钮`);}};// polygon editor endpolyEditorEnd = (target, type) => {const paths = target.getPath();let isSinglePath = false; // 是否是单围栏const pathData = paths.map((item, index) => {if (Array.isArray(item)) {const itemPaths = item.map((element) => [element.lng, element.lat]);return _getClosedPolygon(itemPaths);} else {isSinglePath = true;return [item.lng, item.lat];}});this.setState({data: isSinglePath ? [_getClosedPolygon(pathData)] : pathData,});};// 多边形删除下拉菜单deleteMenuVisibleChange = (flag) => {this.setState({ deleteMenuVisible: flag });};// 删除多边形handleMenuClick = (e) => {this.handleDeletePath(e.key);};handleDeletePath = (key) => {const path = [...this.state.data];path.splice(key, 1);this.setState({ data: path, deleteMenuVisible: false });};handleMenuHover = (key) => {this.setState({ hoverItemData: this.state.data[key] });};handleChangeAdcode = ({ adcode, province, city, area, street,provinceCode,cityCode }) => {this.setState({ adcode, province, city, area, street,provinceCode, cityCode});};handleAdcodeCancle = () => {this.setState({adcode: "",province: "",provinceCode:"",city: "",cityCode:"",area: "",street: "",});};handleAdcodeConfirm = () => {const { adcode, provinceCode, cityCode, area, street, mapEditable } = this.state;if (adcode) {this.setState({mapEditable: "N",adcode: "",polygonActive: false,isDrawingPolygon: false,});if (street) {isomorphicFetch(`/city-tiles/${provinceCode}_${cityCode}.json`).then((response) => {if (response.ok) {return response.json();}throw new Error("Bad response from server");}).then((json) => {if (json.status === "0") {throw new Error("No districts from server");}try {const streetItemData = json.features.find((s) => s.properties.subdistrict == street).geometry.coordinates;if (this.mouseTool) {this.mouseTool.close();}this.setState({data: streetItemData, // some data});if (this.amap) {this.amap.setFitView();}} catch (e) {message.error("获取行政区划数据失败!");}// const polyline = (json.districts && json.districts[0]) ? json.districts[0].polyline : [];// const data = polyline.split('|').map(block => block.split(';').map(pointer => pointer.split(',').map(lnglat => Number(lnglat))));// if (this.mouseTool){//   this.mouseTool.close();// }// this.setState({//   data: data, // some data// })// if (this.amap) {//   this.amap.setFitView();// }}).catch((error) => {message.error("获取行政区划数据失败!");this.setState({mapEditable: "Y",province: "",provinceCode:"",city: "",cityCode:"",area: "",street: "",data: [],});});} else {// fetch polyline dataisomorphicFetch(`//restapi.amap.com/v3/config/district?key=e17fafe279209e4b3a303cc907347277&keywords=${adcode}&subdistrict=0&extensions=all`).then((response) => {if (response.ok) {return response.json();}throw new Error("Bad response from server");}).then((json) => {if (json.status === "0") {throw new Error("No districts from server");}const polyline =json.districts && json.districts[0]? json.districts[0].polyline: [];const data = polyline.split("|").map((block) =>block.split(";").map((pointer) =>pointer.split(",").map((lnglat) => Number(lnglat))));if (this.mouseTool) {this.mouseTool.close();}this.setState({data: data, // some data});if (this.amap) {this.amap.setFitView();}}).catch((error) => {message.error("获取行政区划数据失败!");this.setState({mapEditable: "Y",province: "",provinceCode:"",city: "",cityCode:"",area: "",street: "",data: [],});});}} else {if (mapEditable === "N") {this.setState({mapEditable: "Y",adcode: "",province: "",provinceCode:"",city: "",cityCode:"",area: "",street: "",data: [],});}}};handleFinished = () => {const {polygonActive,data,adcode,province,city,area,street,mapEditable,} = this.state;let result = {geoArea:Array.isArray(data) && data.length > 0 ? JSON.stringify(data) : null,mapEditable,};if (mapEditable === "N") {Object.assign(result, {country: "中国",state: province,city,district: area,subdistrict: street,});}if (polygonActive) {this.setState({ polygonActive: false });Modal.confirm({title: "您的多边形调整还未结束,是否结束?",onOk: () => {this.props.onConfirm(result);},onCancel: () => {this.setState({ polygonActive: true });},});} else {this.props.onConfirm(result);}};render() {const {polygonActive,isDrawingPolygon,pointReferShow,data,pointReferData,areaReferData,areaReferShow,deleteMenuVisible,hoverItemData,adcode,mapEditable,infoWindowPosition,infoWindowVisible,infoWindowData,showLabels,useCluster} = this.state;const { onCancle, isGroup } = this.props;const option = {amapkey: MAP_AMAP_KEY,version: MAP_AMAP_VERSION,mapStyle: "amap://styles/whitesmoke",loading: this.renderLoading(),status: {resizeEnable: true,},plugins: ["ToolBar", "Scale"],events: this.amapEvents,};return (<div style={{ width: "100%", height: "100vh", position: "relative" }}><ActionsForm>{isGroup ? (<Form layout="inline"><Form.Item><Popconfirmtitle={<ZoneCascaderadcode={adcode}onChange={this.handleChangeAdcode}/>}icon={<Tooltip title="选择行政区划。此操作将首先清空已有围栏,已选择的行政区划围栏不允许编辑"><Icon type="question-circle-o" /></Tooltip>}onCancel={this.handleAdcodeCancle}onConfirm={this.handleAdcodeConfirm}><Button type="primary">行政区划选择{isGroup}</Button></Popconfirm></Form.Item><Form.Item><Switchdisabled={mapEditable === "N"}checkedChildren="调整"unCheckedChildren="调整"checked={polygonActive}onChange={this.togglePolygon}/></Form.Item><Form.Item><Switchdisabled={mapEditable === "N"}checkedChildren="新增"unCheckedChildren="新增"checked={isDrawingPolygon}onChange={this.toggleDrawPolygon}/></Form.Item><Form.Item><Dropdownoverlay={<Menu onClick={this.handleMenuClick}>{data &&data.length > 0 &&data.map((item, index) => (<Menu.Item key={index}><spanonMouseOver={() => this.handleMenuHover(index)}>{`${index + 1} 删除`}</span></Menu.Item>))}</Menu>}onVisibleChange={this.deleteMenuVisibleChange}visible={deleteMenuVisible}disabled={mapEditable === "N"}><Button>删除</Button></Dropdown></Form.Item><Form.Item><Button onClick={onCancle}>取消</Button></Form.Item><Form.Item><Button type="primary" onClick={this.handleFinished}>完成</Button></Form.Item><Form.Item><SwitchcheckedChildren="显示地点"unCheckedChildren="显示地点"checked={pointReferShow}onChange={this.changePointReferShow}/></Form.Item><Form.Item><SwitchcheckedChildren="显示其他区域"unCheckedChildren="显示其他区域"checked={areaReferShow}onChange={this.changeAreaReferShow}/></Form.Item><Form.Item><SwitchcheckedChildren="显示区域名称"unCheckedChildren="隐藏区域名称"checked={showLabels}onChange={this.toggleLabels}/></Form.Item></Form>) : (<Form layout="inline"><Form.Item><Button type="primary" onClick={onCancle}>关闭</Button></Form.Item></Form>)}</ActionsForm><Map {...option}><Markersmarkers={pointReferData}offset={[0,0]}render={this.pointRender}events={this.markerEvents}useCluster={useCluster}/>{isGroup && <MouseTool events={this.toolEvents} />}{isGroup ? (<Polygonpath={data}style={{ fillOpacity: 0.3, strokeOpacity: 0.5, strokeWeight: 1 }}events={this.polygonEvents}><PolyEditoractive={polygonActive && data.length > 0 && data.flat().length <= 100}events={this.polyEditorEvents}/></Polygon>) : (data.map((item, index) => (<Polygonevents={this.polygonEvents}key={index}path={item}style={{fillOpacity: 0.3,strokeOpacity: 0.5,strokeWeight: 1,}}/>)))}<Polygonvisible={deleteMenuVisible}path={[hoverItemData]}zIndex={100}style={{fillColor: "red",fillOpacity: 0.3,strokeOpacity: 0.5,strokeWeight: 1,}}/>{this.renderInfo()}{this.renderPolygons()}{this.renderInfoWindow()}</Map></div>);}
}PolygonEdit.propTypes = {isGroup: PropTypes.bool, // 是:data 为单个 polygon 数据;否: data 为多个 polygon 数据data: PropTypes.array,onCancle: PropTypes.func,onConfirm: PropTypes.func,
};
PolygonEdit.defaultProps = {isGroup: true,data: [],onCancle: () => {},onConfirm: () => {},
};export default PolygonEdit;

相关文章:

react-amap海量点优化

前言&#xff1a;高版本的react-amap 支持MassMarkers 组件用于一次性添加大量的标记点。本次优化的海量点是在低版本react-amap的基础上。官方推荐使用聚合useCluster属性来优化海量点的渲染。 直接附上代码&#xff1a; import React, { Component } from "react"…...

GRU(门控循环单元)详解

1️⃣ GRU介绍 前面介绍的LSTM可以有效缓解RNN的梯度消失问题&#xff0c;但是其内部结构比较复杂&#xff0c;因此衍生出了更加简化的GRU。GRU把输入门和遗忘门整合成一个更新门&#xff0c;并且合并了细胞状态和隐藏状态。于2014年被提出 2️⃣ 原理介绍 GRU的结构和最简单…...

【代码随想录|回溯算法排列问题】

491.非减子序列 题目链接. - 力扣&#xff08;LeetCode&#xff09; 这里和子集问题||很像&#xff0c;但是这里要的是非递减的子序列&#xff0c;要按照给的数组的顺序来进行排序&#xff0c;就是如果我给定的数组是[4,4,3,2,1]&#xff0c;如果用子集||的做法先进行排序得到…...

Azure Kubernetes Service (AKS)资源优化策略

针对Azure Kubernetes Service (AKS)的资源优化策略&#xff0c;可以从多个维度进行考虑和实施&#xff0c;以提升集群的性能、效率和资源利用率。以下是一些关键的优化策略&#xff1a; 一、 Pod资源请求和限制 设置Pod请求和限制&#xff1a;在YAML清单中为所有Pod设置CPU和…...

R语言 | 宽数据变成一列,保留对应的行名和列名

对应稀疏矩阵 转为 宽数据框&#xff0c;见 数据格式转换 | 稀疏矩阵3列还原为原始矩阵/数据框&#xff0c;自定义函数 df3toMatrix() 目的&#xff1a;比如查看鸢尾花整体的指标分布&#xff0c;4个指标分开&#xff0c;画到一个图中。每个品种画一个图。 1.数据整理&#…...

RTSP播放器EasyPlayer.js播放器在webview环境下,PC和安卓能够正常播放,IOS环境下播放器会黑屏无法播放

流媒体技术分为顺序流式传输和实时流式传输两种。顺序流式传输允许用户在下载的同时观看&#xff0c;而实时流式传输则允许用户实时观看内容。 流媒体播放器负责解码和呈现内容&#xff0c;常见的播放器包括VLC和HTML5播放器等。流媒体技术的应用场景广泛&#xff0c;包括娱乐…...

.NET周刊【11月第3期 2024-11-17】

国内文章 .NET 9使用Scalar替代Swagger https://www.cnblogs.com/netry/p/18543378/scalar-an-alternative-to-swagger-in-dotnet-9 .NET 9 移除了 Swashbuckle.AspNetCore&#xff0c;因为其维护不力&#xff0c;并转向 Microsoft.AspNetCore.OpenApi。除了 Swashbuckle&am…...

c语言数据22数组使用

1.1数组分配的空间 int a[10]{1,2,3,4,5,6,7,8,9,10};//分配空间 元素类型大小int4*元素个数1040byte 元素之间空间连续 数组名代表数组首元素地址&#xff1b;a 取的是a[0]的地址&#xff1b;&a 是整个数组的地址 说明&#xff1a; 数组首元素地址&#xff1a; 0号元…...

深入理解TensorFlow中的形状处理函数

摘要 在深度学习模型的构建过程中&#xff0c;张量&#xff08;Tensor&#xff09;的形状管理是一项至关重要的任务。特别是在使用TensorFlow等框架时&#xff0c;确保张量的形状符合预期是保证模型正确运行的基础。本文将详细介绍几个常用的形状处理函数&#xff0c;包括get_…...

MySQL数据库3——函数与约束

一.函数 1.字符串函数 MySQL中内置了很多字符串函数&#xff0c;常用的几个如下&#xff1a; 使用方法&#xff1a; SELECT 函数名(参数);注意&#xff1a;MySQL中的索引值即下标都是从1开始的。 2.数值函数 常见的数值函数如下&#xff1a; 使用方法&#xff1a; SELECT…...

⾃动化运维利器 Ansible-Jinja2

Ansible-Jinja2 一、Ansible Jinja2模板背景介绍二、 JinJa2 模板2.1 JinJa2 是什么2.2 JinJa2逻辑控制 三、如何使用模板四、实例演示 按顺序食用&#xff0c;口味更佳 ( 1 ) ⾃动化运维利器Ansible-基础 ( 2 ) ⾃动化运维利器 Ansible-Playbook ( 3 ) ⾃动化运维利器 Ansible…...

博客文章怎么设计分类与标签

首发地址&#xff08;欢迎大家访问&#xff09;&#xff1a;博客文章怎么设计分类与标签 新网站基本上算是迁移完了&#xff0c;迁移之后在写文章的过程中&#xff0c;发现个人的文章分类和标签做的太混乱了&#xff0c;分类做的像标签&#xff0c;标签也不是特别的丰富&#x…...

FastDDS之DataSharing

目录 原理说明限制条件配置Data-Sharing delivery kindData-sharing domain identifiers最大domain identifiers数量共享内存目录 DataReader和DataWriter的history耦合DataAck阻塞复用 本文详细记录Fast DDS中Data Sharing的实现原理和代码分析。 DataSharing的概念&#xff1…...

计算机网络在线测试-概述

单项选择题 第1题 数据通信中&#xff0c;数据传输速率&#xff08;比特率&#xff0c;bps&#xff09;是指每秒钟发送的&#xff08;&#xff09;。 二进制位数 &#xff08;我的答案&#xff09; 符号数 字节数 码元数 第2题 一座大楼内的一个计算机网络系统&#xf…...

【MySQL】数据库必考知识点:查询操作全面详解与深度解剖

前言&#xff1a;本节内容讲述基本查询&#xff0c; 基本查询要分为两篇文章进行讲解。 本篇文章主要讲解的是表内删除数据、查询结果进行插入、聚合统计、分组聚合统计。 如果想要学习对应知识的可以观看哦。 ps:本篇内容友友们只要会创建表了就可以看起来了哦&#xff01;&am…...

鲸鱼机器人和乐高机器人的比较

鲸鱼机器人和乐高机器人各有其独特的优势和特点&#xff0c;家长在选择时可以根据孩子的年龄、兴趣、经济能力等因素进行综合考虑&#xff0c;选择最适合孩子的教育机器人产品。 优势 鲸鱼机器人 1&#xff09;价格亲民&#xff1a;鲸鱼机器人的产品价格相对乐高更为亲民&…...

游戏引擎学习第15天

视频参考:https://www.bilibili.com/video/BV1mbUBY7E24 关于游戏中文件输入输出&#xff08;IO&#xff09;操作的讨论。主要分为两类&#xff1a; 只读资产的加载 这部分主要涉及游戏中用于展示和运行的只读资源&#xff0c;例如音乐、音效、美术资源&#xff08;如 3D 模型和…...

详解模版类pair

目录 一、pair简介 二、 pair的创建 三、pair的赋值 四、pair的排序 &#xff08;1&#xff09;用sort默认排序 &#xff08;2&#xff09;用sort中的自定义排序进行排序 五、pair的交换操作 一、pair简介 pair是一个模版类&#xff0c;可以存储两个值的键值对.first以…...

AI驱动的桌面笔记应用Reor

网友 竹林风 说&#xff0c;已经成功的用 mxbai-embed-large 映射到 text-embedding-ada-002&#xff0c;并测试成功了。不愧是爱折腾的人&#xff0c;老苏还没时间试&#xff0c;因为又找到了另一个支持 AI 的桌面版笔记 Reor Reor 简介 什么是 Reor ? Reor 是一款由人工智…...

搜维尔科技:使用sensglove触觉反馈手套进行虚拟拆装操作

使用sensglove触觉反馈手套进行虚拟拆装操作 搜维尔科技&#xff1a;使用sensglove触觉反馈手套进行虚拟拆装操作...

深入理解电子邮件安全:SPF、DKIM 和 DMARC 完全指南

引言 在当今数字时代&#xff0c;电子邮件已经成为我们日常通信中不可或缺的一部分。然而&#xff0c;随之而来的安全问题也日益突出。邮件欺诈、钓鱼攻击和垃圾邮件等威胁不断增加&#xff0c;这促使了多种邮件安全验证机制的出现。本文将深入探讨三个最重要的邮件安全协议&a…...

【有啥问啥】复习一下什么是NMS(非极大值抑制)?

复习一下什么是NMS&#xff08;非极大值抑制&#xff09;&#xff1f; 什么是NMS&#xff1f; NMS&#xff08;Non-Maximum Suppression&#xff09;即非极大值抑制&#xff0c;是一种在计算机视觉领域&#xff0c;尤其是目标检测任务中广泛应用的后处理算法。其核心思想是抑…...

Java-异步方法@Async+自定义分布式锁注解Redission

如果你在使用 @Async 注解的异步方法中,使用了自定义的分布式锁注解(例如 @DistributedLock),并且锁到期后第二个请求并没有执行,这可能是由于以下几个原因导致的: 锁的超时时间设置不当:锁的超时时间可能设置得太短,导致锁在业务逻辑执行完成之前就已经自 动释放。…...

基本定时器---内/外部时钟中断

一、定时器的概念 定时器&#xff08;TIM&#xff09;&#xff0c;可以对输入的时钟信号进行计数&#xff0c;并在计数值达到设定值的时候触发中断。 STM32的定时器系统有一个最为重要的结构是时基单元&#xff0c;它由一个16位计数器&#xff0c;预分频器&#xff0c;和自动重…...

实现了两种不同的图像处理和物体检测方法

这段代码实现了两种不同的图像处理和物体检测方法&#xff1a;一种是基于Canny边缘检测与轮廓分析的方法&#xff0c;另一种是使用TensorFlow加载预训练SSD&#xff08;Single Shot Multibox Detector&#xff09;模型进行物体检测。 1. Canny边缘检测与轮廓分析&#xff1a; …...

如何在MindMaster思维导图中制作PPT课件?

思维导图是一种利用色彩、图画、线条等图文并茂的形式&#xff0c;来帮助人们增强知识或者事件的记忆。因此&#xff0c;思维导图也被常用于教育领域&#xff0c;比如&#xff1a;教学课件、读书笔记、时间管理等等。那么&#xff0c;在MindMaster免费思维导图软件中&#xff0…...

ORIN NX 16G安装中文输入法

刷机版本为jetpack5.14.刷机之后预装了cuda、cudnn、opencv、tensorrt等&#xff0c;但是发现没有中文输入&#xff0c;所以记录一下安装流程。 jetson NX是arm64架构的&#xff0c;sougoupinyin只支持adm架构的&#xff0c;所以要选择安装Google pinyin 首先打开终端&#x…...

【金融风控项目-07】:业务规则挖掘案例

文章目录 1.规则挖掘简介2 规则挖掘案例2.1 案例背景2.2 规则挖掘流程2.3 特征衍生2.4 训练决策树模型2.5 利用结果划分分组 1.规则挖掘简介 两种常见的风险规避手段&#xff1a; AI模型规则 如何使用规则进行风控 **使用一系列逻辑判断(以往从职人员的经验)**对客户群体进行区…...

退款成功订阅消息点击后提示订单不存在

问题表现&#xff1a; 退款成功发送的小程序订阅消息点击进入后提示订单不存在。 修复方法&#xff1a; 1.打开文件app/services/message/notice/RoutineTemplateListService.php 2.找到方法sendOrderRefundSuccess 3.修改图中红圈内的链接地址 完整方法代码如下 /*** 订…...

实验一 顺序结构程序设计

《大学计算机&#xfe63;C语言版》实验报告 实验名称 实验一 顺序结构程序设计 实验目的 &#xff08;1&#xff09;掌握C语言中常量和变量的概念。 &#xff08;2&#xff09;掌握C语言中常见的数据类型。 &#xff08;3&#xff09;掌握C语言中变量的定义和赋值方法。 …...

深圳做网站优化/推广app用什么平台比较好

LINK 题目大意 有一些猫&#xff0c;放在一些位置&#xff0c;人一步移动一个位置 给出每个猫出现的时间&#xff0c;每个人可以自由安排其出发时间&#xff0c;沿途已经出现的猫捡起&#xff0c;猫等待的时间是被减去的时间减去出现的时间 猫可以等人&#xff0c;人不能等猫 现…...

辽宁新闻网站的建设/软文推广多少钱

在北半球&#xff0c;3月是春季的第一个月&#xff0c;春天象征着希望和美好。关注我的读者大多数都是&#xff08;程序&#xff09;猿&#xff0c;所以好用的键盘必不可少&#xff01;今天为了感谢大家对本公众号的大力支持我联合了10个号主送11个炫酷键盘&#xff0c;不爱可折…...

网址关键词查询网站/网络营销的特征和功能

1.开篇介绍 在开始看本篇文章之前先允许我打断一下各位的兴致。其实这篇文章本来是没有打算加“开篇介绍”这一小节的&#xff0c;后来想想还是有必要反馈一下读者的意见。经过前三篇文章的详细讲解&#xff0c;我们基本上对LINQ框架的构成原理有了一个根本的认识&#xff0c;…...

北京高级网站建设/营业推广方案

什么是事件事件是视图层到逻辑层的通讯方式。事件可以将用户的行为反馈到逻辑层进行处理。事件可以绑定在组件上&#xff0c;当达到触发事件&#xff0c;就会执行逻辑层中对应的事件处理函数。事件对象可以携带额外信息&#xff0c;如 id&#xff0c; dataset&#xff0c; touc…...

it外包wordpress模板/信息流广告投放公司

CentOS 6.5 系统配置nfs服务 了解一下什么是nfs 网络文件系统&#xff08;Network File System&#xff0c;NFS&#xff09;&#xff0c;一种使用于分散式文件系统的协议&#xff0c;由升阳公司开发&#xff0c;于1984年向外公布。功能是通过网络让不同的机器、不同的操作系统能…...

专业营销网站建设/网推平台

路由条目进入路由表的前提条件&#xff1a;路由条目的“下一跳”&#xff0c;必须可达&#xff1b;即路由条目中的网段后面的端口和IP地址&#xff0c;必须是可以访问的&#xff1b;如果是端口&#xff0c;则必须得是 up / up 的&#xff1b; 如果是IP地址&#xff0c;则必须得…...