前端 echarts 3D 地球 自定义地球包材 飞线 + 坐标点

1,208 阅读5分钟

本篇将手把手带你用echarts实现一个超级炫酷惊艳的动态3D地球,废话不多说 上效果图

image.png image.png

实现步骤:

1. 绘制想要的地球包材

思路: 使用echarts的 geo-map 绘制一个世界地图,通过调整参数样式可绘制出期望的包材效果 经过多次实验 最合适的包材尺寸是:6260*2925 只要是这个比例就可以 1252:585

最终效果如下: image.png

核心代码:

  <div class="chinaContainer" id="chinaContainer"></div>
</template>
<script>
import * as echarts from 'echarts';
import 'echarts-gl';
import '@/utils/world.js';// 引入的世界地图文件
export default {
  data() {
    return {
      chart: null,
      data: undefined,
    };
  },
  watch: {},
  methods: {
    async initChart() {
      var dom = document.getElementById('chinaContainer');
      this.chart = await echarts.init(dom, null, {
        devicePixelRatio: 4,
      });
    },
    dataChange() {
      let option = {
        backgroundColor: '#072460',
        tooltip: {
          trigger: 'item',
        },
        geo: {
          map: 'world',
          aspectScale: 1, //'长宽比'
          label: {
            show: false,
          },
          tooltip: {
            show: false,
          },
          itemStyle: {
            areaColor: '#0c3497',
            borderColor: 'rgba(38,254,255, 0.7)',
            borderWidth: 1,
            shadowBlur: 2,
            shadowColor: '#0c3497',
            shadowOffsetX: 0,
            shadowOffsetY: 2,
            emphasis: { disabled: true }, // 关闭高亮状态
          },
        },
      };
      this.chart && this.chart.setOption(option, true);
    },
  },
  async mounted() {
    await this.initChart();
    await this.dataChange();
  },
};
</script>

<style lang="less" scoped>
.chinaContainer {
  width: 100vw;
  height: 100vh;
  color: '#7abbff';
  pointer-events: none;
}
</style>

word.js来源:ecahrts 示例中 随便找一个使用了世界地图的如: echarts.apache.org/examples/zh… 打开控制台可以在加载的资源中找到word.js down下来在代码中引入就好啦 image.png

到这里,代码执行成功后 将浏览器内容窗口尺寸调整为2252*1193打开控制台 找到地图绘制的dom 鼠标右键点击dom找到截取屏幕截图 就可以得到一个 尺寸是2252*1193的高清图片了 image.png

