基于Vue3 + ts + echarts(版本5.X)实现中国地图下钻、地图打点、地图热力图功能

写在前面:

实现效果图

 

1.比较重要的部分用红字标出

 2.安装echats:       

npm install echarts --save

 3.由于echarts5版本的已经没有自带地图数据了,所以地图数据需要到专门的GEO数据网站中下载。这里提供一个阿里的下载地址:DataV.GeoAtlas地理小工具系列 对于这个工具网站,有一个重点需要说一下

用阿里的JSON API测试没有问题,但是上正式环境,调用他们的JSON API是要花钱的。

解决办法就是,将地图数据json文件全部下载下来。然后按照100000_full.json这种格式,放到你们自己的服务器就可以了

4.功能说明,本次教程内容基于vue3+ts+echarts 5版本,实现的内容包括,中国地图的下钻到省市区县级、在指定经纬度进行打点标记。并在鼠标浮动时展示该点的信息、通过区域点数量,呈现地图热力图。

接下来,正式开始实现。

第一步:建立地图容器,给上宽高,导入echarts。

<div ref="echartsMap1" style="width: 100%; height: 79%"></div>
import * as echarts from "echarts";

第二步:实现过程中需要的类型文件:


export interface Geodatav {
    type:     string;
    features: Feature[];
}

export interface Feature {
    type:       FeatureType;
    properties: Properties;
    geometry:   Geometry;
}

export interface Geometry {
    type:        GeometryType;
    coordinates: Array<Array<Array<number[] | number>>>;
}

export enum GeometryType {
    MultiPolygon = "MultiPolygon",
    Polygon = "Polygon",
}

export interface Properties {
    adcode:           number | string;
    name:             string;
    center?:          number[];
    centroid?:        number[];
    childrenNum?:     number;
    level?:           Level;
    parent?:          Parent;
    subFeatureIndex?: number;
    acroutes?:        number[];
    adchar?:          string;
}

export enum Level {
    Province = "province",
}

export interface Parent {
    adcode: number;
}

export enum FeatureType {
    Feature = "Feature",
}

// 城市属性
export interface citymodel {
    name: string,
    adcode: number | string,
    url: string,
    childrenNum: number | undefined,
    center?: number[],
    parentadcode?: number | string,  // 父地图
    hasRegister: boolean  // 是否已经注册在echarts
}

第三步:写一个简单的工具,实现将阿里中国地图城市数据集合JSON数据引入项目中并使用。

// 引入type
import { Feature, Geodatav, citymodel } from "./geodatav";


// 获取当前json下的省份城市区域adcode和json
// 根据城市adcode
function getCurrentadcode(mapdata: Geodatav) {
    let currentMap = new Map();

    mapdata.features.map((item:Feature)=>{
        if (item.properties.name != '') {
            let cityinfo: citymodel = {
                name: item.properties.name,
                adcode: item.properties.adcode,
                childrenNum: item.properties.childrenNum,
                url: `https://geo.datav.aliyun.com/areas_v3/bound/${item.properties.adcode}_full.json`,
               
                center: item.properties.center,
                parentadcode: item.properties.parent?.adcode,
                hasRegister: false
            }
            currentMap.set(cityinfo.adcode, cityinfo);
        }
    })
    return currentMap;
}

// 根据城市名称name
function getCurrentadcodebyname(mapdata: Geodatav) {
    let currentMap = new Map();

    mapdata.features.map((item:Feature)=>{
        if (item.properties.name != '') {
            let cityinfo: citymodel = {
                name: item.properties.name,
                adcode: item.properties.adcode,
                childrenNum: item.properties.childrenNum,
                url: `https://geo.datav.aliyun.com/areas_v3/bound/${item.properties.adcode}_full.json`,
                center: item.properties.center,
                parentadcode: item.properties.parent?.adcode,
                hasRegister: false
            }
            currentMap.set(cityinfo.name, cityinfo);
        }
    })
    return currentMap;
}



export { getCurrentadcode, getCurrentadcodebyname }

注意,在这里,如果你采用将地图数据放在自己的服务器,讲JSON数据下载下来,替换地址即可

第四步:开始渲染地图

首先引入2个工具文件

import * as echarts from "echarts";
import { getCurrentadcode } from "./utils/getAllChineseCity";
import { citymodel } from "./utils/geodatav";

定义地图

const echartsMap1: any = ref(null);
// 定义当前所有的地图
let allMap: Map<string | number, citymodel> = new Map();

// 当前地图
let currentMap: Ref<null | citymodel> = ref(null);
// echarts实例
let myChart: any,
  currentadcode: Ref<number | string> = ref(100000);

在onMounted中初始化中国地图 

