首页 前端知识 vue3 ts echarts 绘制一个射线中国地图 轮播tooltip

vue3 ts echarts 绘制一个射线中国地图 轮播tooltip

2024-02-12 14:02:16 前端知识 前端哥 66 679 我要收藏

1.效果图如下

 

 

 2.代码如下(如果你懂Ts可直接用)

<template>
  <div
    ref="main"
    id="main"
    style="height: 100%; width: 100%; background: skyblue"
  ></div>
</template>

<script setup lang="ts">
// 引入hook
import { ref, reactive, onMounted } from 'vue'
// 引入 echarts
import * as echarts from 'echarts'
import type { utilsParams, funcFace1 } from '@/utils/interface'
import china from '../map/china.json'
console.log(china.features[china.features.length - 1])
// 注册china map
echarts.registerMap('china', require('../map/china.json') || china)
// 定义一个ref
const main = ref<any>(null)
//  tooltip random函数体
const  randomfunc=():number=> Math.random() * 10 | 0
// 定义发射点数据和到达点的经纬度信息
const chinaGeoCoordMap: utilsParams = {
  武汉: [114.298572, 30.584355],
  新疆: [87.617733, 40.792818],
  西藏: [88.132212, 31.660361],
  广西: [108.320004, 22.82402],
  台湾: [121.509062, 24.044332],
  黑龙江: [127.642464, 46.756967],
  吉林: [125.3245, 43.886841],
  澳门: [113.54909, 22.198951],
  海南: [110.33119, 20.031971],
  南海: [128.51865306, 23.46078502]
}

   
const chinaDatas: any = [
  // {
  //   name: '北京',
  //   value: 0
  // },
  {
    name: '新疆',
    value: 2
  },
  {
    name: '西藏',
    value: 1
  },
  {
    name: '台湾',
    value: 1
  },
  {
    name: '广西',
    value: 2
  },
  {
    name: '黑龙江',
    value: 1
  },
  {
    name: '吉林',
    value: 1
  },
  {
    name: '澳门',
    value: 0
  },
  {
    name: '海南',
    value: 0
  },
  {
    name: '南海',
    value: 0
  }
]
// 轮播utils 数组
const dataList: utilsParams[] = reactive([
  {
    name: '南海诸岛',
    value: 25
  },
  {
    name: '北京',
    value: 71
  },
  {
    name: '天津',
    value: 52
  },
  {
    name: '上海',
    value: 14
  },
  {
    name: '重庆',
    value: 50
  },
  {
    name: '河北',
    value: 20
  },
  {
    name: '河南',
    value: 30
  },
  {
    name: '云南',
    value: 55
  },
  {
    name: '辽宁',
    value: 50
  },
  {
    name: '黑龙江',
    value: 40
  },
  {
    name: '湖南',
    value: 6
  },
  {
    name: '安徽',
    value: 96
  },
  {
    name: '山东',
    value: 75
  },
  {
    name: '新疆',
    value: 45
  },
  {
    name: '江苏',
    value: 15
  },
  {
    name: '浙江',
    value: 8
  },
  {
    name: '江西',
    value: 78
  },
  {
    name: '湖北',
    value: 78
  },
  {
    name: '广西',
    value: 36
  },
  {
    name: '甘肃',
    value: 25
  },
  {
    name: '山西',
    value: 140
  },
  {
    name: '内蒙古',
    value: 85
  },
  {
    name: '陕西',
    value: 85
  },
  {
    name: '吉林',
    value: 74
  },
  {
    name: '福建',
    value: 20
  },
  {
    name: '贵州',
    value: 74
  },
  {
    name: '广东',
    value: 47
  },
  {
    name: '青海',
    value: 45
  },
  {
    name: '西藏',
    value: 41
  },
  {
    name: '四川',
    value: 3
  },
  {
    name: '宁夏',
    value: 7
  },
  {
    name: '海南',
    value: 7
  },
  {
    name: '台湾',
    value: 200
  },
  {
    name: '香港',
    value: 2
  },
  {
    name: '澳门',
    value: 5
  }
])

