Vue中如何实现城市3D分布图

news2024/9/21 12:27:17

178775c61d0b1e487633f49f70c844b4.png

cityfenbu.vue

<template>
    <div >
         <el-card class="seriesmap-box-card">
            <div slot="header" class="clearfix">
              <span>城市分布图 (点击可下钻到县)</span>
            </div>
            <div>
                <div class="series-map" :style="{height:height,width:width}" ref="seriesMap"></div>
            </div>
         </el-card>
    </div>
  </template>
  
  <script>
  import resize from './resize.js';
  import echarts from 'echarts';
  import { getGeoJson } from './getGeoJson.js';
  import { getMapChartData } from './getMapChartData.js';
  export default {
    name: 'cityfenbu',
    mixins: [resize],
    props: {
      width: {
        type: String,
        default: '100%'
      },
      height: {
        type: String,
        default: '608px'
      }
    },
    data() {
      return {
        geoJson: {},
        parentInfo: [
          {
            cityName: '全国',
            code: 100000
          }
        ]
      };
    },
    mounted() {
      this.$nextTick(() => {
        this.getMapJson();
      });
    },
    methods: {
      //获取geoJson 地图 已封装好直接传citycode就行
      getMapJson() {
        getGeoJson(this.parentInfo[this.parentInfo.length - 1].code).then(data => {
          this.geoJson = data;
          this.getMapData();
        });
      },
      //获取地图数据 模拟数据 数据格式:[{name:'武汉市',value:96},{name:'长沙市',value:75}]
      // 必须要写成这种,而且name名字要和地图的geoJson名字一样,不然渲染不出来
      getMapData() {
        getMapChartData(this.parentInfo[this.parentInfo.length - 1].code).then(res => {
          const data = res.data;
          this.initEchart(data);
        });
      },
      initEchart(data) {
        this.myChart = echarts.init(this.$refs.seriesMap);
        //设置为 china 则显示南海诸岛 ,不需要可以去掉
        echarts.registerMap(this.parentInfo.length === 1 ? 'china' : 'map', this.geoJson); //注册
  
        const mapData = data.sort((a, b) => {
          return b.value - a.value;
        });
        let max = mapData[0].value;
        let min = mapData[mapData.length - 1].value;
        if (mapData.length === 1) {
          min = 0;
        }
  
        this.myChart.setOption(
          {
            tooltip: {},
            visualMap: {
              min: min,
              max: max,
              left: '3%',
              bottom: '1%',
              calculable: true,
              inRange: {
                color: ['#24CFF4', '#2E98CA', '#1E62AC']
              },
              textStyle: {
                color: '#24CFF4'
              }
            },
            series: [
              {
                name: '地图',
                type: 'map',
                map: this.parentInfo.length === 1 ? 'china' : 'map',
                roam: true, //是否可缩放
                zoom: 1.22, //缩放比例
                // left: '',
                // top: '15%', //可移动地图的位置
                data: mapData,
                label: {
                  normal: {
                    show: true,
                    color: 'rgb(249, 249, 249)', //省份标签字体颜色
                    formatter: p => {
                      switch (p.name) {
                        case '内蒙古自治区':
                          p.name = '内蒙古';
                          break;
                        case '西藏自治区':
                          p.name = '西藏';
                          break;
                        case '新疆维吾尔自治区':
                          p.name = '新疆';
                          break;
                        case '宁夏回族自治区':
                          p.name = '宁夏';
                          break;
                        case '广西壮族自治区':
                          p.name = '广西';
                          break;
                        case '香港特别行政区':
                          p.name = '香港';
                          break;
                        case '澳门特别行政区':
                          p.name = '澳门';
                          break;
                        default:
                          break;
                      }
                      return p.name;
                    }
                  },
                  emphasis: {
                    show: true,
                    color: '#f75a00'
                  }
                },
                itemStyle: {
                  normal: {
                    areaColor: '#24CFF4',
                    borderColor: '#53D9FF',
                    borderWidth: 1.3,
                    shadowBlur: 15,
                    shadowColor: 'rgb(58,115,192)',
                    shadowOffsetX: 7,
                    shadowOffsetY: 6
                  },
                  emphasis: {
                    areaColor: '#8dd7fc',
                    borderWidth: 1.6,
                    shadowBlur: 25
                  }
                }
              }
            ]
          },
          true
        );
  
        this.myChart.getZr().off('click');
        this.myChart.getZr().on('click', params => {
          if (params.target) {
            // 点的是地图
            const index = params.target.dataIndex;
            if (index && data[index]) {
              //如果当前是最后一级了,就直接return
              if (this.parentInfo[this.parentInfo.length - 1].code == data[index].adcode) {
                return;
              }
              //根据这个level判断是否下钻到县
              // if (data[index].level == 'city') {
              // return
              // }
              this.parentInfo.push({
                cityName: data[index].name,
                code: data[index].adcode
              });
              this.getMapJson();
             this.$notify.info({
                title: '温馨提示',
                message: '点击地图空白处即可返回上一级'
             });
            }
          } else {
            //点的空白部分
            if (this.parentInfo.length === 1) {
              return;
            }
            this.parentInfo.pop();
            this.getMapJson();
          }
        });
      }
    }
  };
  </script>
  <style lang="scss" scoped>
  .seriesmap-box-card {
    color:rgb(191, 203, 217);
    background:#2d3a4b;
    width: 100%;
    height: 100%;
    font-size: 14px;
    .clearfix:before,
    .clearfix:after {
      display: table;
      content: "";
    }
    .clearfix:after {
      clear: both
    }
    .series-map {
      cursor:move;
    }
  }
  </style>

