小白篇 -- 基于 React 的 Echarts 迁徙图试探

325 阅读2分钟

前言

安装

npm install echarts --save

开始

Mock 数据

先准备一份 mock 数据(结构自定):

/*
* 1. 有多条航线;
* 2. 且有出发地、目的地;
*/
const mockData = [
  {
    departData: {
      name: '成都双流国际',
      city: '成都',
      country: { name: '中国', code: 'CN' },
      coordinates: {
        longitude: 103.9468994140625,
        latitude: 30.57830047607422,
      },
    },
    arriveData: {
      name: '旧金山国际机场',
      city: '旧金山',
      country: { name: '美国', code: 'US' },
      coordinates: {
        longitude: -122.37529754638672,
        latitude: 37.61859893798828,
      },
    },
  },
  {
    departData: {
      name: '成田国际',
      city: '东京',
      country: { name: '日本', code: 'JP' },
      coordinates: {
        longitude: 140.38560485839844,
        latitude: 35.76530075073242,
      },
    },
    arriveData: {
      name: '巴黎戴高乐国际',
      city: '巴黎',
      country: { name: '法国', code: 'FR' },
      coordinates: {
        longitude: 2.547800064086914,
        latitude: 49.009700775146484,
      },
    },
  },
  {
    departData: {
      name: '上海浦东',
      city: '上海',
      country: { name: '中国', code: 'CN' },
      coordinates: {
        longitude: 121.79219818115234,
        latitude: 31.14389991760254,
      },
    },
    arriveData: {
      name: '台湾桃园国际',
      city: '中国台北',
      country: { name: '中国', code: 'CN' },
      coordinates: {
        longitude: 121.2322006225586,
        latitude: 25.080299377441406,
      },
    },
  },
  {
    departData: {
      name: '成都双流国际',
      city: '成都',
      country: { name: '中国', code: 'CN' },
      coordinates: {
        longitude: 103.9468994140625,
        latitude: 30.57830047607422,
      },
    },
    arriveData: {
      name: '上海浦东',
      city: '上海',
      country: { name: '中国', code: 'CN' },
      coordinates: {
        longitude: 121.79219818115234,
        latitude: 31.14389991760254,
      },
    },
  },
  {
    departData: {
      name: '拉萨贡嘎国际',
      city: '拉萨',
      country: { name: '中国', code: 'CN' },
      coordinates: {
        longitude: 90.91220092773438,
        latitude: 29.298099517822266,
      },
    },
    arriveData: {
      name: '布达佩斯李斯特•费伦茨国际',
      city: '布达佩斯',
      country: { name: '匈牙利', code: 'HU' },
      coordinates: {
        longitude: 19.233299255371094,
        latitude: 47.43330001831055,
      },
    },
  },
];

Page

详细信息请看标注(更多的参数请看官方配置表):

import { useEffect } from 'react'; // React v17.0 不需要导入 React
import echarts from 'echarts';
import geoJson from 'echarts/map/json/world.json'; // 导入世界地图,该目录下还有很多地图,可自行查看

import './App.css';

const planePath =
  'path://M1705.06,1318.313v-89.254l-319.9-221.799l0.073-208.063c0.521-84.662-26.629-121.796-63.961-121.491c-37.332-0.305-64.482,36.829-63.961,121.491l0.073,208.063l-319.9,221.799v89.254l330.343-157.288l12.238,241.308l-134.449,92.931l0.531,42.034l175.125-42.917l175.125,42.917l0.531-42.034l-134.449-92.931l12.238-241.308L1705.06,1318.313z'; // 小飞机的图片,可更换

