梳理清楚的echarts地图下钻和标点信息组件

效果图

效果图

说明

默认数据没有就是全国地图,
$bus.off("onresize")是地图容器变化刷新地图适配的,可以你们自己写
getEchartsFontSize是适配字体大小的,getEchartsFontSize(0.12) === 12
mapScatter是base64图片就是图上那个标点的底图
GetMapGeoJson是获取地图json的,这里的是我公司的,可以用阿里云的代替
还有不明白的可以看是之前的文章,echart5.x地图下钻和地图标点(vue3+ts)

// 地图2--阿里云地图
function GetMapGeoJson2(cityCN: string, citylevel: string) {
  var uploadedDataURL = "";
  if (citylevel == "china") {
    //全国地图
    return "https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json";
  }
  if (citylevel != "district" && (cityCN + "").substring(4) != "00")
    citylevel = "district";
  if (citylevel == "district") {
    uploadedDataURL =
      "https://geo.datav.aliyun.com/areas_v3/bound/" + cityCN + ".json";
  } else if (citylevel == "city") {
    uploadedDataURL =
      "https://geo.datav.aliyun.com/areas_v3/bound/" + cityCN + "_full.json";
  } else {
    uploadedDataURL =
      "https://geo.datav.aliyun.com/areas_v3/bound/" + cityCN + "_full.json";
  }
  return uploadedDataURL;
}

使用

<!-- :defaultMap="defaultMap" -->
<mapChart :list="scatterList" @changeMapData="changeMapData" />

import mapChart from "@/views/universal-visuali/components/charts/map/mapChart.vue";

// 默认的地图数据
let defaultMap = {
  // prefix: "china",
  // adcode: "110000",
  // name: "全国",
  prefix: "province",
  adcode: "150000",
  name: "内蒙古自治区",
};
// 标点
let scatterList = ref<any>([
  {
    FarmName: "养殖场一场",
    Admin: "小王",
    Livestock: 10000,
    Address: "江苏省连云港市",
    Long: 109.494324,
    Lati: 19.598813,
  },
  {
    FarmName: "向东养殖户",
    Admin: "向东",
    Livestock: 0,
    Address: "长虹科技大厦",
    Long: 113.964139785699,
    Lati: 22.544018837551,
  },
  {
    FarmName: "牧养殖种植合作社",
    Admin: "马胜军",
    Livestock: 91,
    Address: "广东省云浮市新兴县",
    Long: 112.231496832189,
    Lati: 22.701890082606,
  },
  {
    FarmName: "苏垦牧场",
    Admin: "小刘",
    Livestock: 8080,
    Address: "江苏省连云港连云区农场",
    Long: 119.43188,
    Lati: 34.62367,
  },
]);
const changeMapData = (info: any) => {
  console.log(info);
};

mapChart 组件代码

<template>
  <div class="cityMap">
    <div class="backMap" :class="{ notAllowed: !notAllowed }" @click="backMap">
      <span>返回</span>
    </div>
    <div class="tradeIn-cattle-map" ref="echartsRef"></div>
  </div>
</template>

<script setup lang="ts">
/**
 * 省市区-地图下钻
 */
import * as echarts from "echarts";
import { ElMessage } from "element-plus";

import {
  ref,
  onMounted,
  reactive,
  Ref,
  onUnmounted,
  nextTick,
  watch,
} from "vue";
import axios from "axios";
import { getEchartsFontSize } from "@/utils/common";
import { mapScatter } from "@/utils/youran";
import $bus from "@/utils/bus";

const props = defineProps({
  list: {
    type: Array,
    default: [],
  },
  defaultMap: {
    type: Object,
    default: {
      prefix: "china",
      adcode: "110000",
      name: "全国",
    },
  },
});

// 坐标点
let scatterDataList = ref<any>([]);

// dom和注册的echart实例
let echartsRef: Ref = ref(null);
let myChart: any = null;
// 没有上一级了,和点击的防抖
let notAllowed = ref<Boolean>(false);
let timeFn: any = null;

// 当前激活地图
let defaultMap = ref<any>({
  prefix: "china",
  adcode: "110000",
  name: "全国",
});
if (props.defaultMap) {
  defaultMap.value = JSON.parse(JSON.stringify(props.defaultMap));
}

// 地图栈
let mapStack: any[] = [];