resize.js

import { debounce } from "./debounce.js";
export default {
  data() {
    return {
      myChart: null,
      resizeHandler: null
    };
  },
  computed: {},
  mounted() {
    this.resizeHandler = debounce(() => {
      if (this.myChart) {
        this.myChart.resize();
      }
    }, 100);
    this.initResizeEvent();
  },

  methods: {
    //监听resize
    initResizeEvent() {
      window.addEventListener("resize", this.resizeHandler);
    },
    //移除resize
    destroyResizeEvent() {
      window.removeEventListener("resize", this.resizeHandler);
    }
  },

  beforeDestroy() {
    this.destroyResizeEvent();
    if (!this.myChart) {
      return;
    }
    this.myChart.dispose();
    this.myChart.off("click");
    this.myChart = null;
  },

  activated() {
    this.initResizeEvent();
    if (this.myChart) {
      this.myChart.resize();
    }
  },

  deactivated() {
    this.destroyResizeEvent();
  },
  watch: {}
};

getGeoJson.js

/**
 * 获取geoJson数据 通过高德获取 递归获取区县geoJson
 * @param {string} adcode 行政区code
 * @param {string} childAdcode 区县级行政区code
 * @return {Array}
 */

import remoteLoad from "./remoteLoad.js";
const  {AMapCDN, AMapUiCDN} = require("./cdn.js");

export function getGeoJson(adcode, childAdcode = "") {
    return new Promise((resolve, reject) => {
      if (window.AMap && window.AMapUI) {
        insideFun(adcode, childAdcode);
      } else {
        remoteLoad(AMapCDN).then(() => {
          if (window.AMap) {
            remoteLoad(AMapUiCDN).then(() => {
              if (window.AMapUI) {
                insideFun(adcode, childAdcode);
              } else {
                console.error("AMapUI获取失败");
              }
            });
          } else {
            console.error("AMap获取失败");
          }
        });
      }
      function insideFun(adcode, childAdcode) {
        // eslint-disable-next-line
        AMapUI.loadUI(["geo/DistrictExplorer"], DistrictExplorer => {
          var districtExplorer = new DistrictExplorer();
          districtExplorer.loadAreaNode(adcode, function(error, areaNode) {
            if (error) {
              console.error(error);
              reject(error);
              return;
            }
            let Json = areaNode.getSubFeatures();
            if (Json.length === 0) {
              let parent = areaNode._data.geoData.parent.properties.acroutes;
              insideFun(parent[parent.length - 1], adcode);
              return;
            }
  
            if (childAdcode) {
              Json = Json.filter(item => {
                return item.properties.adcode == childAdcode;
              });
            }
            let mapJson = {
              features: Json
            };
            resolve(mapJson);
          });
        });
      }
    });
  }

