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

news2024/11/17 21:25:17

效果图

效果图

说明

默认数据没有就是全国地图,
$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(() => {
      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];
  }

  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: #06bcec;
      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>

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

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

相关文章

【Java SE】超详细讲解String类

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. 初步认识String2. String类的常用方法2.1 字符串构造2.2 String对象比较2.2.1 比较是否引用同一个对象2.2…

3.4 移动机器人工作空间(摘自自主移动机器人导论2)

对于一个机器人来说&#xff0c;机动性等效于它的控制自由度。但是&#xff0c;机器人是处于某种环境的&#xff0c;因而下一个问题是把我们的分析放到环境之中。 我们关心机器人用它可控制的自由度在环境中定位它本身的方法。例如&#xff0c;考虑 Ackerman 车辆或汽车&#…

AI时代的服装设计师--AIGC

AI时代的服装设计师--AIGC AIGCAIGC设计能替代真正的设计师吗森马T恤设计AIGC优势、优化 本文记录于去年参加的一次森马T恤设计活动的感受。 AIGC 可以说&#xff0c;近期以来&#xff0c;随着ChatGPT的不断发展&#xff0c;从ChatGPT-3到ChatGPT-4的飞速发展&#xff0c;AIGC…

无人港口/码头兴起,可视化大屏功不可没。

码头/港口可视化大屏可以为管理上带来多方面的价值&#xff0c;包括但不限于&#xff1a; 1. 实时监控&#xff1a; 大屏可以将港口的各种数据、设备状态、船舶位置等信息实时展示&#xff0c;管理人员可以通过大屏随时监控港口的运营情况&#xff0c;及时发现并处理问题。 2…

香橙派AIpro初体验

1.开发板资料 开发板资源 产品介绍主页&#xff1a;http://www.orangepi.cn/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-AIpro.html开发板案例源码&#xff1a;https://gitee.com/ascend/EdgeAndRobotics工具&原理图&案例源码&开发手册&#x…

python知识继续学习

1、计算机表示小数是有误差的&#xff0c;下面的5就是误差 2、在python中&#xff0c;所有的非0数字都是True&#xff0c;零是False。所有的非空字符串都是True&#xff0c;空字符串是False。空列表是False。在python的基本数据类型中&#xff0c;表示空的东西都是False&#x…

代码随想录算法训练营Day 53| 动态规划part14 | 1143.最长公共子序列、1035.不相交的线 、53. 最大子序和 (动态规划 )

代码随想录算法训练营Day 53| 动态规划part14 | 1143.最长公共子序列、1035.不相交的线 、53. 最大子序和 &#xff08;动态规划 &#xff09; 文章目录 代码随想录算法训练营Day 53| 动态规划part14 | 1143.最长公共子序列、1035.不相交的线 、53. 最大子序和 &#xff08;动态…

量化交易:如何在QMT中运行Python策略并在VSCode中高效调试?

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 为何选择QMT和VSCode进行量化策略开发&#xff1f; 在量化交易的世界里&#xff0c;选择正确的工具与拥有优秀的策略同等重要。调用用Visual Studio Code&#xff08;简称VSCode&#xff09;或pycharm&#xff0c;方…

10种排序算法总结-(c语言实现与动画演示)

算法分类 十种常见排序算法可以分为两大类&#xff1a; 比较类排序&#xff1a;通过比较来决定元素间的相对次序&#xff0c;由于其时间复杂度不能突破O(nlogn)&#xff0c;因此也称为非线性时间比较类排序。非比较类排序&#xff1a;不通过比较来决定元素间的相对次序&#…

GPT-4你了解多少呢

一、引言 在人工智能&#xff08;AI&#xff09;领域&#xff0c;自然语言处理&#xff08;NLP&#xff09;技术一直备受关注。近年来&#xff0c;随着深度学习技术的飞速发展&#xff0c;NLP领域也取得了显著进步。GPT-4&#xff0c;作为OpenAI公司最新发布的自然语言处理模型…

wxPython应用开发-后台线程更新大量数据到wxGrid避免ui无响应