// 定义初始化echarts函数
const initView = (): void => {
  const china = echarts.init(main.value)
  china.clear()
  // 自定义toCoord(line 的经纬度)
  let hourIndex = 0
  // ts 类型推断为undefined console.log(typeof carouselTime, 226)

  /*  // 轮播区域开始 */
  let carouselTime = setInterval((): void => {
    // dispatchAction echarts的API:触发图表行为
    china.dispatchAction({
      type: 'downplay', // downplay 取消高亮指定的数据图形
      seriesIndex: 0
    })
    china.dispatchAction({
      type: 'highlight', // highLight 高亮指定的数据图形
      seriesIndex: 0, // 系列index
      dataIndex: hourIndex // 数据index
    })
    china.dispatchAction({
      type: 'showTip', // showTip 显示提示框
      seriesIndex: 0,
      dataIndex: hourIndex
    })
    hourIndex++
    // 当循环到数组当中的最后一条数据后,重新进行循环
    if (hourIndex > dataList.length) {
      hourIndex = 0
    }
  }, 3000)
  // 鼠标移入组件时停止轮播
  china.on('mousemove', (e) => {
    clearInterval(carouselTime) // 清除循环
    china.dispatchAction({
      type: 'downplay',
      seriesIndex: 0
    })
    china.dispatchAction({
      type: 'highlight',
      seriesIndex: 0,
      dataIndex: e.dataIndex
    })
    china.dispatchAction({
      type: 'showTip',
      seriesIndex: 0,
      dataIndex: e.dataIndex
    })
  })
  // 鼠标移出组件时恢复轮播
  china.on('mouseout', () => {
    carouselTime = setInterval(() => {
      china.dispatchAction({
        type: 'downplay',
        seriesIndex: 0
      })
      china.dispatchAction({
        type: 'highlight',
        seriesIndex: 0,
        dataIndex: hourIndex
      })
      china.dispatchAction({
        type: 'showTip',
        seriesIndex: 0,
        dataIndex: hourIndex
      })
      hourIndex++
      if (hourIndex > dataList.length) {
        hourIndex = 0
      }
    }, 3000)
  })

  /* 轮播区域结束 */
  /* 地图绘制开始 */
  // 设置发射的中心点
  const scatterPos: [number, number] = [114.298572, 30.584355]
  // 设置数据格式
  const convertData = function (data: utilsParams): utilsParams[] {
    const res = []
    for (let i = 0; i < data.length; i++) {
      const dataItem = data[i]
      // 添加每一条线的数据
      const fromCoord = chinaGeoCoordMap[dataItem.name]
      // 攻击点
      const toCoord = scatterPos
      if (fromCoord && toCoord) {
        res.push({
          // fromName: toCoord,
          toName: '武汉',
          coords: [toCoord, fromCoord],
          value: 'yinsdemo'
        })
      }
    }
    console.log('res', res)
    return res
  }
  const series: utilsParams[] = []
  ;[['武汉', chinaDatas]].forEach((item, i): void => {
    console.log(item)
    series.push(
      {
        // 绘制一个新地图
        type: 'map',
        map: 'china',
        geoIndex: 0,
        tooltip: {
          trigger: 'item'
        },
        // center: [105.194115019531, 35.582111640625],
        z: 13,
        aspectScale: 0.75, //
        // 定义动态的数据
        data: []
      },
      // 设置指向线和箭头信息 按照固定的格式加进去
      {
        type: 'lines',
        zlevel: 2,
        effect: {
          show: true,
          period: 5, // 箭头指向速度,值越小速度越快
          trailLength: 0.02, // 特效尾迹长度[0,1]值越大,尾迹越长重
          symbol: ['arrow'], // 箭头图标
          symbolSize: 8, // 图标大小
          color: 'yellow'
        },
        lineStyle: {
          normal: {
            color: 'yellow',
            width: 1.5,
            curveness: 0.2
          }
        },
        tooltip: {
          trigger: ''
        },
        // lineStyle: {
        //   normal: {
        //     color: '#fff',
        //     width: 1, //尾迹线条宽度
        //     opacity: 1, //尾迹线条透明度
        //     curveness: 0.3 //尾迹线条曲直度
        //   }
        // },
        data: convertData(item[1])
      },
      // 发射点位置涟漪等效果
      {
        type: 'effectScatter',
        coordinateSystem: 'geo',
        zlevel: 2,
        rippleEffect: {
          // 涟漪特效
          period: 4, // 动画时间,值越小速度越快
          brushType: 'stroke', // 波纹绘制方式 stroke, fill
          scale: 4 // 波纹圆环最大限制,值越大波纹越大
        },
        label: {
          normal: {
            show: false,
            position: 'right', // 显示位置
            offset: [5, 0], // 偏移设置
            formatter: (params: utilsParams): string => {
              // 圆环显示文字
              return params.data.name
            },
            fontSize: 13
          },
          emphasis: {
            show: true
          }
        },
        tooltip: {
          trigger: ''
        },
        symbol: 'circle',
        symbolSize: function (val: any[]): number {
          return 5 + val[2] * 5 // 圆环大小
        },
        itemStyle: {
          normal: {
            show: false,
            color: 'yellow'
          }
        },
        // 点击涟漪时的数据
        data: item[1].map(function (dataItem: any) {
          return {
            name: dataItem.name,
            str: 'demo',
            value: chinaGeoCoordMap[dataItem.name].concat([dataItem.value])
          }
        })
      },
      // 被攻击点
      {
        type: 'effectScatter',
        coordinateSystem: 'geo',
        zlevel: 2,
        rippleEffect: {
          // 涟漪相关
          period: 2,
          brushType: 'stroke',
          scale: 5
        },
        tooltip: {
          trigger: ''
        },
        label: {
          normal: {
            show: true,
            position: 'right',
            // offset:[5, 0],
            color: '#fff',
            formatter: '{b}',
            textStyle: {
              color: '#fff',
              fontSize: 12
            }
          },
          emphasis: {
            show: true,
            color: '#f60'
          }
        },
        itemStyle: {
          normal: {
            color: 'white'
          }
        },
        symbol: 'circle',
        symbolSize: 10, // 圆圈大小
        data: [
          {
            name: item[0],
            value: chinaGeoCoordMap[item[0]]
          }
        ]
      }
    )
    console.log(series, 220)
  })
  const option: utilsParams = {
    tooltip: {
      show: true,
      trigger: 'item',
      padding: 10,
      borderWidth: 1,
      borderColor: '#409eff',
      backgroundColor: 'rgba(255,255,255,0.4)',
      textStyle: {
        color: '#000000',
        fontSize: 12
      },
      // 提示框内容格式器
      formatter: (e: utilsParams): string => {
        console.log(e, 263)
        const data: utilsParams = {}
        // 此处将各等级景点数量表示为0-10内的随机整数
        data.five = randomfunc()
        data.four = randomfunc()
        data.three = randomfunc()
        data.two = randomfunc()
        data.one = randomfunc()
        // 景点数量 - 五个等级之和
        data.number = data.five + data.four + data.three + data.two + data.one
        // 字符串模板
        const context = `
               <div>
                   <p style="line-height: 30px; font-weight: 600">${e.name}</p>
                   <p><span>景点数量 : </span><span>${data.number}处</span></p>
                   <p><span>5A级 : </span><span>${data.five}处</span></p>
                   <p><span>4A级 : </span><span>${data.four}处</span></p>
                   <p><span>3A级 : </span><span>${data.three}处</span></p>
                   <p><span>2A级 : </span><span>${data.two}处</span></p>
                   <p><span>1A级 : </span><span>${data.one}处</span></p>
               </div>
            `
        return context
      }
    },
    geo: [
      {
        // 地理坐标系组件
        map: 'china',
        type: 'map',
        show: true,
        //     map: 'HK',
        roam: true, // 可以缩放和平移
        aspectScale: 0.8, // 比例
        zoom: 1.5,
        center: [105.194115019531, 35.582111640625],
        // center: [116.405285, 39.904989],
        tooltip: {
          trigger: (params: utilsParams): string => {
            return params.name as string
          }
        },
        layoutCenter: ['50%', '50%'], // position位置
        // 地图大小,保证了不超过 370x370 的区域
        label: {
          // 图形上的文本标签
          normal: {
            show: true,
            rotate: 360,
            // position: 'outside',
            // verticalAlign: 'bottom',
            // position: '',
            // offset: ['500px', '50px'],
            // lineHeight: 'bottom',
            // align: 'center',
            // lineHeight: 26,
            backgroundColor: '',
            textStyle: {
              color: '#fff',
              fontSize: '9'
            }
          },
          emphasis: {
            // 高亮时样式
            color: '#fff'
          }
        },
        // 这里是重点!!!
        // regions: [
        //   {
        //     name: '南海诸岛',
        //     itemStyle: {
        //       // 隐藏地图
        //       normal: {
        //         opacity: 0 // 为 0 时不绘制该图形
        //       }
        //     },
        //     label: {
        //       show: false // 隐藏文字
        //     }
        //   }
        // ],
        itemStyle: {
          // 图形上的地图区域
          normal: {
            areaColor: '#00398e'
          },
          emphasis: {
            // 高亮时
            areaColor: 'skyblue',
            shadowOffsetX: 0,
            shadowOffsetY: 0,
            shadowBlur: 10,
            borderWidth: 0,
            shadowColor: 'rgba(0, 93, 255, 0.2)'
          }
        },
        z: 11
      }
    ],
    series: series
  }
  option && china.setOption(option)
  china.on('click', (params) => {
    console.log(params)
  })
  window.addEventListener('resize', function () {
    china.resize()
  })
}
// 挂载dom
onMounted(() => {
  initView()
})
</script>

<style scoped lang="scss">
#main {
  overflow: hidden;
}
</style>

3.绘制原理(重点)

   1.绘制两个地图,分别生成发射线,涟漪等和核心数据流

    2. 把map的数据映射到geo组件上

    3.valueMap组件需要关掉

4.本文轮播效果参考链接

Vue环境下用ECharts绘制中国地图,并实现拖动、缩放与各省份自动轮播高亮显示_敬 之的博客-CSDN博客

 版权声明:本文为博主原创文章,如有雷同纯属巧合,转载请附上原文出处链接和本声明。
本文链接:

https://mp.csdn.net/mp_blog/creation/editor?spm=1001.2101.3001.4503

   

转载请注明出处或者链接地址:https://www.qianduange.cn//article/1879.html
标签
typescript
评论
会员中心 联系我 留言建议 回顶部
复制成功!