onMounted(async () => {
  allMap.set(100000, {
    name: "中国",
    adcode: 100000,
    url: "https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json",
    childrenNum: 34,
    center: [0, 0],
    hasRegister: false, // 是否已经注册在echarts
  });
  currentMap.value = allMap.get(currentadcode.value) as citymodel;
  myChart = echarts.init(echartsMap1.value);
  renderChart(currentMap.value, data, dataMap);
  // 图表跟随屏幕自适应
  window.addEventListener("resize", () => {
    myChart.resize();
  });
  // 地图点击事件
  myChart.on("click", (params: any) => {
    let n = getMapKey(params.name, allMap);
    if (allMap.get(n)?.childrenNum == 0) return;
    (currentadcode.value as number | string) = n;
  });
});
// 根据map中数值,获取key
const getMapKey = (
  value: string,
  map: Map<string | number, citymodel>
): number | string => {
  let arriterator = map.values(),
    res: number | string = 0;
  for (const iterator of arriterator) {
    if (iterator.name == value) {
      res = iterator.adcode;
      break;
    }
  }
  console.log(res);
  return res;
};

其中data,dataMap为我传入地图中需要渲染的数据。你们可以自信传入你们需要展示的数据。

第五步:监听currentadcode的变化,更新地图

// 监听currentadcode地图值
watch(currentadcode, async (newval, oldval) => {
  let nextMap = allMap.get(newval) as citymodel;
  // 如果存在子节点
  if (nextMap?.childrenNum && nextMap.childrenNum > 0) {
    currentMap.value = nextMap;
    // 如果出现意外,没呀父节点
    if (currentMap.value.parentadcode == undefined) {
      currentMap.value.parentadcode = oldval;
    }
    console.log("nextMap: ", nextMap);
    if (nextMap.adcode != 100000) {
      query.code = nextMap.adcode;
      queryData.code = nextMap.adcode;
    } else {
      delete query.code;
      queryData.code = "";
    }
    const data = await getDeptList();
    const dataMap = await getDeptHotMap();
    renderChart(nextMap, data, dataMap);
  }
});

绘制地图函数:

// 获取地图json, 绘制地图
const renderChart = async (cMap: citymodel | null, dataArr, dataMap) => {
  // myChart.showLoading(); // 加载动画
  // 访问当前的地图数据
  let { data: mapdata } = await axios.get(cMap?.url as any);
  let currentName = cMap?.name;

  // 判断是否注册过
  if (!cMap?.hasRegister) {
    echarts.registerMap(currentName as any, mapdata);
    // 当前地图下的地区信息
    let currentCityMap: Map<string | number, citymodel> =
      getCurrentadcode(mapdata);

    allMap = new Map([...allMap, ...currentCityMap]);
    (allMap.get(cMap?.adcode as string | number) as citymodel).hasRegister =
      true;
  }

  let option = {
    tooltip: {
      position: "right",
      color: "#F7C034",
      formatter(d: any) {
        console.log(d);
        return `<div style="padding: 5px 10px;">${d.name}</div>`;
      },
    },
    title: {
      text: `${currentName}地图`,
      left: "center",
      top: "2%",
      textStyle: {
        color: "#fff",
      },
    },
//热力图配置
    visualMap: {
      left: "left",
      orient: "vertical",
      itemWidth: 10,
      min: 0,
      max: 1000,
      align: "center",
      bottom: "10%",
      inRange: {
        color: [
          "#313695",
          "#4575b4",
          "#74add1",
          "#abd9e9",
          "#e0f3f8",
          "#ffffbf",
          "#fee090",
          "#fdae61",
          "#f46d43",
          "#d73027",
          "#a50026",
        ],
      },
      calculable: true,
    },
    //层级地图配置
    series: [
      {
        name: `${currentName}地图`,
        map: currentName,
        type: "map",
        roam: true,
        label: {
          normal: {
            formatter(d: any) {
              return `${d.name}`;
            },
            show: true,
            textStyle: {
              color: "#fff",
            },
          },
          emphasis: {
            show: true,
            textStyle: {
              color: "#05C3F9",
            },
          },
        },
        itemStyle: {
          normal: {
            areaColor: "#3D8CFD",
            borderColor: "#5EC9F9",
            borderWidth: 1,
          },
          emphasis: {
            areaColor: "#0C356C",
            shadowColor: "#1773c3",
            shadowBlur: 20,
          },
        },
        markPoint: {
          symbol: "circle",
          itemStyle: {
            color: "#F7C034",
            // borderColor:'#000'
          },
          label: {
            normal: {
              show: true,
            },
            emphasis: {
              show: true,
            },
          },
          data: dataArr,
          blur: {},
        },
        data: dataMap,
      },
    ],
  };
  myChart.clear();
  myChart.setOption(option, true);
};

最后,返回上级地图方法:

// 返回上级地图
const returnLastMap = (adcode: any) => {
  currentadcode.value = adcode;
};

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值