一、问题描述 最近几天&#xff0c;我在用python开发一个数据处理的小工具。需要将xls文件中的大量数据&#xff08;少则几千行多则几万行&#xff09;读取出来后进行处理。其中一个功能是需要实现将读取到的原始数据和计算出来的结果在软件界面中以表格形式展示出来。 在pyt…

Sectigo证书介绍以及申请流程

Sectigo (原Comodo CA)是全球SSL证书市场占有率最高的CA公司&#xff0c;目前将近40%的SSL证书用户选择了Sectigo。由于其产品安全&#xff0c;价格低&#xff0c;受到大量站长的信任和欢迎。Sectigo旗下的SSL证书品牌包括Sectigo, Positive SSL, Sectigo Enterprise等。 品牌…

卷积常用网络

目录 1.AlexNet2.VGG3.GoogleNet4.ResNet5.MobileNet 1.AlexNet AlexNet是2012年ISLVRC 2012&#xff08;ImageNet Large Scale Visual Recognition Challenge&#xff09;竞赛的冠军网络。 首次利用 GPU 进行网络加速训练。使用了 ReLU 激活函数&#xff0c;而不是传统的 Si…

基于 Arm 虚拟硬件的 TinyMaix 超轻量级神经网络推理框架的项目实践

本实验过程中所显示的优惠价格及费用报销等相关信息仅在【Arm AI 开发体验创造营】体验活动过程中有效&#xff0c;逾期无效&#xff0c;请根据实时价格自行购买和体验。同时&#xff0c;感谢本次体验活动 Arm 导师 Liliya 对于本实验手册的共创与指导。 详见活动地址&#xff…

【大比武08】利用RAG技术构建档案智能问答系统

关注我们 - 数字罗塞塔计划 - # 大比武2024 本篇是参加“华夏伟业”杯第二届档案信息化公司业务与技术实力大比武&#xff08;简称“大比武 2024”&#xff09;的投稿文章&#xff0c;来自燕山大学档案馆&#xff08;校史馆&#xff09;的实际项目&#xff0c;由河北科怡科技…

拍摄的视频内容怎么做成二维码?视频在线转换成二维码的方法

怎么把拍的个人才艺视频做成二维码呢&#xff1f;现在扫码看视频是实现内容快速传播的一种常用方式&#xff0c;所以很多人会将自己拍摄的视频制作二维码图片&#xff0c;然后分享给其他人扫码获取内容&#xff0c;对于内容的传播速度及用户体验有很好的提升&#xff0c;在很多…

NTLM Relay Gat:自动化NTLM中继安全检测工具

关于NTLM Relay Gat NTLM Relay Gat是一款功能强大的NTLM中继威胁检测工具&#xff0c;该工具旨在利用Impacket工具套件中的ntlmrelayx.py脚本在目标环境中实现NTLM中继攻击风险检测&#xff0c;以帮助研究人员确定目标环境是否能够抵御NTLM中继攻击。 功能介绍 1、多线程支持…

【开发利器】使用OpenCV算子工作流高效开发

学习《人工智能应用软件开发》&#xff0c;学会所有OpenCV技能就这么简单&#xff01; 做真正的OpenCV开发者&#xff0c;从入门到入职&#xff0c;一步到位&#xff01; OpenCV实验大师Python SDK 基于OpenCV实验大师v1.02版本提供的Python SDK 实现工作流导出与第三方应用集…

Java---Cloneable接口---浅克隆和深克隆

在Java中&#xff0c;我们如何实现一个对象的克隆呢&#xff1f; 在Java中实现对象的克隆&#xff0c;我们要用到Cloneable接口。克隆也分为浅克隆和深克隆。 1.实现浅克隆 1.重写clone方法 当我们想直接通过前面已经建立好的对象来调用Object类中的clone方法时&#xff0c;…

vbs执行报错vbs没有文件拓展,双击无法打开

如果看不到文件扩展名需要设置&#xff1a; 无法双击打开vbs 一般为注册表问题 解决办法 将下方代码保存为xxx.reg Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\.VBS] "VBSFile" [HKEY_CLASSES_ROOT.VBS\PersistentHandler] "{5e941d80-bf96-…