/**
 * @description  地图SDK
 * @author       朱琦
 * @date         2021/11/12 13:23
 */

import cityCodeJson from "../../../static/json/map-code.json";
import { createMapIcon, getIconSize } from "./map-icon";
import mapPublic from "./map-public";
import { isValidPath } from "../../public-function";
import { labelIndex } from "../../config/map-default-config";

class MapSdk {
  constructor(map, mapId, mapConfig, pointClick) {
    this.initMapConfig(map, mapId, mapConfig);
    this.pointClick = pointClick;
  }

  /**
   * 配置基础参数
   */
  initMapConfig(map, mapId, mapConfig) {
    this.map = map;
    this.mapId = mapId;
    this.mapConfig = mapConfig;
    // 当前选中点位
    this.currentClickMarker = null;
    // 当前选中（悬浮）的信息标签（用marker实现）
    this.currentInfoLabel = new AMap.Marker({
      // map: this.map,
      content: " ",
      // anchor: 'bottom-center',
      zIndex: labelIndex
    });
    // 当前版本
    this.version = window.AMap.version === "2.0" ? 2 : 1.4;

    this.initTheme(mapConfig.theme);
    try {
      setTimeout(this.initMapPlugins());
    } catch (error) {
      console.error("map sdk init error, " + error);
    }
  }
  /**
   * 初始化主题配置
   * @param {String} theme 主题类型
   */
  initTheme(theme) {
    this.theme = theme;
    this.mapIconClass = createMapIcon(theme);
  }
  /**
   * 修改主题配置
   * @param {String} theme 主题类型
   */
  setTheme(theme, mapStyle) {
    if (theme === this.theme) return;
    this.initTheme(theme);
    this.setMvMapStyle(mapStyle);
  }
  /**
   * 配置地图基础插件
   */
  initMapPlugins() {
    this.mouseTool = new AMap.MouseTool(this.map);
    this.mouseToolLayer = {};
  }

  /**
   * 获取地图实例
   * @returns 地图实例
   */
  getMvMap() {
    return this.map;
  }

  /**
   * 获取地图中心点
   * @returns 地图中心点坐标
   */
  getMvMapCenter() {
    return this.map.getCenter();
  }

  /**
   * 获取地图层级
   * @returns 地图当前层级
   */
  getMvMapZoom() {
    return this.map.getZoom();
  }

  /**
   * 清除地图所有的覆盖物
   */
  clearMvMap() {
    return this.map.clearMap();
  }

  /**
   * 添加旋转、倾斜、复位、缩放在内的地图控件
   * @param {Object} config 配置
   * @returns
   */
  addMvMapControlBar(config) {
    if (this.mvMapControlBar) return;
    this.mvMapControlBar = new AMap.ControlBar(config);
    this.map.addControl(this.mvMapControlBar);
  }
  /**
   * 移除旋转、倾斜、复位、缩放在内的地图控件
   */
  removeMvMapControlBar() {
    if (this.mvMapControlBar) {
      this.map.removeControl(this.mvMapControlBar);
      this.mvMapControlBar = null;
    }
  }
  /**
   * 设置当前点击marker，不传参数即清除currentClickMarker
   * @param {Object} event 触发点击dom对象
   * @param {Object} point 点位信息
   * @param {Object} config 点位配置
   * @param {Object} iconActiveConfig icon选中配置
   */
  setMvMapClickMarker(point, config, iconActiveConfig) {
    if (this.currentClickMarker) {
      if (point === this.currentClickMarker.getExtData()) {
        return;
      }
      this.removeMvMapMarkerLayer([this.currentClickMarker]);
      this.currentClickMarker = null;
    }
    if (!point) {
      return;
    }
    iconActiveConfig =
      iconActiveConfig ||
      this.mapIconClass.getIconConfig(point.icon + "-active");
    if (iconActiveConfig.name.includes(point.icon)) {
      const data = {
        ...point,
        zooms: point.zooms || null,
        path: point.path,
        icon: iconActiveConfig.name,
        size: point.size || config.size,
        offset: point.offset || config.offset,
        zIndex: (point.zIndex || config.zIndex || 100) + 1,
        // name: config.MARKER_SOURCE === 'Marker' ? point.name : null,
        name: config.hideClickLabel ? null : point.name, // hideClickLabel 隐藏点位点击选择时的label
        createType: config.createType
      };

      const _config = {
        ...config,
        iconSize: null, // 这里iconSize设置为null，是因为当前设置的是点位点击效果，此时data数据里已有size值
        iconFilter:null,
        hasActive: false,
        isCurrentClickMarker: true
      };

      this.currentClickMarker = this.createMvMapMarkerLayer(
        [data],
        _config,
        (e, data) => {
          // this.pointClick(e, config.MARKER_SOURCE === 'MassPoint' ? { ...data, name: point.name } : data, config)
          this.pointClick(e, { ...data, name: point.name }, config);
        }
      )[0];
    }
  }
  /**
   * 偏移量有问题，暂不用
   * 设置当前展示的信息label
   * @param {Object} data 数据
   * @param {} config
   * @returns
   */
  setMvMapInfoLabel(data, config) {
    if (!data) {
      // 没有传参时，隐藏
      this.currentInfoLabel.hide();
      return;
    }

    if (!data.name || !data.path) return;

    // this.currentInfoLabel.setContent(`<div class="amap-marker-label">${data.name}</div>`)
    this.currentInfoLabel.setPosition(data.path);
    this.currentInfoLabel.setLabel({ content: data.name, direction: "top" });
    this.currentInfoLabel.setMap(this.map);
    this.currentInfoLabel.show();
  }

  /**
   * 修改地图样式
   * @param {String} mapStyle 地图样式
   */
  setMvMapStyle(mapStyle) {
    this.map.setMapStyle(mapStyle);
  }

  /**
   * 地图中点移动（层级/中心）
   * @param center 中心点坐标 [lng,lat]
   * @param zoom   层级
   * @param zoomType   层级类型 可选'min' 'max'
   */
  setMvMapCenterAndZoom(center, zoom, zoomType = null) {
    if (zoom) {
      const currentZoom = this.map.getZoom();
      let num = zoom;
      if (zoomType === "min") {
        // 最小层级
        num = currentZoom > zoom ? currentZoom : zoom;
      }
      if (zoomType === "max") {
        // 最大层级
        num = currentZoom > zoom ? zoom : currentZoom;
      }
      this.map.setZoom(num);
    }

    if (Array.isArray(center)) {
      this.map.setCenter(center);
    }
  }

  /**
   * 设置地图显示范围
   * @param southWestLngLat([lng,lat])-Array
   * @param northEastLngLat([lng,lat])-Array
   */
  setMvMapBounds(southWestLngLat, northEastLngLat) {
    this.map.setBounds(new AMap.Bounds(southWestLngLat, northEastLngLat));
  }

  /**
   * 设置地图可拖动区域
   * @param southWestLngLat([lng,lat])-Array
   * @param northEastLngLat([lng,lat])-Array
   */
  setMvMapLimitBounds(southWestLngLat, northEastLngLat) {
    this.map.setLimitBounds(new AMap.Bounds(southWestLngLat, northEastLngLat));
  }

  /**
   * 清除地图限制拖动区域
   */
  clearMvMapLimitBounds() {
    this.map.clearLimitBounds();
  }

  /**
   * 设置地图显示元素
   * @param features( ['bg','point','road','building'] )-Array
   *          -- bg       地图背景
   *          -- point    兴趣点
   *          -- road     道路
   *          -- building 建筑物
   */
  setMvMapFeatures(features) {
    this.map.setFeatures(features);
  }

