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

news2024/11/19 15:39:51

写在前面:

实现效果图

 

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;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/516901.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云原生环境下的安全实践:保护应用程序和数据的关键策略

文章目录 云原生环境下的安全实践&#xff1a;保护应用程序和数据的关键策略一.安全措施和实践1. 身份和访问管理&#xff1a;2. 容器安全&#xff1a;3. 网络安全&#xff1a;4. 日志和监控&#xff1a;5. 持续集成和持续交付&#xff08;CI/CD&#xff09;安全&#xff1a;6.…

【学习笔记-myabtis】使用mybtis对接pgsql的postgis插件,获取地理字段Geometry信息

使用mybtis对接pgsql的postgis插件&#xff0c;获取地理字段geometry信息 参考资料&#xff1a; Mybatis 自定义TypeHandler - 邓维-java - 博客园 1、如何使用typehandler ​ 相信大家用Mybatis这个框架至少一年以上了吧&#xff0c;有没有思考过这样一个问题&#xff1a;数据…

xxl-job 是什么?

xxl-job 是什么&#xff1f; XXL-JOB 是一个分布式任务调度平台&#xff0c;其核心设计目标是开发迅速、学习简单、轻量级、易扩展。 设计思想 是将调度行为抽象形成 调度中心 平台&#xff0c;平台本身不承担业务逻辑&#xff0c;而是负责发起 调度请求 后&#xff0c;由 执…

右下角任务栏出现广告持续闪烁解决方法

&#x1f466;&#x1f466;一个帅气的boy&#xff0c;你可以叫我Love And Program &#x1f5b1; ⌨个人主页&#xff1a;Love And Program的个人主页 &#x1f496;&#x1f496;如果对你有帮助的话希望三连&#x1f4a8;&#x1f4a8;支持一下博主 右下角任务栏出现广告持…

【K8S】【Jenkins】【CI/CD】【一】交付CI/CD工具至k8s 【待写】

1 安装Harbor镜像仓库&#xff08;之前已部署 &#xff0c;略&#xff09; 可参考之前的《Kubernetes业务迁移.pdf》 网站-账号密码 http://gitlab.oldxu.net:30080/users/sign_in &#xff08; root/ admin12345 &#xff09; http://sonar.oldxu.net:30080/ …

Type-C显示器是什么,Type-C显示器的5大优势

在显示器领域内&#xff0c;USB Type-C接口还处于发展阶段&#xff0c;目前已经在新推出的一些高端显示器和旗舰显示器中有配置。USB Type-C接口的出现&#xff0c;将会形成以显示器为核心的桌面解决方案&#xff0c;用户可以把任何笔记本、手机、平板等等的画面转移到一台大屏…

使用sklearn,报错Library not loaded: @rpath/libgfortran.3.dylib

因为需要使用sklearn&#xff0c;去做一些数据分析&#xff0c;所以使用conda命令进行安装 conda install scikit-learn 在安装完成之后&#xff0c;导入&#xff0c;并使用拟合优度R2函数评估&#xff0c;发生如下报错&#xff1b; import sklearn as sk r2 sk.metrics.r2_sc…

怎么安全快速地创建Windows7文件差异备份任务?

​什么是差异备份&#xff1f; 差异备份是什么呢&#xff1f;简单来说&#xff0c;差异备份就是一种数据备份类型&#xff0c;它会帮助我们备份自上次完整备份以来已更改的全部文件。 举个例子&#xff0c;假如我们在星期一进行了一次完整备份&#xff0c;那么星…

有数·智享未来 | 新华三重磅发布绿洲平台3.0

5月10日&#xff0c;紫光股份旗下新华三集团以“有数智享未来”为主题&#xff0c;成功举办绿洲平台3.0新品发布会。全新一代绿洲平台实现内核进阶&#xff0c;以五大技术能力升级、五大行业方案沉淀、六类服务能力保障&#xff0c;三位一体构筑更领先的用数底座、更落地的用数…

ASEMI代理LT8471IFE#PBF原装ADI车规级LT8471IFE#PBF

编辑&#xff1a;ll ASEMI代理LT8471IFE#PBF原装ADI车规级LT8471IFE#PBF 型号&#xff1a;LT8471IFE#PBF 品牌&#xff1a;ADI/亚德诺 封装&#xff1a;TSSOP-20 批号&#xff1a;2023 引脚数量&#xff1a;20 工作温度&#xff1a;-40C~125C 安装类型&#xff1a;表面…

