商道如狼道 发表于 2024-11-25 00:43:38

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.props

    const l = polygons.length

    const _polygons = []

    for (let i = 0; i < l; i++) {
      const detail = polygons
      if (detail.geoArea && detail.geoArea.length) {
      let _polygonType = polygonType.normal
      if (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.state
    if (!infoWindowPosition) {
      return null
    }

    return <InfoWindow
      position={{
      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={}
      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.state
    if (!data) {
      return null;
    }
    const locTypeItem = locTypes.find(t=>t.domVal==data.locType)
    const tds = (
      <divclassName={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 (
      <InfoWindow
      position={position}
      visible={visible}
      isCustom={true}
      offset={}
      >
      {tds}
      </InfoWindow>
    );
};
pointRender = (extData) => {
    return (
      <div
      style={{
          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>
                <Switch
                  checkedChildren="显示地点"
                  unCheckedChildren="显示地点"
                  checked={pointReferShow}
                  onChange={this.changePointReferShow}
                />
            </Form.Item>
            </Form>
      </ActionsForm>
      <Map {...option}>
          <Markers
          markers={pointReferData}
          offset={}
          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;
    const lastLocation = paths;
    if (
      firstLocation === lastLocation &&
      firstLocation === lastLocation
    ) {
      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,
      : _groups
          .filter(group => !group.lines.length)
          .map(group => ({
            ...group,
            lines: []
          })),
      : _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 zoneDetail
   
          return polygons
      }, [])
      }
    }

    const newData = prepareGroups(areaReferData)
    const polygons = newData.polygons
    const l = polygons.length
    const _polygons = []
    for (let i = 0; i < l; i++) {
      const detail = polygons
      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.state
    if(showLabels){
      if (!infoWindowPosition) {
      return null
      }

      return <InfoWindow
      position={{
          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={}
      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 (
      <div
      style={{
          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.state
    if (!data) {
      return null;
    }
    const locTypeItem = locTypes.find(t=>t.domVal==data.locType)
    const tds = (
      <divclassName={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 (
      <InfoWindow
      position={position}
      visible={visible}
      isCustom={true}
      offset={}
      >
      {tds}
      </InfoWindow>
    );
};
// polygon edit switch
togglePolygon = (checked, e) => {
    if (checked) {
      // open edit and close add if it is drawing
      if (this.mouseTool) {
      this.mouseTool.close();
      }
      this.setState({ polygonActive: true, isDrawingPolygon: false });
    } else {
      // close edit
      this.setState({ polygonActive: false });
    }
};

// polygon add switch
toggleDrawPolygon = (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 draw
drawWhat = (obj) => {
    const paths = obj.getPath();
    let data = this.state.data.slice();
    const pathData = paths.map((item) => );
    if (pathData.length > 2) {
      if (this.amap) {
      this.amap.remove(obj);
      }
      data.push(_getClosedPolygon(pathData));
      this.setState({ data });
      message.success(
      `您成功绘制了一个${
          paths.length
      }边形,可继续绘制或点击结束多边形绘制按钮`
      );
    }
};

// polygon editor end
polyEditorEnd = (target, type) => {
    const paths = target.getPath();
    let isSinglePath = false; // 是否是单围栏
    const pathData = paths.map((item, index) => {
      if (Array.isArray(item)) {
      const itemPaths = item.map((element) => );
      return _getClosedPolygon(itemPaths);
      } else {
      isSinglePath = true;
      return ;
      }
    });
    this.setState({
      data: isSinglePath ? : 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 });
};

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) ? json.districts.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 data
      isomorphicFetch(
          `//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
                ? json.districts.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>
                <Popconfirm
                  title={
                  <ZoneCascader
                      adcode={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>
                <Switch
                  disabled={mapEditable === "N"}
                  checkedChildren="调整"
                  unCheckedChildren="调整"
                  checked={polygonActive}
                  onChange={this.togglePolygon}
                />
            </Form.Item>
            <Form.Item>
                <Switch
                  disabled={mapEditable === "N"}
                  checkedChildren="新增"
                  unCheckedChildren="新增"
                  checked={isDrawingPolygon}
                  onChange={this.toggleDrawPolygon}
                />
            </Form.Item>
            <Form.Item>
                <Dropdown
                  overlay={
                  <Menu onClick={this.handleMenuClick}>
                      {data &&
                        data.length > 0 &&
                        data.map((item, index) => (
                        <Menu.Item key={index}>
                            <span
                              onMouseOver={() => 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>
                <Switch
                  checkedChildren="显示地点"
                  unCheckedChildren="显示地点"
                  checked={pointReferShow}
                  onChange={this.changePointReferShow}
                />
            </Form.Item>
            <Form.Item>
                <Switch
                  checkedChildren="显示其他区域"
                  unCheckedChildren="显示其他区域"
                  checked={areaReferShow}
                  onChange={this.changeAreaReferShow}
                />
            </Form.Item>
            <Form.Item>
                <Switch
                  checkedChildren="显示区域名称"
                  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}>
          <Markers
            markers={pointReferData}
            offset={}
            render={this.pointRender}
            events={this.markerEvents}
            useCluster={useCluster}
          />
          {isGroup && <MouseTool events={this.toolEvents} />}
          {isGroup ? (
            <Polygon
            path={data}
            style={{ fillOpacity: 0.3, strokeOpacity: 0.5, strokeWeight: 1 }}
            events={this.polygonEvents}
            >
            <PolyEditor
                active={
                  polygonActive && data.length > 0 && data.flat().length <= 100
                }
                events={this.polyEditorEvents}
            />
            </Polygon>
          ) : (
            data.map((item, index) => (
            <Polygon
                events={this.polygonEvents}
                key={index}
                path={item}
                style={{
                  fillOpacity: 0.3,
                  strokeOpacity: 0.5,
                  strokeWeight: 1,
                }}
            />
            ))
          )}
          <Polygon
            visible={deleteMenuVisible}
            path={}
            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;


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: react-amap海量点优化