  /**
   * 创建Marker标记点图层
   * @param data
   *          -- icon: [] -Array (['icon-gl-etc','icon-gl-etc-active'])
   *          -- path: [lng,lat]
   *          -- name: ''
   *          -- offset:[0,0]
   *          -- hasClickStatus:false
   * @param config 配置
   *          -- hasClickStatus
   *          -- iconFilter
   *          -- iconSize
   *          -- hasActive 是否有选中状态
   *
   * @param callback 回调
   *          -- e 点击marker对象
   *          -- item 点击marker数据
   *
   * @returns markers实例
   */
  createMvMapMarkerLayer(data, config = {}, callback) {
    const list = data.constructor === Array ? data : [data];
    const markers = [];
    if (list && list.length) {
      list.map((item) => {
        const marker = this.createMvMapMarker(item, config, callback);
        markers.push(marker);
      });
      this.map.add(markers);
    }
    return data.constructor === Array ? markers : markers[0];
  }
  /**
   * 创建marker
   * @param {Object} data 数据 或 marker
   * @param {Object} config 配置
   *                 - hasActive 是否有选中状态
   * @param {Function} callback 点击回调
   * @returns marker
   */
  createMvMapMarker(data, config, callback) {
    config = { hasActive: true, ...config };
    let marker = null;
    let item = null;

    if (data.className === "AMap.Marker") {
      // 已创建marker - 点聚合
      marker = data;
      item = marker.getExtData();
    } else {
      item = data;
    }

    const zIndex = item.zIndex || config.zIndex || 100;
    let icon;
    let offset = [0, 0];
    let iconOptions;
    // 图标打点配置
    if (!item.content) {
      iconOptions = this.mapIconClass.getMarkerIcon(item, config);

      icon = new AMap.Icon(iconOptions);

      const size = this.getMvMapIconSize(icon);
      // 设置默认偏移量
      offset = [-size[0] / 2, -size[1] / 2];
    }

    offset = item.offset || offset;

    const offsetPixel = new AMap.Pixel(offset[0], offset[1]);
    if (!marker) {
      // new marker
      marker = new AMap.Marker({
        ...item,
        // title: item.name,
        icon,
        zIndex,
        position: item.path,
        offset: offsetPixel,
        extData: item
      });
    } else {
      // set marker
      marker.setIcon(icon);
      marker.setOffset(offsetPixel);
    }

    let markerIconConfig = this.getMvMapMarkerIconConfig(marker);

    marker.on("click", (e) => {
      if (!config.isCurrentClickMarker) {
        // 清除之前的点击marker
        this.setMvMapClickMarker();
        if (
          markerIconConfig.hasIconActive &&
          config.hasActive &&
          (item.hasClickStatus || config.hasClickStatus)
        ) {
          // 设置点击效果
          const extData = {
            ...marker.getExtData(),
            size: (iconOptions && iconOptions.pointSize) || item.size,
            offset: item.offset || offset
          };
          this.setMvMapClickMarker(
            extData,
            {
              ...config,
              zIndex,
              MARKER_SOURCE: "Marker"
            },
            markerIconConfig.iconActiveConfig
          );
        }
      }

      callback && callback(e, item, config);
    });

    marker.on("mouseover", (e) => {
      item.name &&
        marker.setLabel({
          offset: new AMap.Pixel(0, -5),
          content: item.name,
          direction: "top"
        });
      // 点位置顶
      marker.setTop(true);

      // this.setMvMapInfoLabel(data)

      // icon 配置发生改变时
      if (markerIconConfig.iconName !== marker.getExtData().icon) {
        markerIconConfig = this.getMvMapMarkerIconConfig(marker);
      }

      // 设置选中样式
      markerIconConfig.hasIconActive &&
        config.hasActive &&
        this.setMvMapMarkerIcon(
          marker,
          markerIconConfig.iconActiveConfig.name,
          true
        );
      // console.log('marker mouseover')
      config.openMouseoverCallback && callback && callback(e, item, config);
    });
    marker.on("mouseout", (e) => {
      // this.setMvMapInfoLabel()
      // 修改marker icon的时候 label会重新出现，不知道原因，所以做了延时解决问题
      item.name && setTimeout(() => marker.setLabel({ content: null }), 10);
      // 取消置顶
      marker.setTop(false);
      // 取消选中样式
      markerIconConfig.hasIconActive &&
        config.hasActive &&
        this.setMvMapMarkerIcon(marker, markerIconConfig.iconName, true);
      // console.log('marker mouseout')
      config.openMouseoverCallback && callback && callback(e, item, config);
    });
    return marker;
  }

  /**
   * 移除Marker标记点
   * @param {Array} markers Marker实例
   * @returns markers实例
   */
  removeMvMapMarkerLayer(markers) {
    if (!markers) return;
    const list = markers.constructor === Array ? markers : [markers];
    list.forEach((marker) => {
      marker.setMap(null);
    });
    return;
  }

  /**
   * 显示Marker标记点
   * @param {Array} markers Marker实例
   */
  showMvMapMarkerLayer(markers) {
    if (!markers) return;
    const list = markers.constructor === Array ? markers : [markers];
    list.forEach((marker) => {
      marker.show();
    });
  }

  /**
   * 隐藏Marker标记点
   * @param {Array} markers Marker实例
   */
  hideMvMapMarkerLayer(markers) {
    if (!markers) return;
    const list = markers.constructor === Array ? markers : [markers];
    list.forEach((marker) => {
      marker.hide();
    });
  }

  /**
   * 修改marker图标
   * @param marker    -marker对象
   * @param icon      -图标名称
   * @param isActive      -是否是设置选中效果 默认false
   */
  setMvMapMarkerIcon(marker, icon, isActive = false) {
    if (icon && marker.getIcon()) {
      const config = {
        icon,
        size: this.getMvMapIconSize(marker.getIcon())
      };
      marker.setIcon(new AMap.Icon(this.mapIconClass.getMarkerIcon(config)));
      if (!isActive) {
        // 不是设置选中效果时
        marker.getExtData().icon = icon;
        // setTimeout(() => marker.setLabel(), 0)
      }
    }
  }
  /**
   * 获取marker 的icon配置
   * @param {Object} marker 点标记对象
   * @returns {Object}
   */
  getMvMapMarkerIconConfig(marker) {
    const iconName = marker.getExtData().icon;
    const iconActiveConfig = this.mapIconClass.getIconConfig(
      iconName + "-active"
    );
    const hasIconActive =
      iconActiveConfig.name.includes(iconName) && iconActiveConfig.url;
    return {
      iconName,
      iconActiveConfig,
      hasIconActive
    };
  }
  /**
   * 获取AMap.Icon的尺寸
   * @param {Object} markerIcon marker Icon 对象
   * @returns {Array} icon 尺寸
   */
  getMvMapIconSize(markerIcon) {
    let size = null;
    const imageSize = markerIcon.getImageSize();
    if (imageSize.constructor === Array) {
      // 2.0
      size = imageSize;
    } else {
      // 1.4.15
      size = [imageSize.width, imageSize.height];
    }
    return size;
  }

