实现3D地图 并且显示地图动态跳动标识,鼠标滑过标识 显示此标识下的详细信息,红色为异常标识,悬浮框内显示查看详情信息


<template>
  <div>
    <div
      class="container"
      style="height: 650px; width: 100%"
      ref="mapContainer"
      v-loading="loading"
      element-loading-background="rgba(0, 0, 0, 0.6)"
      element-loading-text="拼命加载中"
      element-loading-spinner="el-icon-loading"
    ></div>
  </div>
</template>
  <script>
import * as echarts from 'echarts';
import 'echarts/lib/component/geo';
import WLImg from '@/assets/dlkwzImg/dtWlbg.png';

export default {
  name: 'TongshanMap',
  props: {
    mapData: {
      type: Array,
      default: []
    }
  },
  data() {
    return {
      tableData: [],
      loading: false,
      myChart: null,
      mapInfo: [
        require('@/assets/dlkwzImg/wxz.png'),
        require('@/assets/dlkwzImg/xz.png'),
        require('@/assets/dlkwzImg/1.png'),
        require('@/assets/dlkwzImg/2.png')
      ]
    };
  },
  watch: {
    mapData: {
      handler: function (val, oldVal) {
        this.updateChart();
      }
    },
  },
  mounted() {
    this.initChart();
  },
  beforeDestroy() {
    if (this.myChart) {
      this.myChart.dispose();
      this.myChart = null;
    }
  },
  computed: {
    getOption() {
      const that = this;
      const mapData = this.mapData.map((item) => {
        const data = {
          value: [
            item.lng,
            item.lat,
            item.companyName,
            item.companyType,
            item.registerMoney,
            item.industry,
            item.createDate,
            item.companyStatus,
            item.address,
            item.abnormalCount
          ]
        };
        return data;
      });
      let option = {
        tooltip: {
          show: false
        },
        label: {
          normal: {
            show: true,
            textStyle: { color: '#fff', fontSize: '20px' }
          },
          emphasis: {
            show: true,
            textStyle: { color: '#fff', fontSize: '20px' }
          }
        },

        geo: [
          {
            map: '铜山',
            aspectScale: 1,
            zoom: 0.75,
            roam: true,
            animationDurationUpdate: 0, //实现缩放、拖动同步且不卡顿
            layoutCenter: ['50%', '50%'],
            layoutSize: '180%',
            show: true,
            itemStyle: {
              borderWidth: 2,
              // 线性渐变,前四个参数分别是 x0, y0, x2, y2, 范围从 0 - 1,相当于在图形包围盒中的百分比,如果 globalCoord 为 `true`,则该四个值是绝对的像素位置
              // areaColor: {
              //   type: 'linear',
              //   x: 0,
              //   y: 0,
              //   x2: 0,
              //   y2: 700,
              //   colorStops: [
              //     {
              //       offset: 0,
              //       color: '#1858b4' // 0% 处的颜色
              //     },
              //     {
              //       offset: 1,
              //       color: '#1fcdff' // 100% 处的颜色
              //     }
              //   ],
              //   global: true // 整体渐变,缺省为 false,区块渐变
              // },
              // 添加纹理图片
              normal: {
                borderColor: '#7ad8ff',
                borderWidth: 3,
                color: {
                  image: WLImg,
                  repeat: 'repeat'
                }
              }
            },
            emphasis: {
              disabled: true
            },
            z: 2,
            // 点位提示
            tooltip: {
              show: true,
              // 将 tooltip 框限制在图表的区域内
              enterable: true,
              confine: true,
              trigger: 'item',
              shadowBlur: 0,
              triggerOn: 'mousemove',
              backgroundColor: 'rgba(255, 255, 255, 0)',
              borderWidth: 0,
              padding: 0,
              formatter: (params) => {
                let arr = params?.value ?? [];
                if (Array.isArray(arr) && arr.length > 0) {
                  function leftslide() {
                    that.$emit('handleAbnormal',arr[2]);
                  }
                  window.leftslide = leftslide;
                  // 可在JS文件单独引入CSS文件(import 'xx.css';),这里把CSS文件里定义的样式复制到style
                  let html = `<div class="custom-tooltip-box" style="width: 360px;height: auto;font-size: 18px;box-sizing: border-box;background: rgba(6,13,39,0.88);border: 1px solid #265DED;box-shadow: 0px 4px 10px 0px rgba(3,6,11,0.84);border-radius: 5px;">`;
                  html += `<div class="title" style="font-size: 18px;color: #fff;line-height: 40px;background: rgba(38,93,237,0.93);text-align: center;white-space: pre-wrap;line-height: 1.5;">${arr[2]}</div>`;
                  html += `<div class="row" style="margin-top: 3px;padding-left:20px;padding-top:10px">`;
                  html += `<span class="label" style="font-size: 18px;color: #fff;margin-right: 10px;padding-left:30px;">企业类型:</span>`;
                  html += `<span style="color: #fff; font-size: 18px;" class="content">${arr[3]}</span>`;
                  html += `</div>`;
                  html += `<div class="row" style="margin-top: 3px;padding-left:20px;padding-top:10px"">`;
                  html += `<span class="label" style="font-size: 18px;color: #fff;margin-right: 10px;padding-left:30px;">注册资本:</span>`;
                  html += `<span style="color: #fff; font-size: 18px;" class="content">${arr[4] == '-' ? '-': (arr[4] + '万元')}</span>`;
                  html += `</div>`;
                  html += `<div class="row" style="margin-top: 3px;padding-left:20px;padding-top:10px"">`;
                  html += `<span class="label" style="font-size: 18px;color: #fff;margin-right: 10px;padding-left:30px;">所属行业:</span>`;
                  html += `<span style="color: #fff; font-size: 18px;white-space: pre-wrap;line-height: 1.5;" class="content">${arr[5]}</span>`;
                  html += `</div>`;
                  html += `<div class="row" style="margin-top: 3px;padding-left:20px;padding-top:10px"">`;
                  html += `<span class="label" style="font-size: 18px;color: #fff;margin-right: 10px;padding-left:30px;">成立日期:</span>`;
                  html += `<span style="color: #fff; font-size: 18px;" class="content">${arr[6]}</span>`;
                  html += `</div>`;
                  html += `<div class="row" style="margin-top: 3px;padding-left:20px;padding-top:10px"">`;
                  html += `<span class="label" style="font-size: 18px;color: #fff;margin-right: 10px;padding-left:30px;">企业状态:</span>`;
                  html += `<span style="color: #fff; font-size: 18px;" class="content">${arr[7]}</span>`;
                  html += `</div>`;
                  html += `<div class="row" style="margin-top: 3px;padding-left:20px;padding-top:10px"">`;
                  html += `<span class="label" style="font-size: 18px;color: #fff;margin-right: 10px;padding-left:30px;">企业地址:</span>`;
                  html += `<span style="color: #fff; font-size: 18px;white-space: pre-wrap;line-height: 1.5;" class="content" >${arr[8]}</span>`;
                  if(arr[9] && arr[9] > 0){
                    html += `<div style="font-size: 16px;color: #2697F0;background: rgba(38,151,240,0);border: 1px solid #2697F0;width: 144px;line-height:32px;text-align:center;margin: 0 auto;margin-top:10px"><a onclick="leftslide()">异常详情>></a></div>`;
                  }
                  html += `<div style="height:20px;line-height:20px;"></div>`
                  html += `</div>`;
                  html += `</div>`;
                  return html;
                }
              },
              // 提示框浮层的位置,让提示框在鼠标正上方或正下方
              position: (point, params, dom, rect, size) => {
                // 当前鼠标位置
                let pointX = point[0];
                let pointY = point[1];
                // 提示框大小
                let boxWidth = size.contentSize[0];
                let boxHeight = size.contentSize[1];
                let x = pointX - boxWidth / 2; // X坐标位置
                let y = 0; // Y坐标位置
                // boxHeight > pointY 说明鼠标上边放不下提示框
                if (boxHeight > pointY) {
                  y = pointY + 10;
                } else {
                  y = pointY - boxHeight - 10;
                }
                return [x, y];
              }
            }
          },
          // 重影
          {
            map: '铜山',
            roam: false,
            animationDurationUpdate: 0, //实现缩放、拖动同步且不卡顿
            zlevel: -1,
            aspectScale: 1,
            zoom: 0.75,
            layoutCenter: ['50%', '51%'],
            layoutSize: '180%',
            silent: true,
            itemStyle: {
              areaColor: '#305391',
              borderWidth: 0,
              shadowColor: '#30476e',
              shadowBlur: 1,
              shadowOffsetX: 1,
              shadowOffsetY: 15
            }
          }
        ],
        series: [
          {
            // 自定义系列, 实现地图点位跳动
            type: 'custom',
            // 该系列使用的坐标系
            coordinateSystem: 'geo',
            geoIndex: 0,
            zlevel: 1,
            data: mapData,

            // 图形渲染逻辑
            renderItem(params, api) {
              // 节点名称
              let name = api.value(2, params.dataIndex);
              // 等级关键字
              let riskKey = api.value(4, params.dataIndex);
              // 异常数据个数
              let abnormalCount = api.value(9, params.dataIndex);
              // 点位图片
              let imgPath =
                abnormalCount > 0 ? that.mapInfo[2] : that.mapInfo[0];
              // 点位图片-鼠标悬浮
              let imgPathEmphasis =
                abnormalCount > 0 ? that.mapInfo[3] : that.mapInfo[1];
              // 字体样式
              let fontStyle = api.font({
                fontStyle: 'normal',
                fontWeight: 400,
                fontSize: 18,
                fontFamily: 'Microsoft Yahei'
              });
              // 获取点位经纬度
              let coord = api.coord([
                api.value(0, params.dataIndex),
                api.value(1, params.dataIndex)
              ]);
              return {
                type: 'group',
                x: coord[0],
                y: coord[1],
                children: [
                  {
                    type: 'image',
                    style: {
                      image: imgPath,
                      x: -15,
                      y: -41,
                      width: 30,
                      height: 41
                    },
                    // 关键帧动画 Jump animation.
                    keyframeAnimation: {
                      duration: 1500,
                      loop: true,
                      delay: Math.random() * 3000,
                      keyframes: [
                        {
                          y: -10,
                          percent: 0.5,
                          // 点位跳动状态,参考缓动示例
                          easing: 'circularOut'
                        },
                        {
                          y: 0,
                          percent: 1,
                          easing: 'quarticOut'
                        }
                      ]
                    },
                    // 高量状态
                    emphasis: {
                      style: {
                        image: imgPathEmphasis,
                        x: -18,
                        y: -49,
                        width: 36,
                        height: 49
                      }
                    }
                  }
                ]
              };
            }
          }
        ]
      };
      return option;
    }
  },
  // mounted() {
  //   const _this = this;
  //   window.myDialog = function (title) {
  //     // 写你的逻辑 我这里该页面以子组件存在父组件中,触发的父组件中的一个方法 该方法里写的展示弹窗的相关逻辑
  //     _this.$emit('showDetail', title);
  //   };
  // },
  methods: {
    initChart() {
      this.loading = true;
      if (!this.myChart) {
        this.myChart = echarts.init(this.$refs.mapContainer);
      }
      echarts.registerMap('铜山', require('@/static/json/xuzhou.json')); // 重要代码
      this.loading = false;
      const that = this;
      this.myChart.setOption(this.getOption);
      this.myChart.on('georoam', (params) => {
        let myOption = that.myChart.getOption();
        if (params.zoom != null) {
          //捕捉到缩放时
          myOption.geo[1].zoom = myOption.geo[0].zoom; //下层geo的缩放等级跟着上层的geo一起改变
          myOption.geo[1].center = myOption.geo[0].center; //下层的geo的中心位置随着上层geo一起改变
        } else {
          //捕捉到拖曳时
          myOption.geo[1].center = myOption.geo[0].center; //下层的geo的中心位置随着上层geo一起改变
        }
        that.myChart.setOption(myOption);
      });
      // 添加 resize 事件监听
      window.addEventListener('resize', function () {
        // 重新计算图表容器大小
        that.myChart && that.myChart.resize();
      });
    },
    updateChart() {
      // 绘制折线图
      this.myChart.setOption(this.getOption);
    },
  }
};
</script>
<style lang="scss" scoped>
@import './style.scss';
.dialogTable {
  padding: 0 10px;
  ::v-deep .el-table thead tr {
    // box-shadow: 0px 0px 30px 5px #203468 inset;
    // background: none !important;
    box-shadow: none !important;
  }
  ::v-deep .el-table tr:nth-child(2n-1) {
    box-shadow: 0px 0px 30px 5px #203468 inset;
    background: none;
  }
  ::v-deep .el-table tr:nth-child(2n) {
    background: none;
  }
}
::v-deep .el-dialog__header {
  background-color: #07083a;
  background-image: url(~@/assets/dlkwzImg/biaoti.png);
  background-size: 100% 100%;
  background-repeat: no-repeat;
  // background: url(~@/assets/dlkwzImg/biaoti.png) no-repeat;
  .el-dialog__title {
    color: #fff;
    font-size: 30;
    font-weight: 900;
    padding-left: 40px;
  }
}
::v-deep .el-dialog__body {
  background: #07083a;
  color: #fff;
}
::v-deep .el-dialog__headerbtn .el-dialog__close {
  color: #fff;
}
.hong {
  background: rgba(251, 64, 65, 0.13);
  color: #fc4141;
  border: none;
}
.huang {
  background: rgba(252, 224, 87, 0.2);
  color: #fce057;
  border: none;
}
</style>
  
posted @ 2025-02-25 17:17  刘酸酸sour  阅读(49)  评论(0)    收藏  举报