getMapChartData.js

import { getGeoJson } from "./getGeoJson.js";

/** 地图数据
 * @param {string} adcode 城市code
 * @returns {Array}
 */
export function getMapChartData(adcode) {
  return new Promise((resolve, reject) => {
    getGeoJson(adcode)
      .then(res => {
        const data = res.features;
        const mapData = data.map(item => {
          return {
            name: item.properties.name,
            value: parseFloat((Math.random() * 3000).toFixed(2)),
            adcode: item.properties.adcode,
            level: item.properties.level
          };
        });
        resolve({
          code: 200,
          data: mapData
        });
      })
      .catch(error => {
        reject(error);
      });
  });
}

/** 地图数据 散点
 * @param {string} adcode 城市code
 * @returns {Array}
 */
export function getPointChartData(adcode) {
  return new Promise((resolve, reject) => {
    getGeoJson(adcode)
      .then(res => {
        const data = res.features;
        const mapData = data.map(item => {
          return {
            name: item.properties.name,
            value: [
              item.properties.center[0],
              item.properties.center[1],
              parseFloat((Math.random(0.1, 1) * 1000).toFixed(2))
            ],
            adcode: item.properties.adcode,
            level: item.properties.level
          };
        });
        resolve({
          code: 200,
          data: mapData
        });
      })
      .catch(error => {
        reject(error);
      });
  });
}

/** 地图数据 热力图
 * @param {string} adcode 城市code
 * @returns {Array}
 */
export function getHotMapChartData(adcode) {
  const data = [
    {
      name: "地点1",
      value: [114.412021, 30.481201, 1000]
    },
    {
      name: "地点2",
      value: [114.411266, 30.480921, 1000]
    },
    {
      name: "地点3",
      value: [114.411985, 30.481387, 1000]
    },
    {
      name: "地点4",
      value: [114.411159, 30.481917, 1000]
    },
    {
      name: "地点5",
      value: [114.412488, 30.481917, 1000]
    },
    {
      name: "地点6",
      value: [114.413638, 30.482726, 1000]
    },
    {
      name: "地点7",
      value: [114.412344, 30.48341, 1000]
    },
    {
      name: "地点8",
      value: [114.413494, 30.483939, parseInt(Math.random(0.6, 1) * 1000)]
    },
    {
      name: "地点9",
      value: [114.411877, 30.484469, parseInt(Math.random(0.6, 1) * 1000)]
    },
    {
      name: "地点10",
      value: [114.412308, 30.484531, parseInt(Math.random(0.6, 1) * 1000)]
    },
    {
      name: "地点11",
      value: [114.407853, 30.4845, parseInt(Math.random(0.6, 1) * 1000)]
    },
    {
      name: "地点12",
      value: [114.407242, 30.48285, parseInt(Math.random(0.1, 0.5) * 1000)]
    },
    {
      name: "地点13",
      value: [114.412021, 30.481201, parseInt(Math.random(0.1, 0.5) * 1000)]
    },
    {
      name: "地点14",
      value: [114.412021, 30.481201, parseInt(Math.random(0.1, 0.5) * 1000)]
    },
    {
      name: "地点15",
      value: [114.412021, 30.481201, parseInt(Math.random(0.1, 0.5) * 1000)]
    },
    {
      name: "地点16",
      value: [114.412021, 30.481201, parseInt(Math.random(0.1, 0.5) * 1000)]
    },
    {
      name: "地点17",
      value: [114.412021, 30.481201, parseInt(Math.random(0.1, 0.5) * 1000)]
    },
    {
      name: "地点18",
      value: [114.412021, 30.481201, parseInt(Math.random(0.1, 0.5) * 1000)]
    },
    {
      name: "地点19",
      value: [114.412021, 30.481201, parseInt(Math.random(0.1, 0.5) * 1000)]
    },
    {
      name: "地点20",
      value: [114.447306, 30.560407, parseInt(Math.random(0.1, 0.9) * 1000)]
    },
    {
      name: "地点21",
      value: [114.296104, 30.600017, parseInt(Math.random(0.1, 0.9) * 1000)]
    },
    {
      name: "地点22",
      value: [114.29402, 30.597406, parseInt(Math.random(0.1, 0.9) * 1000)]
    },
    {
      name: "地点23",
      value: [114.300487, 30.595106, parseInt(Math.random(0.1, 0.9) * 1000)]
    },
    {
      name: "地点24",
      value: [114.295026, 30.592805, parseInt(Math.random(0.1, 0.9) * 1000)]
    },
    {
      name: "地点25",
      value: [114.291648, 30.597282, 1000]
    },
    {
      name: "地点26",
      value: [114.287408, 30.599147, 1000]
    },
    {
      name: "地点27",
      value: [114.282378, 30.598649, 1000]
    },
    {
      name: "地点28",
      value: [114.286689, 30.600514, 1000]
    }
  ];
  return new Promise((resolve, reject) => {
    resolve({
      code: 200,
      data: data
    });
  });
}