  /**
   * 创建线图层
   * @param data  -Array
   *          - path: [lng,lat]
   *          - name: '' 名称
   *          - config.lineColor: '' 线条颜色
   *          - config.lineWidth: '' 线条宽度
   *          - config.lineStyle: '' 线条样式
   * @param callback
   *          - e     对象
   *          - item  对应数据
   */
  createMvMapLineLayer(data, config, callback = null) {
    const list = data.constructor === Array ? data : [data];
    const polylineList = [];
    if (list.length > 0) {
      const _hoverMarker = new AMap.Marker({
        content: " ",
        offset: new AMap.Pixel(0, -10)
      });

      list.forEach((item) => {
        // const itemConfig = item.config ? item.config : (item['config'] = {})
        const itemConfig = {
          ...config,
          ...item.config
        };
        // 高德的入参
        itemConfig.strokeWeight = itemConfig.lineWidth || 4;
        itemConfig.strokeColor = itemConfig.lineColor || "#3366FF";
        itemConfig.strokeStyle = itemConfig.lineStyle || "solid";

        const zIndex = itemConfig.zIndex || 50;

        const polyline = new AMap.Polyline({
          path: item.path,
          strokeOpacity: 1,
          cursor: "pointer",
          ...itemConfig,
          zIndex
        });
        // 鼠标悬停
        polyline.on("mouseover", (e) => {
          // 选中样式
          itemConfig.selectWidth &&
            polyline.setOptions({ strokeWeight: itemConfig.selectWidth });
          itemConfig.selectColor &&
            polyline.setOptions({ strokeColor: itemConfig.selectColor });
          // itemConfig.hasHoverStatus && polyline.setOptions({
          //   strokeWeight: itemConfig.selectWidth || itemConfig.strokeWeight,
          //   strokeColor: itemConfig.selectColor || itemConfig.strokeColor
          // });

          const offsetNum = itemConfig.selectWidth || itemConfig.strokeWeight;
          // 悬浮label样式
          _hoverMarker.setPosition(e.lnglat);
          // 设置偏移量 防止选中路线时，label闪动（鼠标悬浮到了_hoverMarker上）
          _hoverMarker.setOffset(
            new AMap.Pixel(-offsetNum / 2, -offsetNum - 5)
          );
          _hoverMarker.setzIndex(labelIndex);
          _hoverMarker.setLabel({ content: item.name, direction: "top" });
          this.map.add(_hoverMarker);

          itemConfig.openMouseoverCallback &&
            callback &&
            callback(e, item, config);
        });
        // 鼠标移出
        polyline.on("mouseout", (e) => {
          // 移除选中样式

          itemConfig.selectWidth &&
            polyline.setOptions({ strokeWeight: itemConfig.lineWidth });
          itemConfig.selectColor &&
            polyline.setOptions({ strokeColor: itemConfig.lineColor });
          // itemConfig.hasHoverStatus && polyline.setOptions({
          //   ...itemConfig
          // });

          this._setHoverMarker(_hoverMarker);

          itemConfig.openMouseoverCallback &&
            callback &&
            callback(e, item, config);
        });
        polyline.on("click", (e) => {
          callback && callback(e, item, config);
        });
        polylineList.push(polyline);
      });
      polylineList.__proto__._hoverMarker = _hoverMarker;
    }
    this.map.add(polylineList);
    return data.constructor === Array ? polylineList : polylineList[0];
  }
  /**
   * 移除折线
   * @param {Object | Array} line 线实例
   */
  removeMvMapLineLayer(line) {
    if (!line) return;
    this.map.remove(line);
    this._setHoverMarker(line._hoverMarker);
  }
  /**
   * 隐藏折线
   * @param {Array} line 线实例
   */
  hideMvMapLineLayer(line) {
    if (!line) return;
    const list = line.constructor === Array ? line : [line];
    list.forEach((i) => i.hide());
    this._setHoverMarker(list._hoverMarker);
  }

  /**
   * 显示折线
   * @param {Array} line 线实例
   */
  showMvMapLineLayer(line) {
    if (!line) return;
    const list = line.constructor === Array ? line : [line];
    list.forEach((i) => i.show());
  }

  /**
   * 创建文本标记
   * @param data  Array
   *          - text string 内容
   *          - path: [lng,lat]
   *          - offset: [0,0]    偏移量
   *          - style object  样式
   * @param callback  Function 点击回调
   * @returns 文本标记对象
   */
  createMvMapTextMarker(data, callback) {
    const textLayers = [];
    if (data) {
      data.forEach((item) => {
        const textMarker = new AMap.Text({
          text: item.text || "",
          map: this.map,
          position: item.path || this.getMvMapCenter(),
          zIndex: data.zIndex || 100,
          offset: new AMap.Pixel(
            item.offset ? item.offset[0] : 0,
            item.offset ? item.offset[1] : 0
          ),
          style: item.style || null
        });
        textLayers.push(textMarker);
        callback && textMarker.on("click", (e) => callback(e, item));
      });
    }
    return textLayers;
  }
  /**
   * 移除文本标记
   * @param {Array} layer 文本标记图层
   */
  removeMvMapTextMarker(layerList) {
    if (layerList && layerList.constructor === Array) {
      layerList.forEach((layer) => {
        this.map.remove(layer);
      });
    }
  }
  /**
   * 隐藏文本标记
   * @param {Array} layer 文本标记图层
   */
  hideMvMapTextMarker(layerList) {
    if (layerList && layerList.constructor === Array) {
      layerList.forEach((layer) => {
        layer.hide();
      });
    }
  }
  /**
   * 显示文本标记
   * @param {Array} layer 文本标记图层
   */
  showMvMapTextMarker(layerList) {
    if (layerList && layerList.constructor === Array) {
      layerList.forEach((layer) => {
        layer.show();
      });
    }
  }
  /**
   * 设置文本标记
   * @param {Object} layer 文本标记图层
   * @param {Object} config 配置
   *          - text 文本内容
   *          - style 文本样式
   */
  setMvMapTextMarker(layer, config = {}) {
    if (!layer) return;
    if (config.text) {
      layer.setText(config.text);
    }
    if (config.style) {
      layer.setStyle(config.style);
    }
  }

  /**
   * 创建弹框
   * @param isCustom Boolean - 是否使用自定义组件
   * @param data - Object
   *          -- path: [lng,lat] -弹框显示位置
   *          -- content: ''/VNode/$el -弹框内容
   *          -- offset: [] 弹框偏移量
   */
  createMvMapWindowInfo(data, isCustom) {
    const windowInfo = new AMap.InfoWindow({
      isCustom: isCustom || false,
      content: data.content,
      offset: new AMap.Pixel(
        data.offset ? data.offset[0] : 0,
        data.offset ? data.offset[1] : 0
      )
    });
    windowInfo.open(this.map, data.path);
    return windowInfo;
  }

  /**
   * 创建图片图层
   * @param {Object} data              数据
   *                 - url             图片地址
   *                 - southWest [lng,lat]-Array 西南角
   *                 - northEast [lng,lat]-Array 东北角
   * @param {Object} config            配置
   *                 - zooms           显示层级范围
   *                 - opacity         图层透明度 取值[0, 1]
   *                 - zIndex          图层叠加的顺序值，0表示最底层。默认zIndex：1
   */
  createMvMapImgLayer(data, config) {
    const defaultConfig = {
      zooms: [3, 18],
      opacity: 1,
      zIndex: 1
    };
    const imageLayer = new AMap.ImageLayer({
      ...defaultConfig,
      url: data.url,
      bounds: new AMap.Bounds(data.southWest, data.northEast),
      ...config
    });
    this.map.add(imageLayer);
    return imageLayer;
  }
  /**
   * 移除图片图层
   * @param {Object} layer 图片图层
   */
  removeMvMapImgLayer(layer) {
    layer && this.map.remove(layer);
  }

  /**
   * 地图缩放至适合marker级别
   *  - layers Array  图层集合(仅支持polyline图层和marker图层)
   */
  setMvMapFitView(layers = null) {
    this.map.setFitView(layers);
  }

