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海量点优化
前言:高版本的react-amap 支持MassMarkers 组件用于一次性添加大量的标记点。本次优化的海量点是在低版本react-amap的基础上。官方推荐使用聚合useCluster属性来优化海量点的渲染。 直接附上代码: import React, { Component } from "react"…...
GRU(门控循环单元)详解
1️⃣ GRU介绍 前面介绍的LSTM可以有效缓解RNN的梯度消失问题,但是其内部结构比较复杂,因此衍生出了更加简化的GRU。GRU把输入门和遗忘门整合成一个更新门,并且合并了细胞状态和隐藏状态。于2014年被提出 2️⃣ 原理介绍 GRU的结构和最简单…...
【代码随想录|回溯算法排列问题】
491.非减子序列 题目链接. - 力扣(LeetCode) 这里和子集问题||很像,但是这里要的是非递减的子序列,要按照给的数组的顺序来进行排序,就是如果我给定的数组是[4,4,3,2,1],如果用子集||的做法先进行排序得到…...
Azure Kubernetes Service (AKS)资源优化策略
针对Azure Kubernetes Service (AKS)的资源优化策略,可以从多个维度进行考虑和实施,以提升集群的性能、效率和资源利用率。以下是一些关键的优化策略: 一、 Pod资源请求和限制 设置Pod请求和限制:在YAML清单中为所有Pod设置CPU和…...
R语言 | 宽数据变成一列,保留对应的行名和列名
对应稀疏矩阵 转为 宽数据框,见 数据格式转换 | 稀疏矩阵3列还原为原始矩阵/数据框,自定义函数 df3toMatrix() 目的:比如查看鸢尾花整体的指标分布,4个指标分开,画到一个图中。每个品种画一个图。 1.数据整理&#…...
RTSP播放器EasyPlayer.js播放器在webview环境下,PC和安卓能够正常播放,IOS环境下播放器会黑屏无法播放
流媒体技术分为顺序流式传输和实时流式传输两种。顺序流式传输允许用户在下载的同时观看,而实时流式传输则允许用户实时观看内容。 流媒体播放器负责解码和呈现内容,常见的播放器包括VLC和HTML5播放器等。流媒体技术的应用场景广泛,包括娱乐…...
.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,因为其维护不力,并转向 Microsoft.AspNetCore.OpenApi。除了 Swashbuckle&am…...
c语言数据22数组使用
1.1数组分配的空间 int a[10]{1,2,3,4,5,6,7,8,9,10};//分配空间 元素类型大小int4*元素个数1040byte 元素之间空间连续 数组名代表数组首元素地址;a 取的是a[0]的地址;&a 是整个数组的地址 说明: 数组首元素地址: 0号元…...
深入理解TensorFlow中的形状处理函数
摘要 在深度学习模型的构建过程中,张量(Tensor)的形状管理是一项至关重要的任务。特别是在使用TensorFlow等框架时,确保张量的形状符合预期是保证模型正确运行的基础。本文将详细介绍几个常用的形状处理函数,包括get_…...
MySQL数据库3——函数与约束
一.函数 1.字符串函数 MySQL中内置了很多字符串函数,常用的几个如下: 使用方法: SELECT 函数名(参数);注意:MySQL中的索引值即下标都是从1开始的。 2.数值函数 常见的数值函数如下: 使用方法: SELECT…...
⾃动化运维利器 Ansible-Jinja2
Ansible-Jinja2 一、Ansible Jinja2模板背景介绍二、 JinJa2 模板2.1 JinJa2 是什么2.2 JinJa2逻辑控制 三、如何使用模板四、实例演示 按顺序食用,口味更佳 ( 1 ) ⾃动化运维利器Ansible-基础 ( 2 ) ⾃动化运维利器 Ansible-Playbook ( 3 ) ⾃动化运维利器 Ansible…...
博客文章怎么设计分类与标签
首发地址(欢迎大家访问):博客文章怎么设计分类与标签 新网站基本上算是迁移完了,迁移之后在写文章的过程中,发现个人的文章分类和标签做的太混乱了,分类做的像标签,标签也不是特别的丰富&#x…...
FastDDS之DataSharing
目录 原理说明限制条件配置Data-Sharing delivery kindData-sharing domain identifiers最大domain identifiers数量共享内存目录 DataReader和DataWriter的history耦合DataAck阻塞复用 本文详细记录Fast DDS中Data Sharing的实现原理和代码分析。 DataSharing的概念࿱…...
计算机网络在线测试-概述
单项选择题 第1题 数据通信中,数据传输速率(比特率,bps)是指每秒钟发送的()。 二进制位数 (我的答案) 符号数 字节数 码元数 第2题 一座大楼内的一个计算机网络系统…...
【MySQL】数据库必考知识点:查询操作全面详解与深度解剖
前言:本节内容讲述基本查询, 基本查询要分为两篇文章进行讲解。 本篇文章主要讲解的是表内删除数据、查询结果进行插入、聚合统计、分组聚合统计。 如果想要学习对应知识的可以观看哦。 ps:本篇内容友友们只要会创建表了就可以看起来了哦!&am…...
鲸鱼机器人和乐高机器人的比较
鲸鱼机器人和乐高机器人各有其独特的优势和特点,家长在选择时可以根据孩子的年龄、兴趣、经济能力等因素进行综合考虑,选择最适合孩子的教育机器人产品。 优势 鲸鱼机器人 1)价格亲民:鲸鱼机器人的产品价格相对乐高更为亲民&…...
游戏引擎学习第15天
视频参考:https://www.bilibili.com/video/BV1mbUBY7E24 关于游戏中文件输入输出(IO)操作的讨论。主要分为两类: 只读资产的加载 这部分主要涉及游戏中用于展示和运行的只读资源,例如音乐、音效、美术资源(如 3D 模型和…...
详解模版类pair
目录 一、pair简介 二、 pair的创建 三、pair的赋值 四、pair的排序 (1)用sort默认排序 (2)用sort中的自定义排序进行排序 五、pair的交换操作 一、pair简介 pair是一个模版类,可以存储两个值的键值对.first以…...
AI驱动的桌面笔记应用Reor
网友 竹林风 说,已经成功的用 mxbai-embed-large 映射到 text-embedding-ada-002,并测试成功了。不愧是爱折腾的人,老苏还没时间试,因为又找到了另一个支持 AI 的桌面版笔记 Reor Reor 简介 什么是 Reor ? Reor 是一款由人工智…...
搜维尔科技:使用sensglove触觉反馈手套进行虚拟拆装操作
使用sensglove触觉反馈手套进行虚拟拆装操作 搜维尔科技:使用sensglove触觉反馈手套进行虚拟拆装操作...
深入理解电子邮件安全:SPF、DKIM 和 DMARC 完全指南
引言 在当今数字时代,电子邮件已经成为我们日常通信中不可或缺的一部分。然而,随之而来的安全问题也日益突出。邮件欺诈、钓鱼攻击和垃圾邮件等威胁不断增加,这促使了多种邮件安全验证机制的出现。本文将深入探讨三个最重要的邮件安全协议&a…...
【有啥问啥】复习一下什么是NMS(非极大值抑制)?
复习一下什么是NMS(非极大值抑制)? 什么是NMS? NMS(Non-Maximum Suppression)即非极大值抑制,是一种在计算机视觉领域,尤其是目标检测任务中广泛应用的后处理算法。其核心思想是抑…...
Java-异步方法@Async+自定义分布式锁注解Redission
如果你在使用 @Async 注解的异步方法中,使用了自定义的分布式锁注解(例如 @DistributedLock),并且锁到期后第二个请求并没有执行,这可能是由于以下几个原因导致的: 锁的超时时间设置不当:锁的超时时间可能设置得太短,导致锁在业务逻辑执行完成之前就已经自 动释放。…...
基本定时器---内/外部时钟中断
一、定时器的概念 定时器(TIM),可以对输入的时钟信号进行计数,并在计数值达到设定值的时候触发中断。 STM32的定时器系统有一个最为重要的结构是时基单元,它由一个16位计数器,预分频器,和自动重…...
实现了两种不同的图像处理和物体检测方法
这段代码实现了两种不同的图像处理和物体检测方法:一种是基于Canny边缘检测与轮廓分析的方法,另一种是使用TensorFlow加载预训练SSD(Single Shot Multibox Detector)模型进行物体检测。 1. Canny边缘检测与轮廓分析: …...
如何在MindMaster思维导图中制作PPT课件?
思维导图是一种利用色彩、图画、线条等图文并茂的形式,来帮助人们增强知识或者事件的记忆。因此,思维导图也被常用于教育领域,比如:教学课件、读书笔记、时间管理等等。那么,在MindMaster免费思维导图软件中࿰…...
ORIN NX 16G安装中文输入法
刷机版本为jetpack5.14.刷机之后预装了cuda、cudnn、opencv、tensorrt等,但是发现没有中文输入,所以记录一下安装流程。 jetson NX是arm64架构的,sougoupinyin只支持adm架构的,所以要选择安装Google pinyin 首先打开终端&#x…...
【金融风控项目-07】:业务规则挖掘案例
文章目录 1.规则挖掘简介2 规则挖掘案例2.1 案例背景2.2 规则挖掘流程2.3 特征衍生2.4 训练决策树模型2.5 利用结果划分分组 1.规则挖掘简介 两种常见的风险规避手段: AI模型规则 如何使用规则进行风控 **使用一系列逻辑判断(以往从职人员的经验)**对客户群体进行区…...
退款成功订阅消息点击后提示订单不存在
问题表现: 退款成功发送的小程序订阅消息点击进入后提示订单不存在。 修复方法: 1.打开文件app/services/message/notice/RoutineTemplateListService.php 2.找到方法sendOrderRefundSuccess 3.修改图中红圈内的链接地址 完整方法代码如下 /*** 订…...
实验一 顺序结构程序设计
《大学计算机﹣C语言版》实验报告 实验名称 实验一 顺序结构程序设计 实验目的 (1)掌握C语言中常量和变量的概念。 (2)掌握C语言中常见的数据类型。 (3)掌握C语言中变量的定义和赋值方法。 …...
深圳做网站优化/推广app用什么平台比较好
LINK 题目大意 有一些猫,放在一些位置,人一步移动一个位置 给出每个猫出现的时间,每个人可以自由安排其出发时间,沿途已经出现的猫捡起,猫等待的时间是被减去的时间减去出现的时间 猫可以等人,人不能等猫 现…...
辽宁新闻网站的建设/软文推广多少钱
在北半球,3月是春季的第一个月,春天象征着希望和美好。关注我的读者大多数都是(程序)猿,所以好用的键盘必不可少!今天为了感谢大家对本公众号的大力支持我联合了10个号主送11个炫酷键盘,不爱可折…...
网址关键词查询网站/网络营销的特征和功能
1.开篇介绍 在开始看本篇文章之前先允许我打断一下各位的兴致。其实这篇文章本来是没有打算加“开篇介绍”这一小节的,后来想想还是有必要反馈一下读者的意见。经过前三篇文章的详细讲解,我们基本上对LINQ框架的构成原理有了一个根本的认识,…...
北京高级网站建设/营业推广方案
什么是事件事件是视图层到逻辑层的通讯方式。事件可以将用户的行为反馈到逻辑层进行处理。事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。事件对象可以携带额外信息,如 id, dataset, touc…...
it外包wordpress模板/信息流广告投放公司
CentOS 6.5 系统配置nfs服务 了解一下什么是nfs 网络文件系统(Network File System,NFS),一种使用于分散式文件系统的协议,由升阳公司开发,于1984年向外公布。功能是通过网络让不同的机器、不同的操作系统能…...
专业营销网站建设/网推平台
路由条目进入路由表的前提条件:路由条目的“下一跳”,必须可达;即路由条目中的网段后面的端口和IP地址,必须是可以访问的;如果是端口,则必须得是 up / up 的; 如果是IP地址,则必须得…...