ECharts实现炫酷的中国地图动画效果(点动画 + 线动画)

一、项目背景

在数据可视化中,地图可视化是一种非常直观且富有表现力的方式。ECharts作为一款强大的可视化库,提供了丰富的地图功能。今天,我们将通过一个完整的示例,展示如何使用ECharts实现中国地图的点动画和线动画效果,让你的可视化项目更具吸引力!

二、技术栈

  • ECharts:用于地图绘制和动画效果实现。

  • Vue.js:作为前端框架,方便组件化开发和数据绑定。

三、地图基础配置

首先,我们需要一个基本的地图配置,展示中国地图的轮廓和一些基础样式。以下是代码示例:

<template>
  <div ref="chartsRef" />
</template>

<script setup>
import * as echarts from 'echarts'
import { ref, onMounted } from 'vue'

const chartsRef = ref(null)

// 地图基础配置
const options = {
  tooltip: {
    trigger: 'item',
  },
  geo: {
    show: true,
    map: 'china', // 使用中国地图
    roam: true, // 允许缩放和拖动
    zoom: 1, // 初始缩放比例
    center: [101.4038, 36.8207], // 地图中心点经纬度
    emphasis: {
      show: false,
      areaColor: '#389BB7', // 高亮区域颜色
      borderWidth: 0
    },
    itemStyle: {
      borderColor: 'rgba(147, 235, 248, 1)', // 区域边框颜色
      borderWidth: 1,
    }
  },
  series: [
    {
      type: 'map',
      map: 'china',
      geoIndex: 0,
      aspectScale: 0.75, // 长宽比
      showLegendSymbol: false, // 存在legend时显示
      label: {
        normal: {
          show: false
        },
        textStyle: {
          color: '#fff'
        }
      },
      itemStyle: {
        areaColor: '#031525', // 默认区域颜色
        borderColor: '#FFFFFF' // 区域边框颜色
      },
      emphasis: {
        areaColor: '#2B91B7' // 高亮区域颜色
      },
      animation: false // 禁用地图的动画效果
    }
  ]
}

let chart = null
const initChart = () => {
  chart = echarts.init(chartsRef.value) // 初始化 ECharts 实例
  chart.setOption(options) // 设置地图配置
}

onMounted(() => {
  initChart() // 初始化地图
})
</script>

四、地图点动画效果

1. 数据准备

const geoCoordMap = {
  江苏: [118.8062, 31.9208],
  //...网上有相关数据,自行查找
  湖北: [112.29, 30.98]
}

const mapData = []
for (const key in geoCoordMap) {
  mapData.push({
    year: '湖北',
    name: key,
  })
}

2. 动画效果配置

const convertData = (data) => {
  const res = []
  for (let i = 0; i < data.length; i++) {
    const geoCoord = geoCoordMap[data[i].name]
    if (geoCoord) {
      res.push({
        name: data[i].name,
        value: geoCoord.concat(data[i].value) // 将经纬度和数据值合并
      })
    }
  }
  return res
}

const pointOptions = {
  series: [
    {
      type: 'effectScatter', // 使用 effectScatter 类型实现动态点效果
      coordinateSystem: 'geo', // 指定坐标系为地理坐标系
      data: convertData(
        mapData
          .sort((a, b) => b.value - a.value) // 按数据值降序排序
      ),
      showEffectOn: 'render', // 在渲染时显示动画效果
      rippleEffect: {
        brushType: 'stroke' // 波纹效果类型
      },
      label: {
        formatter: '{b}', // 显示地区名称
        position: 'right', // 标签位置
        show: true
      },
      itemStyle: {
        color: '#f00', // 动态点的颜色
      },
      emphasis: {
        scale: true // 高亮时放大
      },
      zlevel: 1 // 设置层级
    }
  ]
}

五、地图线动画效果

最后,我们为地图添加动态的线,用于表示地区之间的流动关系。以下是实现代码:

1. 数据准备

const geoGpsMap = [112.29, 30.98] // 湖北省的经纬度,作为起点

2. 动画效果配置

const convertToLineData = (data, gps) => {
  const res = []
  for (let i = 0; i < data.length; i++) {
    const dataItem = data[i]
    const toCoord = geoCoordMap[dataItem.name] // 目标地区的经纬度
    const fromCoord = gps // 起点经纬度,例如:湖北
    if (fromCoord && toCoord) {
      res.push([
        {
          coord: fromCoord,
        },
        {
          coord: toCoord
        }
      ])
    }
  }
  return res
}