remoteLoad.js

const remoteLoad = url => {
    return new Promise((resolve, reject) => {
      const existingScript = document.getElementById(url);
      //如果script不存在
      if (!existingScript) {
        const script = document.createElement("script");
        script.id = url;
        script.src = url;
        script.async = true;
        document.body.appendChild(script);
        script.onload = function() {
          setTimeout(() => {
            this.onerror = this.onload = null;
            resolve();
          }, 500);
        };
        script.onerror = function() {
          this.onerror = this.onload = null;
          reject("加载失败" + url);
        };
      } else {
        setTimeout(() => {
          resolve();
        }, 500);
      }
    });
  };
  
  export default remoteLoad;

cdn.js

const AMapCDN =
  "https://webapi.amap.com/maps?v=1.3&key=73cddabc2173e0166a622f4483d3592a&plugin=AMap.DistrictSearch";
const AMapUiCDN = "https://webapi.amap.com/ui/1.0/main.js";
const VueCDN = "https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js";
const AxiosCDN = "https://cdn.bootcdn.net/ajax/libs/axios/0.21.0/axios.min.js";
const VueRouterCDN =
  "https://cdn.bootcdn.net/ajax/libs/vue-router/3.2.0/vue-router.min.js";
const VuexCDN = "https://cdn.bootcdn.net/ajax/libs/vuex/3.5.1/vuex.min.js";
const TinymceCDN =
  "https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js";
const html2canvasCDN =
  "https://cdn.jsdelivr.net/npm/html2canvas@1.0.0-rc.7/dist/html2canvas.min.js";

module.exports = {
  AMapCDN,
  AMapUiCDN,
  VueCDN,
  AxiosCDN,
  VueRouterCDN,
  VuexCDN,
  TinymceCDN,
  html2canvasCDN
};

视频号如何做视频任务进行变现

2023-09-05

380aa791f41ecbf439667a54d080e02a.jpeg

视频号如何插入带货商品链接进行变现

2023-09-04

18d58b43f50326bf75f5ddf723f04b24.jpeg

36岁男子自称被裁,曾是前500强公司市场总监,最后接受做外买

2023-09-03

2944e1dee434498ac35ac381d15e1185.jpeg

聊一下互联网红利并牢牢抓住

2023-09-02

b0b405f1be0254fb3c3ed981e3f1f698.jpeg

关于大学考研与不考研自己一点看法

2023-09-01

1d31375fc500862aefaaa7729b46ed15.jpeg

css中文本阴影特效