function App() {
  useEffect(() => {
    const echartsConDom = document.getElementById('echarts-container');
    const myChart = echarts.init(echartsConDom); // 初始化
    echarts.registerMap('world', geoJson);
    
    //   const IMG = myChart.getDataURL(); // 截图
    //   console.log(IMG);

		// 将数据整理成 echarts 需要的格式结构
    const convertData = (data) => {
      const { departData, arriveData } = data;
      const newData = [];
      const obj = {
        fromName: departData.name,
        toName: arriveData.name,
        coords: [
          [departData.coordinates.longitude, departData.coordinates.latitude],
          [arriveData.coordinates.longitude, arriveData.coordinates.latitude],
        ],
      };
      newData.push(obj);
      return newData;
    };

    const series = [];
    mockData.forEach((item, index) => {
      const { departData, arriveData } = item;
      series.push(
        // 起点(按需求可省略)
        {
          name: departData.city,
          type: 'effectScatter', //  指明图表类型
          coordinateSystem: 'geo', //  指明绘制在geo坐标系上
          zlevel: 2,
          rippleEffect: {
            brushType: 'stroke', // 波纹的绘制方式
          },
          label: {
            show: false,
            position: 'right',
            formatter: '{b}',
          },
          // symbolSize: function(val) {
          //   return val[2] / 8;
          // },
          symbolSize: 6,
          itemStyle: {
            color: '#a6c84c',
          },
          data: [
            {
              name: departData.name,
              value: [
                departData.coordinates.longitude,
                departData.coordinates.latitude,
              ],
            },
          ],
        },
        // 线路
        {
          name: departData.name,
          type: 'lines',
          zlevel: 1,
          effect: {
            show: true,
            period: 6,
            trailLength: 0.7,
            color: '#fff',
            symbolSize: 3,
          },
          lineStyle: {
            normal: {
              color: '#a6c84c',
              width: 0,
              curveness: 0.2,
            },
          },
          data: convertData(item),
        },
        // 轨迹图标
        {
          name: `${departData.name}=>${arriveData.name}`,
          type: 'lines',
          zlevel: 2,
          symbol: ['none', 'arrow'],
          symbolSize: 8,
          effect: {
            show: true,
            period: 6,
            trailLength: 0,
            symbol: planePath,
            symbolSize: 15,
          },
          lineStyle: {
            color: '#a6c84c',
            width: 1,
            opacity: 0.6,
            curveness: 0.2,
          },
          data: convertData(item),
        },
        // 终点
        {
          name: arriveData.city,
          type: 'effectScatter',
          coordinateSystem: 'geo',
          zlevel: 2,
          rippleEffect: {
            brushType: 'stroke',
          },
          label: {
            show: false,
            position: 'right',
            formatter: '{b}',
          },
          // symbolSize: function (val) {
          //   console.log(val,'vvvvla')
          //   return val[2] / 8;
          // },
          symbolSize: 6,
          itemStyle: {
            color: '#a6c84c',
          },
          data: [
            {
              name: arriveData.name,
              value: [
                arriveData.coordinates.longitude,
                arriveData.coordinates.latitude,
              ],
            },
          ],
        }
      );
    });

    const option = {
      title: {
        text: 'Map Demo',
        left: 'center',
        textStyle: {
          color: '#fff',
        },
      },
      backgroundColor: '#404a59',

      geo: {
        map: 'world', // 地图选择
        silent: true, // 禁止图形响应鼠标事件
        itemStyle: {
          color: '#323c48', // 背景颜色
          borderColor: '#404a59', // 边框颜色
        },
        label: {
          show: false,
        },
        roam: true, // 是否开启鼠标缩放和平移漫游
        emphasis: {
          label: {
            show: true,
          },
          itemStyle: {
            color: '#2a333d',
          },
        },
      },

      tooltip: {
        // alwaysShowContent: true, // 提示框总是显示(不再是鼠标离开就消失)
        // enterable: true, // 允许提示框被点击
        formatter: function(params) {
          // const value = params.value;
          // const a =
          // '<br> <a href="http://www.baidu.com" style="color: red">查看详情</a>';
          // return params.name + ': ' + value[2] + a;
          return `${params.name}`;
        },
      }, // 配置提示框
      series: series,
    };
    myChart.setOption(option);
  }, []);

  return (
    <div className='App'>
      <div id='echarts-container'></div>
    </div>
  );
}

export default App;

Happy Hacking!!! 🧑‍💻🧑‍💻🧑‍💻