  /**
   * 右击菜单
   * @param events
   *          -- 事件数组  [{name:String,event:Function}]
   */
  setMvMapRightClick(events) {
    const contextMenu = new AMap.ContextMenu();
    if (events && events.length > 0) {
      events.map((item, index) => {
        contextMenu.addItem(
          item.name,
          (e) => {
            item.event(e);
            contextMenu.close();
          },
          index
        );
      });
    }
    this.map.on("rightclick", (e) => {
      contextMenu.open(this.map, e.lnglat);
    });
  }

  /**
   * 判断点是否在区域内
   * @param region    -区域对象
   * @param markers   -点对象集合
   */
  judgePointIsInRegion(region, markers) {
    const result = [];
    if (markers && markers.length > 0) {
      markers.map((item) => {
        if (region.contains(item.getPosition())) {
          result.push(item);
        }
      });
    }
    return result;
  }

  /**
   * 创建实时路况
   * config:{
   *    zIndex 图层叠加的顺序值，0表示最底层，默认zIndex：4
   *    autoRefresh 是否设置可以自动刷新实时路况信息，默认为true
   *    interval 设置刷新间隔时长，单位：秒 默认180s刷新一次
   *    zooms 支持的缩放级别范围，默认范围[3, 17],取值范围[3, 17]
   * }
   */
  createMvMapTrafficLayer(config = {}) {
    const layer = new AMap.TileLayer.Traffic({
      autoRefresh: true,
      interval: 180,
      ...config
    });
    layer.setMap(this.map);
    return layer;
  }

  /**
   * 隐藏实时路况
   * @param layer 图层
   */
  hideMvMapTrafficLayer(layer) {
    layer.hide();
  }
  /**
   * 显示实时路况
   * @param layer 图层
   */
  showMvMapTrafficLayer(layer) {
    layer.show();
  }
  /**
   * 创建卫星图层
   * config:{
   *    zIndex 图层叠加的顺序值，0表示最底层，默认zIndex：4
   *    opacity 图层的透明度，取值范围[0,1]
   *    zooms 支持的缩放级别范围，默认范围[3, 17],取值范围[3, 17]
   * }
   */
  createMvMapSatelliteLayer(config = {}) {
    const layer = new AMap.TileLayer.Satellite(config);
    layer.setMap(this.map);
    return layer;
  }

  /**
   * 隐藏卫星图层
   * @param layer 图层
   */
  hideMvMapSatelliteLayer(layer) {
    layer.hide();
  }
  /**
   * 显示卫星图层
   * @param layer 图层
   */
  showMvMapSatelliteLayer(layer) {
    layer.show();
  }