2023-08-30

f937bf70bf5017f39012ba075716e048.jpeg

8d5b7ba2bc51eef1736bdce50d22f2f7.png

(能绘画,能问答)

f43e85a14eb42c562714935bde373b41.jpeg

(拓展人脉,圈子)

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

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

相关文章

不出意外的话,2023年是AI大模型元年

这两天听的最多的新闻莫过于&#xff0c;谁谁谁&#xff08;AI 大模型&#xff09;面向全社会开放使用&#xff0c;文心一言、WPSAI、讯飞星火、百川智能等等&#xff0c;2023年&#xff0c;AI大模型注定在历史上增添了浓妆淡抹的一幕&#xff0c;未来 AI 将与各个软件应用如影…

RPC协议交互流程

文章目录 RPC特性RPC实现RPC交互流程RPC交互时序图RPC交互流程 RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09; 是一种分布式计算的通信协议和编程模型&#xff0c;用于不同计算机或进程之间进行远程通信。它允许一个计算机程序&#xff08;通常是…

TOWE新能源电动汽车充电延长线,解决户外充电距离过短烦恼

随着新能源汽车市场的日益繁荣&#xff0c;越来越多的车主开始关注充电设备的便利性。为了满足广大车主的充电需求&#xff0c;同为科技&#xff08;TOWE&#xff09;荣誉推出全新16A三芯大功率新能源电动汽车充电延长电源线。这款产品采用优质材料&#xff0c;结构合理&#x…

@Value,@Autowired,@Qualifier

Value 当属性的类型是简单类型时&#xff0c;可以使用Value注解进行注入。 package com.powernode.spring6.bean4;import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;Component public class User {Value(value …

NASM编译器之下载安装使用

NASM的下载和安装 每种处理器都可能会有自己的汇编语言编译器&#xff0c;而对于同一款处理器来说&#xff0c;针对不同的平台(比如Windows和Linux&#xff09;&#xff0c;也会有不同版本的汇编语言编译器。 现存的汇编语言编译器有多种&#xff0c;用得比较多的有 MASM、FA…

如何加快跨国传输大文件的速度?

在当今的信息化社会&#xff0c;数据已经成为各行各业的重要资产&#xff0c;而数据的传输和交换则是数据价值的体现。在很多场景中&#xff0c;我们需要跨国传输大文件&#xff0c;比如政府、军队、金融、医疗等涉密行业&#xff0c;或者跨国、跨区域的企业合作。然而&#xf…

浅谈安科瑞ADL400系列导轨电能表在沙特电力物联网平台中的应用

1.项目概述&#xff1a;Project Overview 沙特客户需要对小区住宅&#xff0c;及商铺进行用户端电能计量&#xff0c;管理。需要安装三相交流电表监测电能数据&#xff0c;并上传到后台系统进行统一监控管理。安科瑞推荐电力物联网平台&#xff0c;可以通过云端界面和APP查看不…

Python中文字体包下载经历(经验分享)

故事背景 python解释器需要中文字体包&#xff0c;我找了半天网络上的中文字体包&#xff0c;每一个过程都非常繁琐。 都是先注册&#xff0c;在安装他们的软件&#xff0c;软件安装好后下载&#xff0c;下载的还不是字体包格式的文件&#xff0c;反正就是在欺负小白。 解决…

浅谈能源汽车下乡充电桩建设优化建议及解决方案

1.趋势分析 新能源汽车下乡已经成为提振汽车市场表现、推动汽车行业发展的重要措施。国家发改委日前也提出&#xff0c;汽车消费是支撑消费的“大头”&#xff0c;将加快推进充电桩和城市停车设施建设&#xff0c;大力推动新能源汽车下乡&#xff0c;鼓励汽车企业开发更适宜县…

若依集成mybatisplus、兼容旧分页【亲测有效】