const lineOptions = {
  series: [
    {
      type: 'lines', // 使用 lines 类型实现动态线效果
      zlevel: 2, // 设置层级
      effect: {
        show: true, // 显示动画效果
        period: 4, // 箭头指向速度,值越小速度越快
        trailLength: 0.02, // 特效尾迹长度
        symbol: 'arrow', // 箭头图标
        symbolSize: 3 // 图标大小
      },
      lineStyle: {
        color: '#f00', // 线的颜色
        width: 0.1, // 线的宽度
        opacity: 0.5, // 线的透明度
        curveness: 0.3 // 线的曲直度
      },
      data: convertToLineData(mapData, geoGpsMap) // 动态线的数据
    }
  ]
}

六、完整代码

以下是完整的代码实现,包括地图基础配置、点动画和线动画:

<template>
  <div ref="chartsRef" />
</template>

<script setup>
import * as echarts from 'echarts'
import { ref, onMounted } from 'vue'

const chartsRef = ref(null)

// 地图基础配置
const options = {
  tooltip: {
    trigger: 'item',
  },
  geo: {
    show: true,
    map: 'china',
    roam: true,
    zoom: 1,
    center: [101.4038, 36.8207],
    emphasis: {
      show: false,
      areaColor: '#389BB7',
      borderWidth: 0
    },
    itemStyle: {
      borderColor: 'rgba(147, 235, 248, 1)',
      borderWidth: 1,
    }
  },
  series: [
    {
      type: 'map',
      map: 'china',
      geoIndex: 0,
      aspectScale: 0.75,
      showLegendSymbol: false,
      label: {
        normal: {
          show: false
        },
        textStyle: {
          color: '#fff'
        }
      },
      roam: true,
      itemStyle: {
        areaColor: '#031525',
        borderColor: '#FFFFFF'
      },
      emphasis: {
        areaColor: '#2B91B7'
      },
      animation: false
    }
  ]
}

// 地图点动画数据
const geoCoordMap = {
  江苏: [118.8062, 31.9208],
  湖北: [112.29, 30.98]
}

const mapData = []
for (const key in geoCoordMap) {
  mapData.push({
    year: '湖北',
    name: key,
  })
}

const convertData = (data) => {
  const res = []
  for (let i = 0; i < data.length; i++) {
    const geoCoord = geoCoordMap[data[i].name]
    if (geoCoord) {
      res.push({
        name: data[i].name,
        value: geoCoord.concat(data[i].value)
      })
    }
  }
  return res
}

const pointOptions = {
  series: [
    {
      type: 'effectScatter',
      coordinateSystem: 'geo',
      data: convertData(
        mapData
          .sort((a, b) => b.value - a.value)
          .slice(0, 20)
      ),
      symbolSize: (val) => val[2] / 10,
      showEffectOn: 'render',
      rippleEffect: {
        brushType: 'stroke'
      },
      label: {
        formatter: '{b}',
        position: 'right',
        show: true
      },
      itemStyle: {
        color: '#f00',
        shadowBlur: 10,
        shadowColor: '#f00'
      },
      emphasis: {
        scale: true
      },
      zlevel: 1
    }
  ]
}

// 地图线动画数据
const geoGpsMap = [112.29, 30.98]

const convertToLineData = (data, gps) => {
  const res = []
  for (let i = 0; i < data.length; i++) {
    const dataItem = data[i]
    const toCoord = geoCoordMap[dataItem.name]
    const fromCoord = gps
    if (fromCoord && toCoord) {
      res.push([
        {
          coord: fromCoord,
          value: dataItem.value
        },
        {
          coord: toCoord
        }
      ])
    }
  }
  return res
}

const lineOptions = {
  series: [
    {
      type: 'lines',
      zlevel: 2,
      effect: {
        show: true,
        period: 4,
        trailLength: 0.02,
        symbol: 'arrow',
        symbolSize: 3
      },
      lineStyle: {
        color: '#f00',
        width: 0.1,
        opacity: 0.5,
        curveness: 0.3
      },
      data: convertToLineData(mapData, geoGpsMap)
    }
  ]
}

// 初始化地图
let chart = null
const initChart = () => {
  chart = echarts.init(chartsRef.value)
  chart.setOption(options) // 设置地图基础配置
  chart.setOption(pointOptions) // 设置点动画配置
  chart.setOption(lineOptions) // 设置线动画配置
}

onMounted(() => {
  initChart()
  window.addEventListener('resize', () => {
    chart && chart.resize()
  })
})
</script>

<style>
.echarts {
  width: 100%;
  height: 600px;
}
</style>

1、完整效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值