  /**
   * 行政边界区域
   * @param config
   *          - code 区域code
   *          - codeName 区域名
   *          - depth [Number] 层级 区域类型 0：省级 1：市级 2：县级
   *          - fillColor  [String] 行政区域填充色
   *          - fillFunction(properties)  [Function] 行政区域填充色函数 return color
   *          - cityBorderColor [String] 行政区域边界颜色
   *          - countyBorderColor [String] 县边界颜色
   *
   *          - provinceBorder
   *            borderColor String 边界颜色
   *            borderWeight Number 边界宽度
   *            zIndex Number 图层叠加的顺序值 默认 50
   *
   *          - provinceOutside 绘制外界遮罩
   *            - borderColor String 边界颜色
   *            - borderWeight Number 边界宽度
   *            - fillColor 图层遮罩颜色
   *            - fillOpacity 图层遮罩透明度
   *            - bubble 图层遮罩是否允许点击事件冒泡 默认false
   *            - zIndex 图层叠加的顺序值 默认 999
   * @returns Promise
   */
  createMvMapProvince(config = {}) {
    return new Promise((resolve, reject) => {
      const self = this;
      let province = null; // 行政区域图层
      let provinceBorder = null; // 行政区域边界图层
      let provinceOutside = null; // 行政区域外部遮罩图层
      let cityConfig = {
        codeName: "江苏省",
        code: "320000",
        citycode: ""
      };
      cityCodeJson.some((item) => {
        // 默认已code为准
        if (config.code) {
          if (item.code == config.code) {
            cityConfig = item;
            return true;
          }
        } else if (config.codeName) {
          if (item.codeName == config.codeName) {
            cityConfig = item;
            return true;
          }
        }
      });
      province = new AMap.DistrictLayer.Province({
        zIndex: config.zIndex || 10,
        adcode: [cityConfig.code],
        depth: config.depth || 1,
        zooms: config.zooms || [3, 20],
        styles: {
          fill:
            config.fillFunction ||
            function () {
              return config.fillColor || "rgba(1,49,133,0)"; // 中国地级市填充色
            },
          "city-stroke": config.cityBorderColor || "#fff", // 中国地级市边界
          "stroke-width": config.strokeWidth || 1, // 2.0
          "province-stroke": "cornflowerblue",
          "county-stroke": config.countyBorderColor || "rgba(255,255,255,0.3)" // 中国区县边界
        }
      });
      province.setMap(this.map);
      // 实例化一个行政区查询实例
      const district = new AMap.DistrictSearch({
        extensions: "all"
      });

      // 查询行政边界
      district.search(cityConfig.codeName, function (status, result) {
        if (status !== "complete") {
          reject(result);
          return;
        }
        const outer = [
          new AMap.LngLat(-360, 90, true),
          new AMap.LngLat(-360, -90, true),
          new AMap.LngLat(360, -90, true),
          new AMap.LngLat(360, 90, true)
        ];
        const bounds = result.districtList[0].boundaries;

        // 行政边界描边
        if (config.provinceBorder) {
          provinceBorder = bounds.map((item) => {
            return new AMap.Polyline({
              path: item,
              strokeColor: config.provinceBorder.borderColor || "#fff",
              strokeWeight: config.provinceBorder.borderWeight || 2,
              zIndex: config.provinceBorder.zIndex || 50
            });
          });
          self.map.add(provinceBorder);
        }

        // 外部遮罩
        if (config.provinceOutside) {
          const pathArray = [outer];
          pathArray.push.apply(pathArray, bounds);
          provinceOutside = self.createMvMapPolygon(pathArray, {
            strokeColor: config.provinceOutside.borderColor || "#fff",
            strokeWeight: config.provinceOutside.borderWeight || 0,
            fillColor: config.provinceOutside.fillColor || "rgba(1,49,133,1)",
            fillOpacity:
              config.provinceOutside.fillOpacity === undefined
                ? 1
                : config.provinceOutside.fillOpacity,
            bubble: config.provinceOutside.bubble,
            zIndex: config.provinceOutside.zIndex || 999
          });
        }

        resolve({ province, provinceBorder, provinceOutside });
      });
    });
  }
  /**
   * 移除行政区域图层
   * @param {Object} province  行政区域图层
   * @param {Object} polygon  外界遮罩图层
   */
  removeMvMapProvince({ province, provinceBorder, provinceOutside }) {
    province && province.setMap(null);
    provinceOutside && provinceOutside.setMap(null);
    provinceBorder && this.removeMvMapLineLayer(provinceBorder);
  }
  /**
   * 绘制多边形覆盖物
   * @param {Array} path 多边形轮廓线的节点坐标数组
   * @param {Object} config 配置项
   * config：
   *       - strokeColor 	线条颜色
   *       - strokeWeight 轮廓线宽度
   *       - fillColor 	填充颜色
   *       - fillOpacity 	填充透明度
   *       - bubble 	是否将覆盖物的鼠标或touch等事件冒泡到地图上
   * @returns
   */
  createMvMapPolygon(path, config = {}) {
    const polygon = new AMap.Polygon({
      path: path,
      ...config
    });
    this.map.add(polygon);
    return polygon;
  }
  /**
   * 加载海量点图层
   * @param data Array
   *          - id 标注层id
   *          - name  标注层提示信息
   *          - path    标注层经纬度
   *          - icon      标注层名称
   *          - angle     旋转角度
   *          - zooms     标注层展示层级范围
   *          - zIndex    标注层与其它图层的叠加顺序
   * @param config Object
   *          - iconSize [Array | Function]    标注层图片size
   *          - offset [Array]    偏移量
   *          - zIndex [Number]    图层叠加的顺序值 默认 101
   *          - hoverTitleStyle [Object] 鼠标Hover时显示的Title 样式配置
   *          - topNAreaStyle [Object] TopN区域的样式
   *          - hasClickStatus [Boolean] 是否有点击效果
   * @param callback  事件回调
   */
  createMvMapMassPoint(data, config = {}, callback) {
    const self = this;
    return new Promise((resolve, reject) => {
      AMapUI.load(
        ["ui/misc/PointSimplifier", "lib/utils", "lib/dom.utils", "lib/$"],
        function (PointSimplifier, utils, domUtils, $) {
          if (!PointSimplifier.supportCanvas) {
            alert("当前环境不支持 Canvas！");
            reject();
            return;
          }
          const zIndex = config.zIndex || 110;
          const groupIconMap = {};
          const pointSimplifierIns = new PointSimplifier({
            zIndex: zIndex,
            map: self.map,
            autoSetFitView: config.fitView || false,
            compareDataItem: function (a, b, aIndex, bIndex) {
              return aIndex > bIndex ? -1 : 1;
            },
            getPosition: function (item) {
              if (!item) {
                return null;
              }
              return item.path;
            },
            getHoverTitle: function (dataItem, idx) {
              return dataItem.name;
            },
            renderConstructor: PointSimplifier.Render.Canvas.GroupStyleRender,
            renderOptions: {
              getGroupId: function (item) {
                return item.angle ? item.icon + "&" + item.angle : item.icon;
              },
              groupStyleOptions: function (gid) {
                return groupIconMap[gid];
              },
              hoverTitleStyle: {
                position: "top",
                offset: [0, -10],
                classNames: "mv-map-ui-hover-title",
                ...config.hoverTitleStyle
              },
              topNAreaStyle: {
                content: "none",
                ...config.topNAreaStyle
              }
            }
          });
          // 遍历数据 创建icon分组
          data.forEach((item) => {
            const key = item.angle ? item.icon + "&" + item.angle : item.icon;
            if (groupIconMap[key]) return;
            groupIconMap[key] = self._getGroupStyleOptions(
              item,
              config,
              pointSimplifierIns
            );
          });
          // console.log(groupIconMap)

          pointSimplifierIns.setData(data);

          pointSimplifierIns.on("pointClick", (event, point) => {
            if (pointSimplifierIns.isHidden()) return;
            // 清除之前的点击marker
            self.setMvMapClickMarker();
            const target = event.originalEvent;
            // 获取鼠标点击的渲染点
            const targetsUndermouse =
              pointSimplifierIns.renderEngine._getTargetsUndermouse(target);
            if (targetsUndermouse.length && config.hasClickStatus) {
              const pointItem = targetsUndermouse[0].d;
              const pointStyleOptions =
                pointSimplifierIns.renderEngine._groupPoints([pointItem])[0]
                  .styleOptions;
              const styleOptions = Object.assign(
                {},
                pointStyleOptions.pointStyle,
                pointStyleOptions.pointHoverStyle
              );

              self.setMvMapClickMarker(
                {
                  ...point.data,
                  size: [styleOptions.width, styleOptions.height]
                },
                {
                  ...config,
                  ...styleOptions,
                  zIndex,
                  createType: config.createType,
                  MARKER_SOURCE: "MassPoint",
                  hideClickLabel: true,
                  openMouseoverCallback: false
                }
              );
            }
            callback &&
              callback(
                { ...event.originalEvent, type: "click" },
                { ...point.data, index: point.index },
                config
              );
          });

          pointSimplifierIns.on("pointMouseover", (event, point) => {
            config.openMouseoverCallback &&
              callback &&
              callback(
                { ...event.originalEvent, type: "mouseover" },
                { ...point.data, index: point.index },
                config
              );
          });
          pointSimplifierIns.on("pointMouseout", (event, point) => {
            config.openMouseoverCallback &&
              callback &&
              callback(
                { ...event.originalEvent, type: "mouseout" },
                { ...point.data, index: point.index },
                config
              );
          });

          resolve(pointSimplifierIns);
        }
      );
    });
  }
  /**
   * 获取 海量点 样式分组配置
   * @param {String} data 数据
   * @param {Object} config 图标配置
   * @returns 配置
   */
  _getGroupStyleOptions(data, config, pointSimplifierIns) {
    const iconConfig = this.mapIconClass.getIconConfig(data.icon);
    const iconActiveConfig = this.mapIconClass.getIconConfig(
      data.icon + "-active"
    );

    let size = getIconSize();

    let width;
    let height;
    let content;
    let pointHoverStyle = {
      content: "none"
    };

    if (iconConfig.url) {
      // 绘制图片

      size = getIconSize(iconConfig.name, config.iconSize);

      content = mapPublic.getGroupStyleContent(
        data,
        iconConfig,
        pointSimplifierIns
      );
    } else if (iconConfig.type) {
      // 绘制形状

      size = getIconSize(iconConfig.name, config.iconSize, iconConfig.size);

      content = iconConfig.type;
    }

    width = size[0];
    height = size[1];

    const defaultConfig = {
      width,
      height,
      offset: config.offset || [-width / 2, -height / 2],
      fillStyle: config.iconColor || "#1f77b4"
    };

    // 海量点选中样式
    if (iconActiveConfig.name.includes(data.icon) && config.hasClickStatus) {
      pointHoverStyle = {
        content: mapPublic.getGroupStyleContent(
          data,
          iconActiveConfig,
          pointSimplifierIns
        ),
        ...defaultConfig
      };
    }

    const options = {
      pointStyle: {
        content,
        ...defaultConfig
      },
      pointHoverStyle: {
        ...pointHoverStyle,
        ...defaultConfig
      }
      // drawPositionPoint:true // 辅助设定点的绘制区域的偏移
    };
    return options;
  }