这里写目录标题 一 修改pom文件最外层的pom.xml增加如下配置common模块的pom文件加入如下配置 二 framework模块的config包增加两个类MybatisPlusPageConfigurerSqlFilterArgumentResolver 三 全局搜索com.ruoyi.framework.config.MyBatisConfig类&#xff0c;将此类注释掉四 y…

excel表中复制粘贴有隐藏行的情况

一、原始数据&#xff0c;没有任何隐藏的情况&#xff1a; 二、隐藏3、4行&#xff1a; 这种情况下&#xff1a; 三、我想复制粘贴出可见的内容&#xff0c;全选&#xff0c;ctrlc复制 四、ctrlv粘贴到别处&#xff0c;结果却是 发现隐藏的行也被复制粘贴出来了。并不是我们想…

求求你,别再用 Mybatis Plus 的伪批量新增了!

前言 大家好&#xff0c;我是小哈~ 本文节选自小哈写的《Mybatis Plus 教程》中的批量新增一节&#xff0c;旨在帮助大家如何在 Mybatis Plus 中&#xff0c;实现 MySQL 真实的批量新增&#xff0c;而不是伪批量新增。 最近&#xff0c;小哈在带小伙伴做 前后端分离项目&#x…

2023年MySQL-8.0.34保姆级安装教程

重点放前面&#xff1a;演示环境为windows环境。 MySQL社区版本安装教程如下&#xff1a; 一、MySQL安装包下载二、安装配置设置三、配置环境变量 大体分为3个步骤&#xff1a;①安装包的下载&#xff1b;②安装配置设置&#xff1b;③配置环境变量 一、MySQL安装包下载 下载官…

界面长的像算抄袭吗?

昨晚&#xff0c;在GitHub和X上&#xff0c;被一次疑似抄袭的问题刷了一会儿屏&#xff0c;主要是下面这个issue&#xff1a; 相关的开源项目是小米的米效&#xff0c;英文名&#xff1a;Mone。一个以微服务为中心的一站式企业协同研发平台。支持公有云、私有云、混合云等多种部…

Redis Cluster集群运维与核心原理剖析

Redis集群方案比较 哨兵模式 在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态&#xff0c;如果master节点异常&#xff0c;则会做主从切换&#xff0c;将某一台slave作为master&#xff0c;哨兵的配置略微复杂&#xff0c;并且性能和高可用性…

2023/09/07 c++qt day2

#include <iostream>using namespace std; //封装一个学生类 struct stu { private://存放学生的成绩int stu_score[256];//记录学生个数int stu_num; public://用于设置学生个数void setNum(){cout<<"请输入学生的个数"<<" ";cin>&g…

神策数据发布汽车行业 CJO 解决方案,打造客户旅程全新体验

最近&#xff0c;围绕数字化客户经营&#xff0c;神策数据基于“客户旅程编排&#xff08;Customer Journey Orchestration&#xff0c;简称 CJO&#xff09;”理念&#xff0c;发布汽车行业全新解决方案&#xff0c;通过全渠道打通给客户带来一致的、个性化的体验&#xff0c;…

如何做好自己的职业规划

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ 进入公司以后&#xff0c;就是进入了人生的下一个阶段&#xff0c;通过前面几个章节&#xff0c;我们谈到了入职新公司后应该如何开展工作。这节我们来聊一聊如何做好职业规…

2594. 修车的最少时间

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;二分枚举答案 写在最后 Tag 【二分枚举答案】【数组】 题目来源 2594. 修车的最少时间 题目解读 给你一个表示机械工能力的数组 ranks&#xff0c;ranks[i] 表示第 i 位机械工可以在 r a n k s [ i ] ∗ n 2 ranks[…

【三维】NeRF神经辐射场构建三维模型

论文地址&#xff1a;paper 代码地址&#xff1a;code 视频地址&#xff1a;油管 目录 0.&#x1f308;&#x1f308;摘要 1.&#x1f308;&#x1f308;nerf主要原理 2.&#x1f308;&#x1f308;网络结构 2.1&#x1f4cc;渲染 2.2&#x1f4cc;消融实验 3.&#x…