// 所有下级地图,下钻用
let AllMap = ref<any[]>([]);

// 向外传值
const emit = defineEmits(["changeMapData"]);

onMounted(() => {
  // 如果容器大小变化
  $bus.on("onresize", () => {
    initChart();
    myChart.resize();
  });
  initChart();
});

onUnmounted(() => {
  $bus.off("onresize");
  if (timeFn) {
    clearTimeout(timeFn);
  }
});

watch(
  () => props,
  (val) => {
    nextTick(() => {
      mapStack = []
      if (props.defaultMap) {
        defaultMap.value = JSON.parse(JSON.stringify(props.defaultMap));
      }
      initChart();
    });
  },
  {
    deep: true,
  }
);

// 获取地图--和域名一样的地图(上线上上去,防跨域)
function GetMapGeoJson(cityCN: string, citylevel: string) {
  var uploadedDataURL = "";
  if (citylevel == "china") {
    //全国地图
    return "/YooHooMIS/Scripts/echarts/china/100000_full.json";
  }
  if (citylevel != "district" && (cityCN + "").substring(4) != "00")
    citylevel = "district";
  if (citylevel == "district") {
    uploadedDataURL =
      "/YooHooMIS/Scripts/echarts/china/district/" + cityCN + ".json";
  } else if (citylevel == "city") {
    uploadedDataURL =
      "/YooHooMIS/Scripts/echarts/china/city/" + cityCN + "_full.json";
  } else {
    uploadedDataURL =
      "/YooHooMIS/Scripts/echarts/china/province/" + cityCN + "_full.json";
  }
  return uploadedDataURL;
}
// 创建地图实例
let initChart = () => {
  if (!myChart) {
    myChart = echarts.init(echartsRef.value);
  }
  loadMap();
};
// 注册地图
function loadMap() {
  // 当前地图
  if (mapStack.length <= 0) {
    mapStack.push(defaultMap.value);
  } else {
    defaultMap.value = mapStack[mapStack.length - 1];
  }
  console.log(defaultMap.value, props.defaultMap, mapStack);
  
  let mapData = GetMapGeoJson(defaultMap.value.adcode, defaultMap.value.prefix);
  // 注册当前激活地图
  axios
    .get(mapData)
    .then((geoJson: any) => {
      AllMap.value = geoJson.data.features || [];
      echarts.registerMap(defaultMap.value.name, geoJson.data);
      setOption();
    })
    .catch((err: any) => {
      // 接口404没地图数据的情况
      ElMessage.error(`${defaultMap.value.name}的地图数据`);
      mapStack.pop();
      defaultMap.value = mapStack[mapStack.length - 1];
      if (mapStack && mapStack.length <= 1) {
        notAllowed.value = false;
      }
    });
}
// 加牧场坐标点
function addScatter() {
  scatterDataList.value = [];
  if (props.list && props.list.length > 0) {
    props.list.forEach((item: any) => {
      let name = `
      <div class="CityMapChartTooltipBgBox">
        <div class="list">
          <div class="item">
            <span>${item.FarmName || ""}:</span>
            <span>${item.Livestock || 0}头</span>
          </div>
          <div class="item">
            <span>负责人:</span>
            <span>${item.Admin || ""}</span>
          </div>
          <div class="item">
            <span>地址:</span>
            <span>${item.Address || ""}</span>
          </div>
        </div>
      </div>`;
      scatterDataList.value.push({
        name: name,
        value: [item.Long, item.Lati],
      });
    });
  }
}
// 创建地图
function setOption() {
  addScatter();
  let option = {
    tooltip: {
      show: true,
      className: "CityMapChartTooltipBg",
      formatter: (params: any) => {
        if (params.componentSubType === "scatter") return params.name;
      },
    },
    geo: {
      show: false,
      map: defaultMap.value.name || "全国",
    },
    series: [
      {
        name: "MAP",
        type: "map",
        map: defaultMap.value.name || "全国",
        selectedMode: "false", //是否允许选中多个区域
        aspectScale: 0.75,
        zoom: 1.2,
        zlevel: 1,
        label: {
          show: true,
          textStyle: {
            color: "#fff",
            // fontSize: getEchartsFontSize(0.14),
            fontFamily: "YouSheBiaoTiHei",
          },
        },
        itemStyle: {
          areaColor: new echarts.graphic.LinearGradient(0, 0, 1, 1, [
            {
              offset: 0,
              color: `#06236d`,
            },
            {
              offset: 1,
              color: `#1d46a1`,
            },
          ]),
          borderColor: "#6789d7",
          borderWidth: getEchartsFontSize(0.01),
          shadowColor: "#0156f2",
          shadowOffsetX: -getEchartsFontSize(0.03),
          shadowOffsetY: getEchartsFontSize(0.03),
          shadowBlur: getEchartsFontSize(0.02),
          emphasis: {
            show: true,
            areaColor: "#182e8f", // 鼠标悬浮地图面的颜色
            borderColor: "#fff",
            borderWidth: getEchartsFontSize(0.02),
            label: {
              show: true,
              textStyle: {
                color: "#fff",
                fontSize: getEchartsFontSize(0.16),
                fontFamily: "YouSheBiaoTiHei",
              },
            },
          },
        },
        data: [],
      },
      {
        type: "scatter",
        coordinateSystem: "geo",
        symbol: "image://" + mapScatter,
        symbolSize: [getEchartsFontSize(0.66), getEchartsFontSize(0.36)],
        itemStyle: {
          color: "#1cedd4",
          shadowBlur: getEchartsFontSize(0.1),
          shadowColor: "#333",
        },
        zlevel: 200,
        data: scatterDataList.value || [],
      },
    ],
  };
  // 地图数据的关系setOption有时会报错,暂时无解
  myChart.setOption(option);
  mapChartAddClick();
}
// 加点击事件
function mapChartAddClick() {
  // 清空之前的点击事件
  myChart.off("click");
  myChart.on("click", (params: any) => {
    if (timeFn) {
      clearTimeout(timeFn);
    }
    //由于单击事件和双击事件冲突,故单击的响应事件延迟250毫秒执行
    timeFn = setTimeout(() => {
      // 现在和点的是一个阻止
      if (params.name === mapStack[mapStack.length - 1].name) {
        return;
      }
      if (params.seriesType == "scatter") {
        // 点标点逻辑,传递标点信息
        emit("changeMapData", props.list[params.dataIndex]);
      } else {
        // 地图下钻逻辑
        if (AllMap.value && AllMap.value.length > 0) {
          let clickMap = AllMap.value.find(
            (item) => item.properties.name === params.name
          );
          if (!clickMap) {
            ElMessage.warning("无此区域地图显示");
            return;
          }
          mapStack.push({
            prefix: clickMap.properties.level,
            adcode: clickMap.properties.adcode,
            name: clickMap.properties.name,
          });
          notAllowed.value = true;
          loadMap();
        } else {
          ElMessage.warning("无下级地图数据");
        }
      }
    }, 250);
  });
  // 绑定双击事件,返回
  // myChart.on("dblclick", (params: any) => {
  //   backMap();
  // });
}
// 返回上一级
let backMap = () => {
  // 当双击事件发生时,清除单击事件,仅响应双击事件
  if (timeFn) {
    clearTimeout(timeFn);
  }
  // 删最后一个,跳上一个
  if (mapStack && mapStack.length > 1) {
    mapStack.pop();
    loadMap();
  }
  // 鼠标放上去的禁用状态
  if (mapStack && mapStack.length <= 1) {
    notAllowed.value = false;
  }
};
</script>

<style lang="less" scoped>
.cityMap {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;

  .backMap {
    position: absolute;
    top: 27px;
    left: 40px;
    border: none;
    z-index: 9;
    cursor: pointer;
    // width: 123px;
    // height: 44px;
    // background-image: url("../assets/common/top_icon_back_default.png");
    // background-size: 100% 100%;
    // padding-left: 50px;
    // padding-top: 10px;

    span {
      display: block;
      font-size: 12px;
      // margin-left: 40px;
      border-radius: 7px;
      background-color: #1c4fb1;
      padding: 4px 6px;
      color: #fff;
    }

    &:focus {
      outline: none;
    }

    &:hover {
      // opacity: 0.93;
      // background-image: url("../assets/common/top_icon_back_select.png");
      background-size: 100% 100%;

      span {
        color: #ffffff;
      }
    }

    &.notAllowed {
      cursor: not-allowed;
    }
  }

  .tradeIn-cattle-map {
    // height: 600px;
    width: 100%;
    height: 100%;
    // margin-top: 50px;
  }
}
</style>


  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值