  /**
   * 设置海量点数据
   * @param {Object} layer 海量点图层
   * @param {Array} data 海量点数据
   */
  setMvMapMassPoint(layer, data = null) {
    layer && layer.setData(data);
  }
  /**
   * 绘制海量线
   * @param data
   * @param callback
   * @returns {Promise<unknown>}
   */
  createMvMapMassLine(data, config = {}, callback) {
    const self = this;
    return new Promise((resolve, reject) => {
      const defaultRenderOptions = {
        renderAllPointsIfNumberBelow: -1,
        pathTolerance: 1,
        keyPointTolerance: -1,
        eventSupportInvisible: false,
        startPointStyle: {
          radius: 0,
          lineWidth: 0
        },
        endPointStyle: {
          radius: 0,
          lineWidth: 0
        },
        keyPointStyle: {
          radius: 0,
          lineWidth: 0
        },
        keyPointHoverStyle: {
          radius: 0,
          lineWidth: 0
        },
        keyPointOnSelectedPathLineStyle: {
          radius: 0,
          lineWidth: 0
        },
        getPathStyle(pathItem, zoom) {
          const styleConfig = {
            lineWidth: 6,
            lineColor: "#FFD703",
            selectWidth: 6,
            selectColor: "#FFD703",
            dirArrowStyle: false
          };
          if (
            pathItem.pathData.config &&
            pathItem.pathData.config.constructor === Object
          ) {
            Object.assign(styleConfig, pathItem.pathData.config);
          }
          return {
            pathLineStyle: {
              lineWidth: styleConfig.lineWidth,
              strokeStyle: styleConfig.lineColor,
              borderWidth: 0,
              borderStyle: styleConfig.lineColor,
              dirArrowStyle: styleConfig.dirArrowStyle
            },
            pathLineSelectedStyle: {
              lineWidth: styleConfig.selectWidth,
              strokeStyle: styleConfig.selectColor,
              borderWidth: 0,
              borderStyle: styleConfig.selectColor
            },
            pathLineHoverStyle: {
              lineWidth: styleConfig.selectWidth,
              strokeStyle: styleConfig.selectColor,
              borderWidth: 0,
              borderStyle: styleConfig.selectColor
            }
          };
        },
        hoverTitleStyle: {
          position: "top",
          offset: [0, 0],
          classNames: "mv-map-ui-hover-title",
          ...config.hoverTitleStyle
        }
      };
      AMapUI.load(["ui/misc/PathSimplifier"], function (PathSimplifier) {
        const line = new PathSimplifier({
          zIndex: config.zIndex || 100,
          map: self.map,
          autoSetFitView: config.fitView || false,
          getPath: function (pathData, pathIndex) {
            return pathData.path;
          },
          getHoverTitle: function (pathData, pathIndex, pointIndex) {
            return pathData.name;
          },
          renderOptions: defaultRenderOptions
        });
        line.setData(data);
        line.on("pathClick ", (e, info) => {
          if (line.isHidden()) return;
          callback &&
            callback(
              { ...e.originalEvent, type: "click" },
              { ...info.pathData, index: info.pathIndex }
            );
        });

        // 海量线分为 节点/轨迹 点击等操作，由于AMapUI高德官方不进行维护了，暂不开放悬浮等事件
        // line.on('pathMouseover', (event, point) => {
        //   config.openMouseoverCallback && callback && callback({...event.originalEvent, type: 'mouseover'}, { ...point.data, index: point.index }, config)
        // })
        // line.on('pathMouseout', (event, point) => {
        //   config.openMouseoverCallback && callback && callback({...event.originalEvent, type: 'mouseout'}, { ...point.data, index: point.index }, config)
        // })

        resolve(line);
      });
    });
  }
  /**
   * 设置海量线数据
   * @param {Object} layer 海量线图层
   * @param {Array} data 海量线数据
   */
  setMvMapMassLine(layer, data) {
    layer && layer.setData(data);
  }
  /**
   * 移除点聚合
   */
  removeMvMapMarkerCluster(cluster) {
    cluster && cluster.setMap(null);
  }

  /**
   * 移除热力图 图层
   * @param {Object} layer 热力图 图层
   */
  removeMvMapHeatMap(layer) {
    layer && layer.setMap(null);
  }

  /**
   * 绘制区域
   * @param config
   *              -{
   *                  type:'', 绘制类型
   *                  id:'', 绘制形状id
   *                  lineColor:'', 边框颜色
   *                  areaColor:'',  区域颜色
   *                  edit:false, 是否编辑
   *              }
   * @param markers  （标记点对象数组 可获取所绘制区域内的markers）
   * @param callback
   *             -return 覆盖物对象
   */
  drawMvMapRegion(config, markers, callback) {
    const defaultId = new Date().getTime();
    // 默认配置
    const defaultConfig = {
      areaColor: "#00b0ff",
      lineColor: "#80d8ff",
      edit: false,
      id: defaultId
    };
    // 初始化配置
    const regionConfig =
      config.constructor === String
        ? { ...defaultConfig, type: config }
        : { ...defaultConfig, ...config };
    regionConfig.id = String(regionConfig.id);
    // 自定义属性
    const extData = {
      ...regionConfig
    };
    // 关闭其他绘制图层
    Object.keys(this.mouseToolLayer).forEach((key) => {
      this.mouseToolLayer[key].editLayer.close();
    });
    switch (regionConfig.type) {
      case "rectangle": {
        // 矩形
        this.mouseTool.rectangle({
          fillColor: regionConfig.areaColor,
          strokeColor: regionConfig.lineColor,
          extData
        });
        break;
      }
      case "circle": {
        // 圆形
        this.mouseTool.circle({
          fillColor: regionConfig.areaColor,
          strokeColor: regionConfig.lineColor,
          extData
        });
        break;
      }
      case "polygon": {
        // 多边形
        this.mouseTool.polygon({
          fillColor: regionConfig.areaColor,
          strokeColor: regionConfig.lineColor,
          extData
        });
        break;
      }
    }
    // 监听绘制事件
    this.mouseTool.on("draw", (e) => {
      this.mouseTool.close(false);

      const extData = e.obj.getExtData();
      // 判断是否是当前绘制操作
      if (extData.id !== regionConfig.id) return;

      let inRegionPoints = [];

      inRegionPoints = this.judgePointIsInRegion(e.obj, markers);

      if (!this.mouseToolLayer[extData.id]) {
        this.mouseToolLayer[extData.id] = {};
        // 获取编辑图层
        switch (extData.type) {
          case "rectangle": {
            // 矩形
            if (window.AMap.version !== "2.0") {
              // 因为高德1.4.15版本的bug 使用AMap.MouseTool API绘制矩形，再使用AMap.RectangleEditor API进行矩形的更改拖动修改点，图形无变化
              // 解决办法：用户绘制完成保存，再删除地图上的图形。调用绘制完成的矩形范围，用AMap.Rectangle API绘制一个图形进行编辑
              this.map.remove(e.obj);
              e.obj = new AMap.Rectangle({
                bounds: e.obj.getBounds(),
                ...e.obj.getOptions()
              });
              e.obj.setMap(this.map);
            }
            this.mouseToolLayer[extData.id].editLayer =
              new AMap.RectangleEditor(this.map, e.obj);
            break;
          }
          case "circle": {
            // 圆形
            this.mouseToolLayer[extData.id].editLayer = new AMap.CircleEditor(
              this.map,
              e.obj
            );
            break;
          }
          case "polygon": {
            // 多边形
            this.mouseToolLayer[extData.id].editLayer = new AMap.PolyEditor(
              this.map,
              e.obj
            );
            break;
          }
        }
        this.mouseToolLayer[extData.id].layer = e.obj;
      }
      // 可编辑操作
      if (regionConfig.edit) {
        e.obj.on("click", (obj) => {
          // 之前的编辑图层关闭
          this.mouseToolLayer[extData.id].editLayer &&
            this.mouseToolLayer[extData.id].editLayer.close();

          this.mouseToolLayer[extData.id].editLayer.open();
        });
        e.obj.on("rightclick", (obj) => {
          this.mouseToolLayer[extData.id].editLayer &&
            this.mouseToolLayer[extData.id].editLayer.close();
          inRegionPoints = this.judgePointIsInRegion(e.obj, markers);
          callback(e.obj, extData, inRegionPoints);
        });
      }

      callback(e.obj, extData, inRegionPoints);
    });
  }