Protobuf:一种轻量级、高效的数据交换格式,附Java与Python数据交换示例

目录 下载安装Protobuf定义数据格式Java代码序列化Python反序列化 Protobuf&#xff08;Protocol Buffers&#xff09;是由 Google 开发的一种轻量级、高效的数据交换格式 官方文档&#xff1a;https://protobuf.dev/overview/GitHub&#xff1a;https://github.com/protocolb…

佩戴舒适的蓝牙耳机有哪些?蓝牙耳机佩戴舒适度排名

随着技术的成熟&#xff0c;真无线耳机这个市场竞争也越来越激烈&#xff0c;伴随着TWS真无线耳机快速发展&#xff0c;许多耳机品牌凭借着优质的产品抓住了时代机遇&#xff0c;各家无论是手机厂商还是耳机品牌争相布局真无线耳机市场&#xff0c; 下面笔者整理了几款佩戴舒适…

Towards Open World Object Detection(OWOD)代码复现

参考上一篇博客detectron2-入门安装,然后进行以下操作&#xff1a; 1、首先在OWOD文件目录运行以下代码&#xff0c;完成内部构建 python -m pip install -e ./ 2、数据集准备 首先下载数据集Annotations和JPEGImages:下载链接&#xff0c;需要翻墙&#xff0c;下载方法可以…

苹果手机连接电脑没反应怎么办?都进来看一下!

案例&#xff1a;iPhone连接电脑没反应 【盆友们&#xff0c;想要上传照片到电脑上&#xff0c;但是苹果手机连接电脑没反应是咋回事&#xff1f;】 手机连接电脑没反应会影响到您与电脑之间的数据传输和文件管理。本文将为您介绍解决苹果手机连接电脑没反应问题的方法&#x…

RethinkDB成为Linux基金会的一员

导读日前&#xff0c;RethinkDB项目有了新的动态。Cloud Native Computing基金会&#xff08;CNCF&#xff09;宣布它购买了NoSQL分布式文件存储数据库RethinkDB的源代码版权&#xff0c;将授权协议从Affero GPLv3改为Apache v2&#xff0c;并将其捐赠给Linux基金会。 2016年1…

多媒体基础

第九章、多媒体基础 1、多媒体技术基本概念 1.1、音频相关概念 超声波的频率通常在20千赫兹以上&#xff0c;无法被人类的耳朵听到&#xff0c;常用于医疗诊断、非破坏性材料测试、清洗、测量等领域 次声波的频率通常在20赫兹以下&#xff0c;同样无法被人类的耳朵听到&…

失败 深度linux社区版 20.8 编译安装 nvidia-docker,启动Stable Deffision WebUI docker 容器

环境 说明&#xff1a; 深度apt 源中无法直接安装nvidia-docker 下载源码 github地址&#xff1a; GitHub - NVIDIA/nvidia-docker: Build and run Docker containers leveraging NVIDIA GPUs 下载最新release https://github.com/NVIDIA/nvidia-docker/archive/refs/tags/…

普通人如何抓住AI这个风口?

​ 要抓住AI这个风口&#xff0c;普通人可以从以下几个方面入手&#xff1a; 1. 学习AI相关知识&#xff1a;可以通过自学、参加培训班、参加线上课程等方式学习AI相关知识&#xff0c;掌握AI的基本原理和应用场景。 2. 参与AI开源社区&#xff1a;可以加入AI开源社区&#…

CVPR 2023 | 目标跟踪新框架:用自回归序列生成的方式训练模型读出目标

如果模型知道目标在哪&#xff0c;那么我们只需要教模型读出目标的位置&#xff0c;而不需要显式地进行分类、回归。对于这项工作&#xff0c;研究者们希望可以启发人们探索目标跟踪等视频任务的自回归式序列生成建模。 自回归式的序列生成模型在诸多自然语言处理任务中一直占…

【Midjourney】Midjourney 的 Prompt 指令类型 ( 画风指令 | 人物细节指令 | 灯光镜头指令 | 艺术家风格指令 )

文章目录 一、Midjourney 的 Prompt 详细指令规则二、Midjourney 的画风指令关键词1、超现实主义2、注重细节描写3、Artstation 画风4、数字绘画风格5、漫画风格6、线条艺术 三、Midjourney 的人物细节描写关键词1、面部特征描写2、身体描写3、生成示例 14、生成示例 2 四、Mid…