但是这样得到的图片有很多留白,无法直接作为地图包材,下一步我们需要裁剪掉多余的留白 这可能是个数学题 不想计算的同学裁剪的时候 可以直接拿最终的包材图 作为参考依据 放大到内容尺寸吻合后裁剪 或者有条件的话直接把难题丢给ui童鞋 罒ω罒(不要说是我说的啦~

But 细心的话就可以发现 这个地图没有南极的部分o(╥﹏╥)o...那怎么办呢,这里我是请UI同学帮忙ps拼上去的,嘻嘻毕竟专业的事情还是要交给专业的人去做~当然如果你的需求里这部分要求不高也可以不弄。

到这里你就获得了一个属于你的包材,这个包材的优点一是自定义风格另外就是 扎点配坐标的时候可以非常很好的吻合,不用担心坐标跟位置对不上

2. 绘制基本的echarts3D地球并给它,穿上我们精心准备的包材,再给它配一个美丽的背景

这里提供3个可选的背景效果放在最后 可以根据你的主题自己选择我的效果图中背景选择的是pic3

3. 准备数据+添加地球高亮点及地球飞线

这里数据只提供一小部分示意,想要炫酷的点高亮效果数据量要够才可以哦~

<template>
  <div class="globalEarthContainer" id="globalEarthContainer"></div>
</template>
<script>
import * as echarts from 'echarts';
import 'echarts-gl';
import '@/utils/world.js';
import texture from '@/assets/newdashboard/global.jpg';// 
import env_star from '@/assets/dashboard/global/env_star3.jpg';
var chart = null;
export default {
  data() {
    return {
      map_2d: null,
      trajectory_data: [
        {
          coords: [
            [-43.36898, -21.776951],
            [6.037305, 46.304153],
          ],
          value: 79,
        },
        {
          coords: [
            [-71.965149, 45.406967],
            [2.263994, 48.847603],
          ],
          value: 47,
        },
        {
          coords: [
            [120.405823, 22.727173],
            [-72.526711, 42.391155],
          ],
          value: 41,
        },
        {
          coords: [
            [77.117668, 28.750074],
            [12.521381, 55.785576],
          ],
          value: 37,
        },
        {
          coords: [
            [8.670249, 49.41914],
            [-83.167488, 41.114845],
          ],
          value: 35,
        },
        {
          coords: [
            [151.704178, -32.892773],
            [-1.614661, 54.979187],
          ],
          value: 34,
        },
        {
          coords: [
            [7.212825, 51.488232],
            [8.54767, 47.376312],
          ],
          value: 33,
        },
        {
          coords: [
            [7.84595, 47.993546],
            [-81.665985, 41.500916],
          ],
          value: 29,
        },
        {
          coords: [
            [4.86572, 52.333755],
            [4.394886, 50.821659],
          ],
          value: 29,
        },
        {
          coords: [
            [0.135048, 52.194889],
            [-95.888664, 36.072567],
          ],
          value: 28,
        },
        {
          coords: [
            [11.353998, 44.496365],
            [-72.876297, 40.87479],
          ],
          value: 28,
        },
        {
          coords: [
            [9.227277, 45.478107],
            [-99.13456, 19.501354],
          ],
          value: 26,
        },
        {
          coords: [
            [150.878433, -34.405403],
            [-72.920235, 41.315128],
          ],
          value: 25,
        },
        {
          coords: [
            [20.457567, 44.818436],
            [-122.250031, 37.875927],
          ],
          value: 25,
        },
        {
          coords: [
            [-87.111984, 37.76894],
            [10.217297, 45.537838],
          ],
          value: 24,
        },
        {
          coords: [
            [144.965118, -37.808945],
            [130.425049, 33.626659],
          ],
          value: 24,
        },
        {
          coords: [
            [-3.189241, 55.944515],
            [37.189461, 56.746433],
          ],
          value: 24,
        },
        {
          coords: [
            [-87.627007, 41.834873],
            [87.310532, 22.314928],
          ],
          value: 23,
        },
        {
          coords: [
            [6.052951, 46.234032],
            [6.037305, 46.304153],
          ],
          value: 23,
        },
        {
          coords: [
            [126.653114, 37.449627],
            [-86.801865, 36.141346],
          ],
          value: 23,
        },
        {
          coords: [
            [-84.396698, 33.779884],
            [114.265465, 22.336399],
          ],
          value: 20,
        },
        {
          coords: [
            [-121.925842, 37.477684],
            [108.913795, 34.243614],
          ],
          value: 20,
        },
        {
          coords: [
            [-73.579025, 45.497265],
            [-122.636887, 45.57019],
          ],
          value: 20,
        },
        {
          coords: [
            [23.307348, 42.683857],
            [16.35157, 48.220345],
          ],
          value: 20,
        },
        {
          coords: [
            [2.345169, 48.842205],
            [6.566758, 46.519054],
          ],
          value: 19,
        },
        {
          coords: [
            [-92.068733, 32.530979],
            [9.955582, 48.42223],
          ],
          value: 19,
        },
        {
          coords: [
            [-83.167488, 41.114845],
            [8.670249, 49.41914],
          ],
          value: 19,
        },
        {
          coords: [
            [-80.114861, 26.883827],
            [14.391284, 50.103035],
          ],
          value: 19,
        },
        {
          coords: [
            [121.192513, 24.969481],
            [-118.290001, 34.019714],
          ],
          value: 18,
        },
        {
          coords: [
            [-81.665985, 41.500916],
            [7.84595, 47.993546],
          ],
          value: 18,
        },
        {
          coords: [
            [-74.451057, 40.494221],
            [2.340761, 48.85125],
          ],
          value: 18,
        },
        {
          coords: [
            [5.342293, 50.933533],
            [140.874069, 38.253834],
          ],
          value: 17,
        },
        {
          coords: [
            [-84.328011, 33.799316],
            [116.456879, 39.873989],
          ],
          value: 17,
        },
        {
          coords: [
            [2.211292, 48.714298],
            [6.566758, 46.519054],
          ],
          value: 17,
        },
        {
          coords: [
            [-76.998695, 38.936882],
            [4.700295, 50.877956],
          ],
          value: 17,
        },
        {
          coords: [
            [106.688606, 10.786378],
            [2.311249, 48.840374],
          ],
          value: 17,
        },
        {
          coords: [
            [14.504155, 46.049194],
            [-80.114861, 26.883827],
          ],
          value: 17,
        },
      ],
      thermodynamic: [
        {
          name_zh: '美国',
          name: 'United States',
          geo: { lat: 37.9992177, lng: -97.00002479999999 },
          expert_num: 26323,
        },
        {
          name_zh: '中国',
          name: 'China',
          geo: { lat: 35.0073952, lng: 104.9866713 },
          expert_num: 7171,
        },
        {
          name_zh: '英国',
          name: 'United Kingdom',
          geo: { lat: 53.981364, lng: -1.9953132 },
          expert_num: 6711,
        },
        {
          name_zh: '日本',
          name: 'Japan',
          geo: { lat: 36.0002914, lng: 138.0064397 },
          expert_num: 5650,
        },
        {
          name_zh: '意大利',
          name: 'Italy',
          geo: { lat: 42.8339394, lng: 12.8327414 },
          expert_num: 4407,
        },
        {
          name_zh: '德国',
          name: 'Germany',
          geo: { lat: 50.9991135, lng: 8.9987249 },
          expert_num: 4725,
        },
      ],
    };
  },
  methods: {
    init() {
      chart = echarts.init(document.getElementById('globalEarthContainer'));
    },
    async dataChange() {
      const lines = this.trajectory_data;
      const value = this.thermodynamic;
      let dataArr = [];
      lines.forEach((item) => {
        // item.value 的作用是控制 点距离地球表面的垂直距离
        dataArr.push([...item.coords[0], item.value]);
        dataArr.push([...item.coords[1], item.value]);
      });

      let series = value.map((item) => {
        // 首都点
        return {
          name: item.name,
          type: 'scatter3D',
          coordinateSystem: 'globe',
          blendMode: 'lighter',
          symbolSize: 10, // 点位大小
          itemStyle: {
            color: '#1890ff', // 各个点位的颜色设置
            opacity: 1, // 透明度
            borderWidth: 1, // 边框宽度
            borderColor: 'rgba(255,255,255,0.8)', //rgba(180, 31, 107, 0.8)
          },
          label: {
            show: true, // 是否显示字体
            position: 'left', // 字体位置。top、left、right、bottom
            formatter: item.name_zh, // 具体显示的值
            textStyle: {
              color: '#fff', // 字体颜色
              borderWidth: 0, // 字体边框宽度
              borderColor: '#fff', // 字体边框颜色
              fontFamily: 'sans-serif', // 字体格式
              fontSize: 18, // 字体大小
              fontWeight: 700, // 字体加粗
            },
          },
          data: [[item.geo.lng, item.geo.lat, 0]], // 数据来源
        };
      });
      let linesSeries = [
        // 飞线
        {
          type: 'lines3D',
          coordinateSystem: 'globe',
          blendMode: 'lighter',
          effect: {
            show: true,
            constantSpeed: 15,
          },
          data: lines
            .map((item) => ({
              lineStyle: {
                width: 1,
                color: 'rgb(255,255,255)',
                opacity: 0.7,
                trailWidth: 1,
                trailLength: 0.001,
              },
              ...item,
            }))
            .slice(0, 50),
        },
        {
          name: '点', // 高亮
          type: 'scatter3D',
          coordinateSystem: 'globe',
          blendMode: 'lighter',
          symbolSize: 2, // 点位大小
          itemStyle: {
            color: '#1890ff',
            opacity: 1, // 透明度
            borderWidth: 0, // 边框宽度
          },
          data: dataArr, // 数据
        },
      ];
      let option = {
        globe: {
          baseTexture: texture,
          environment: env_star,
          shading: 'realistic',
          globeOuterRadius: 120,
          realisticMaterial: {
            roughness: 0.9,
          },
          postEffect: {
            enable: true,
          },
          light: {
            ambient: {
              color: '#ffffff',
              intensity: 1,
            },
          },
          viewControl: {
            autoRotate: true,
            autoRotateSpeed: 5,
            targetCoord: [116.46, 39.92],
            alpha: 30,
            zoomSensitivity: 0,
          },
        },
        series: series.concat(linesSeries),
      };
      chart.setOption(option, true);
    },
  },
  async mounted() {
    await this.init();
    await this.dataChange();
  },
};
</script>

<style lang="less" scoped>
.globalEarthContainer {
  width: 100%;
  height: 100%;
}
</style>

pic1: env_star.jpg pic2: env_star2.jpg pic3: env_star3.jpg