  /**
   * 清除绘制内容
   * @param {Object | String} 清除绘制形状图层或id
   */
  clearMvMapRegion(layer) {
    if (layer) {
      // 清除指定绘制图层
      const id = layer.constructor === String ? layer : layer.getExtData().id;
      this.removeMouseToolLayer(id);
    } else {
      // 清除所有绘制图层
      this.mouseTool.close(true);
      Object.keys(this.mouseToolLayer).forEach((id) => {
        this.removeMouseToolLayer(id);
      });
    }
  }
  /**
   * 清除指定绘制内容
   * @param {String} id 绘制内容id
   */
  removeMouseToolLayer(id) {
    if (!this.mouseToolLayer[id]) return;
    this.mouseToolLayer[id].editLayer.close();
    this.map.remove(this.mouseToolLayer[id].layer);
    delete this.mouseToolLayer[id];
  }

  /**
     * 路线规划
     * @param {Array} path 规划路线数组
     *        [
     *          [lng,lat],
     *          [lng,lat]
     *        ] 第一个为起始点，最后一个为终点 其余的途经点
     * @param {Object} config 配置
     *        {
                isMap: true,  是否 将索结果的线路会自动添加在地图上 默认false
                autoFitView: false, 是否自动调整地图视野 默认false
                hideMarkers: true,   是否隐藏路径规划的起始点图标 默认true
                showTraffic: true,  是否显示实时路况信息 默认true
                isOutline: false, 绘制的规划线路是否显示描边 默认false
                outlineColor: 'white', 绘制的规划线路的描边颜色。缺省为'white'
                ferry: 0, 默认为0，表示可以使用轮渡，为1的时候表示不可以使用轮渡
     *        }
      * @param {Array} avoidPath 规避区域  最大支持三个避让区域
     *        [
     *          [[lng,lat],[lng,lat]...],
     *          []
     *        ]
     */
  createMvMapDriving(path, config, avoidPath) {
    return new Promise((resolve, reject) => {
      const lngLatData = mapPublic.onCalculationSign(path);
      const waypointsData = JSON.parse(JSON.stringify(lngLatData));

      waypointsData.shift();
      waypointsData.pop();

      // 默认配置
      const defaultConfig = {
        autoFitView: false,
        hideMarkers: true,
        showTraffic: true,
        isOutline: false,
        ferry: 0
        // policy: AMap.DrivingPolicy.LEAST_FEE
      };

      const driving = new AMap.Driving({
        ...defaultConfig,
        ...config,
        map: config.isMap ? this.map : null
      });

      // 设置避让区域
      avoidPath && driving.setAvoidPolygons(avoidPath);

      driving.search(
        lngLatData[0],
        lngLatData[lngLatData.length - 1],
        {
          waypoints: waypointsData
        },
        (status, result) => {
          if (status === "complete") {
            resolve({
              layer: driving,
              routes: result.routes
            });
          } else {
            reject(result);
          }
        }
      );
    });
  }

  /**
     * 轨迹纠偏绘制
     * @param {Array} path 轨迹点
     * [{"x":116.478928,"y":39.997761,"sp":19,"ag":0, "tm":1478031031},
        { x: 116.478907, y: 39.998422, sp: 10, ag: 0, tm: 1478033031 },
        { x: 116.479384, y: 39.998546, sp: 10, ag: 110, tm: 1478036031 },
        { x: 116.481053, y: 39.998204, sp: 10, ag: 120, tm: 1478040031 },
        { x: 116.481793, y: 39.997868, sp: 10, ag: 120, tm: 1478045031 }]
        x、y、sp、ag、tm分别代表经度、纬度、速度、角度、时间(时间戳)
     * @param {Object} config 轨迹绘制配置
     */
  createMvMapGraspRoad(path, config = {}, callback = null) {
    const self = this;
    return new Promise((resolve, reject) => {
      const grasp = new AMap.GraspRoad();
      const newPath = path.map((item, index) => {
        return {
          x: parseFloat(item.x),
          y: parseFloat(item.y),
          sp: item.sp || 0,
          ag: item.ag || 0,
          tm: index === 0 ? item.tm : (item.tm - path[index - 1].tm) / 1000
        };
      });
      grasp.driving(newPath, function (error, result) {
        if (!error) {
          const graspPath = result.data.points.map((i) => [i.x, i.y]); // 纠偏后的轨迹
          const _data = [
            {
              path: graspPath,
              name: config.name
            }
          ];
          const _config = { showDir: true, ...config };
          // 绘制折线
          const lineLayer = self.createMvMapLineLayer(_data, _config, callback);
          resolve({
            layer: lineLayer[0],
            graspRoad: result
          });
        } else {
          reject(error);
        }
      });
    });
  }

  /**
   * 创建标注类图层，支持大量点标注和文本标注的绘制
   * @param {Array} data 数据
   * @param {Object} config 配置
   *              - iconAnchor 图标锚点
   *              - zIndex
   *              - iconFilter
   *              - hasClickStatus
   * @param {Function} callback 回调
   * @returns layer 图层
   */
  createMvMapLabelMarkerLayer(data, config = {}, callback) {
    return new Promise((resolve) => {
      const layerZindex = config.zIndex || 110;

      const _hoverMarker = this._createHoverMarker(
        {
          ...config,
          zIndex: layerZindex,
          MARKER_SOURCE: "LabelMarker"
        },
        callback
      );

      // 标注类图层
      const layer = new AMap.LabelsLayer({
        zooms: [3, 20],
        // 开启标注避让
        collision: true,
        // 开启标注淡入动画
        animation: false,
        ...config,
        zIndex: layerZindex
      });

      this.map.add(layer);

      const labelMarkers = [];

      data.forEach((item) => {
        if (!isValidPath(item.path)) return;
        // icon
        let icon = null;
        let iconConfigure;
        let iconSize;
        if (item.icon || config.iconFilter) {
          const anchor = item.iconAnchor || config.iconAnchor || "center";

          iconConfigure = this.mapIconClass.getIconConfigure(item, config);
          iconSize = iconConfigure.size;

          const { hoverOffset, clickOffset } = mapPublic.getHoverMarkerOffset(
            anchor,
            iconSize,
            this.version
          );

          // 点标记信息
          item.icon = iconConfigure.name;
          item.size = iconConfigure.size;
          item.offset = clickOffset;
          item.hoverOffset = hoverOffset;

          icon = {
            ...iconConfigure,
            image: iconConfigure.url,
            size: iconConfigure.size,
            anchor,
            angle: item.angle || 0 // 不支持角度旋转
          };
        }

        // label
        let text = null;
        if (item.labelText) {
          text = {
            content: item.labelText,
            direction: item.labelDirection || "top",
            zooms: item.labelZooms || [3, 20],
            offset: item.labelOffset || [0, 0],
            style: {
              ...item.labelStyle
            }
          };
        }

        // new labelMarker
        const labelMarker = new AMap.LabelMarker({
          // zIndex,
          retina: true,
          ...item,
          position: item.path,
          zooms: item.zooms || [3, 20],
          icon,
          text
        });

        // labelMarker click
        labelMarker.on("click", (e) => {
          callback && callback(e, item, config);
        });

        // labelMarker mouseover
        labelMarker.on("mouseover", () => {
          this._setHoverMarker(_hoverMarker, item, config);
        });

        labelMarkers.push(labelMarker);
      });

      layer.__proto__._hoverMarker = _hoverMarker;
      layer.add(labelMarkers);
      resolve(layer);
    });
  }
  /**
   * 清空标注类图层
   * @param {Object} layer 图层
   */
  clearMvMapLabelMarkerLayer(layer) {
    if (!layer) return;
    layer.clear();
    this._setHoverMarker(layer._hoverMarker);
  }

  /**
   * 显示标注类图层
   * @param {Object} layer 图层
   */
  showMvMapLabelMarkerLayer(layer) {
    layer && layer.show();
  }

  /**
   * 隐藏标注类图层
   * @param {Object} layer 图层
   */
  hideMvMapLabelMarkerLayer(layer) {
    if (!layer) return;
    layer.hide();
    this._setHoverMarker(layer._hoverMarker);
  }
  /**
   * 创建海量点标记图层
   * @param {Array} data 数据
   * @param {Object} config 配置
   *              - zIndex
   *              - iconFilter
   *              - hasClickStatus
   * @param {Function} callback 回调
   * @returns layer 图层
   */
  createMvMapMassMarksLayer(data, config = {}, callback) {
    return new Promise((resolve) => {
      const zIndex = config.zIndex || 110;

      const anchor = config.iconAnchor || "center";
      // 样式对象数组
      var styleObjectArr = [];

      const markerData = [];

      const _hoverMarker = this._createHoverMarker(
        {
          ...config,
          zIndex,
          MARKER_SOURCE: "MassMarks"
        },
        callback
      );

      data.forEach((item) => {
        if (!isValidPath(item.path)) return;

        let styleIndex = styleObjectArr.findIndex(
          (i) => i.name === item.icon + item.angle
        );

        // 没查找到对应的styleIndex 需要创建
        if (styleIndex === -1) {
          let iconConfigure, iconSize;

          iconConfigure = this.mapIconClass.getIconConfigure(item, config);
          iconSize = iconConfigure.size;
          // MassMarks offset 不能为负

          const { hoverOffset, clickOffset } = mapPublic.getHoverMarkerOffset(
            anchor,
            iconSize,
            this.version
          );
          styleObjectArr.push({
            ...iconConfigure,
            iconSize,
            offset: clickOffset, // 点击offset
            hoverOffset, // 鼠标悬浮offset
            url: iconConfigure.url,
            anchor: new AMap.Pixel(-clickOffset[0], -clickOffset[1]),
            size: new AMap.Size(iconSize[0], iconSize[1]),
            rotation: Number(item.angle) || 0,
            name: iconConfigure.name + item.angle
          });
          styleIndex = styleObjectArr.length - 1;
        }
        const styleOptions = styleObjectArr[styleIndex];

        markerData.push({
          ...item,
          lnglat: item.path,
          style: styleIndex,
          size: styleOptions.iconSize,
          offset: styleOptions.offset,
          hoverOffset: styleOptions.hoverOffset
        });
      });

      // new MassMarks
      const layer = new AMap.MassMarks(markerData, {
        cursor: "pointer",
        // alwaysRender:false,
        ...config,
        style: styleObjectArr.length > 1 ? styleObjectArr : styleObjectArr[0],
        zIndex
      });

      layer.setMap(this.map);

      // click
      layer.on("click", (e) => {
        callback && callback(e, e.data);
      });

      layer.on("mouseover", (e) => {
        this._setHoverMarker(_hoverMarker, e.data, config);
      });

      layer.__proto__._hoverMarker = _hoverMarker;
      resolve(layer);
    });
  }
  /**
   * 清空海量点标记图层
   * @param {Object} layer 图层
   */
  clearMvMapMassMarksLayer(layer) {
    if (!layer) return;
    layer.clear();
    this._setHoverMarker(layer._hoverMarker);
  }

  /**
   * 显示海量点标记图层
   * @param {Object} layer 图层
   */
  showMvMapMassMarksLayer(layer) {
    layer && layer.show();
  }

  /**
   * 隐藏海量点标记图层
   * @param {Object} layer 图层
   */
  hideMvMapMassMarksLayer(layer) {
    if (!layer) return;
    layer.hide();
    this._setHoverMarker(layer._hoverMarker);
  }
  /**
   * 创建 鼠标悬浮 marker
   * @param {Object} config 配置
   * @param {Function} callback 回调函数
   * @returns marker
   */
  _createHoverMarker(config, callback) {
    const zIndex = labelIndex;
    const _hoverMarker = new AMap.Marker({
      zIndex,
      cursor: "pointer",
      content: " "
    });
    // 线图层忽略
    if (config._type === "line") return;

    // _hoverMarker click
    _hoverMarker.on("click", (e) => {
      const item = _hoverMarker.getExtData();
      const markerIconConfig = _hoverMarker._markerIconConfig;
      if (item.icon) {
        // 清除之前的点击marker
        this.setMvMapClickMarker();
        if (markerIconConfig.hasIconActive && config.hasClickStatus) {
          // 设置点击效果
          const extData = _hoverMarker.getExtData();
          this.setMvMapClickMarker(
            extData,
            {
              ...config,
              zIndex
            },
            markerIconConfig.iconActiveConfig
          );
        }
      }
      this._setHoverMarker(_hoverMarker);

      callback && callback(e, item, config);
    });
    _hoverMarker.on("mouseover", (e) => {
      config.openMouseoverCallback &&
        callback &&
        callback(e, _hoverMarker.getExtData(), config);
      // console.log('--------- mouseout')
    });

    // _hoverMarker mouseout
    _hoverMarker.on("mouseout", (e) => {
      this._setHoverMarker(_hoverMarker);
      config.openMouseoverCallback &&
        callback &&
        callback(e, _hoverMarker.getExtData(), config);
      // console.log('--------- mouseout')
    });

    return _hoverMarker;
  }
  /**
   * 设置 选中 标记点
   * @param {Object} _hoverMarker 点标记对象
   */
  _setHoverMarker(_hoverMarker, item, config) {
    if (!_hoverMarker) return false;
    // 移除选中
    if (!item) {
      setTimeout(() => {
        _hoverMarker.setLabel({
          content: ""
        });

        this.map.remove(_hoverMarker);
      });
      return true;
    }

    // 悬浮选中
    let markerIconConfig = {};
    const iconOffset = item.hoverOffset || item.offset;
    _hoverMarker.setExtData(item);

    // icon
    if (item.icon) {
      markerIconConfig = this.getMvMapMarkerIconConfig(_hoverMarker);
      _hoverMarker.setOffset(new AMap.Pixel(iconOffset[0], iconOffset[1]));
      // 判断是否与选中icon配置
      if (markerIconConfig.hasIconActive) {
        _hoverMarker.setContent("");

        // 这里iconSize设置为null，是因为当前设置的是鼠标悬浮效果，此时item数据里已有size值
        const iconOptions = this.mapIconClass.getMarkerIcon(
          { ...item, icon: markerIconConfig.iconActiveConfig.name },
          { ...config, iconSize: null, iconFilter:null }
        );
        const markerIcon = new AMap.Icon(iconOptions);
        _hoverMarker.setIcon(markerIcon);
      } else {
        const size = item.size;
        // _hoverMarker在没有选中图标的情况下保持和图标点一样的大小
        _hoverMarker.setContent(
          `<div class="map-hover-marker" style="width: ${size[0]}px; height:${size[1]}px"></div>`
        );
      }
    } else {
      _hoverMarker.setContent(" ");
    }

    // angle
    if (Number(item.angle)) {
      _hoverMarker.setAngle(Number(item.angle));
    } else {
      _hoverMarker.setAngle(0);
    }

    // name
    if (item.name) {
      _hoverMarker.setLabel({
        offset: new AMap.Pixel(0, 0),
        content: item.name,
        direction: "top"
      });
    } else {
      setTimeout(() => {
        _hoverMarker.setLabel({
          content: ""
        });
      });
    }

    _hoverMarker.setPosition(item.path);
    this.map.add(_hoverMarker);

    _hoverMarker.__proto__._markerIconConfig = markerIconConfig;
    return _hoverMarker;
  }
}

export default MapSdk;
