echarts 绘制3D中国地图

一、项目背景

本项目基于 ECharts 和 ECharts-GL 实现了一个3D中国地图的可视化页面,支持地图区域高亮、涟漪散点、动态飞线等效果,适用于地理数据展示、流向分析等场景。

二、效果图

  • 3D中国地图,带有地形贴图和立体边界。
  • 主要城市以涟漪散点高亮显示。
  • 城市间流向以动态飞线展示,直观表现数据流动。

三、实现过程

1. 技术选型

  • ECharts:强大的数据可视化库,支持丰富的图表类型和地理可视化。
  • ECharts-GL:ECharts 的 3D 扩展,支持三维地图、三维柱状图等高级可视化效果。
  • Vue.js:前端主流框架,负责页面结构和生命周期管理。

2. 地图数据准备

使用了 china.json 作为中国地图的 GeoJSON 数据源,放置于 src/utils/china.json。 贴图采用了 map.svg,增强地图的地形感和美观度。 点击这里获取中国地图json

3. 主要实现步骤

(1)地图注册与初始化

在 mounted 钩子中,注册中国地图并初始化 ECharts 实例:

javascript 复制代码
import * as echarts from 'echarts'
import "echarts-gl";
import geoJson from '@/utils/china.json'

mounted() {
	//点击散点城市坐标位置
    const chinaData = [
        { name: '北京市', value: [116.405285, 39.904989] },
        { name: '成都', value: [104.0657, 30.6598] },
        { name: '上海', value: [121.4737, 31.2304] },
        { name: '拉萨', value: [91.11, 29.97] }
    ];
    const myChart = echarts.init(document.getElementById('mapContainer'));
    this.initChart('china', chinaData, myChart)
}

(2)3D地图与贴图

使用 geo3D 配置项实现三维地图。 通过 colorMaterial.detailTexture 属性,将2D地图渲染为纹理贴图,贴在3D地图表面,提升真实感。

因3d地图无法实现散点效果,故此采用3d和2d贴合实现,散点效果

javascript 复制代码
geo3D: {
    map: 'china',
    regionHeight: 2.1,
    shading: 'color',
    colorMaterial: {
        detailTexture: mapBg, // 纹理贴图
        textureTiling: 1
    },
    // ... 视角、边界等配置
}

(3)下层地图与分层效果

通过 series 添加 map3D 类型,设置不同的 regionHeight,实现地图分层立体感。

(4)2D地图贴图生成

LoadMapping 方法生成2D地图配置,主要用于生成纹理贴图。 贴图采用 SVG 图像,提升地图的美观度和辨识度。

javascript 复制代码
itemStyle: {
    areaColor: {
        type: 'pattern',
        image: require('../assets/images/map.svg'),
        repeat: 'no-repeat',
    },
}

(5)涟漪散点与飞线

使用 effectScatter 实现城市位置的涟漪散点动画。 使用 lines 实现城市之间的动态飞线,模拟流向效果。

javascript 复制代码
{
    type: `effectScatter`,
    coordinateSystem: `geo`,
    rippleEffect: { period: 5, scale: 4, brushType: 'fill' },
    itemStyle: { normal: { color: 'yellow', shadowBlur: 10, shadowColor: '#333' } },
    symbolSize: 16,
    data: [ ... ]
},
{
    type: 'lines',
    effect: { show: true, period: 4, trailLength: 0.4, symbol: 'arrow', symbolSize: 7 },
    lineStyle: { normal: { color:'#1DE9B6', width: 3, opacity: 0.6, curveness: .3 } },
    data: [ ... ]
}

(6)完整代码

html 复制代码
<template>
    <div>
        <div style="width: 100%; height: 100%;">
            <div class="contanier"></div>
            <div ref="mapContainer" id="mapContainer" style="width: 100%; height: 100vh;"></div>
        </div>
    </div>
</template>
<script>
import * as echarts from 'echarts'
import "echarts-gl";
import geoJson from '@/utils/china.json'
export default {
    data() {

    },
    mounted() {
        const chinaName = 'china';
        const chinaData = [{ name: '北京市', value: [116.405285, 39.904989] },{ name: '成都', value: [104.0657, 30.6598] },{ name: '上海', value: [121.4737, 31.2304] },{ name: '拉萨', value: [91.11, 29.97] }];
        const myChart = echarts.init(document.getElementById('mapContainer'));
        this.initChart('china', chinaData, myChart)
    },
    methods: {
        initChart(name, data, myChart) {
            // const myChart = echarts.init(this.$refs.mapContainer);
            echarts.registerMap("china", geoJson); // 注册地图
            const canvas = document.createElement(`canvas`);
            var mapBg = echarts.init(canvas, null, {
                width: 1024,
                height: 1024,
            });
            const chartOption = this.LoadMapping(name);
            mapBg.setOption(chartOption);
            let option = {
                backgroundColor: '#000000',
                // 上层
                geo3D: {
                    map: 'china',
                    regionHeight: 2.1, //地图厚度
                    label: {
                        show: false,
                        color: '#fff',
                    },
                    itemStyle: {
                        borderWidth: 1, //分界线宽度
                        borderColor: '#fff', //分界线颜色
                    },
                    emphasis: {
                        label: {
                            show: false,
                        },
                    },
                    shading: 'color', // lambert  color  realistic  只有为color时,可以设置colorMaterial,实现将平面地图贴在3D地图上
                    colorMaterial: {
                        detailTexture: mapBg, // 纹理贴图
                        textureTiling: 1 // 纹理平铺,1是拉伸,数字表示纹理平铺次数
                    },
                    viewControl: {
                        distance: 90, // 地图视角 控制初始大小
                        beta: 0, //旋转视角
                        alpha: 90, //视角
                        center: [0, 0, 0],
                    },
                },
                series: [
                    // 下层
                    {
                        type: "map3D",
                        map: "china",
                        regionHeight: 2, //地图厚度
                        label: {
                            show: false,
                            color: '#ff000000',
                        },
                        itemStyle: {
                            normal: {
                                color: "rgba(52, 299, 218, 1)",
                            }
                        },
                        viewControl: {
                            distance: 90, // 地图视角 控制初始大小
                            beta: 0, //旋转视角
                            alpha: 90, //视角
                            center: [0, 0, 0],
                        },
                    },
                ],
            }
            myChart.setOption(option, true);
        },
        // 2D地图
        LoadMapping(name) {
            var chartOption = {
                geo: {
                    show: true,
                    map: name,
                    top: '0',
                    width: 1024,
                    label: {
                        position: 'top',
                        distance: 4,
                        normal: {
                            show: true,
                            textStyle: {
                                color: '#fff'
                            }
                        },
                    },
                    itemStyle: {
                        areaColor: {
                            type: 'pattern',
                            image: require('../assets/images/map.svg'), // 贴图(山形地貌图)
                            repeat: 'no-repeat',
                            
                        },
                    },
                },

                series: [
                    {
                        type: `effectScatter`,  // 散点, scatter不能实现涟漪效果
                        coordinateSystem: `geo`,
                        showEffectOn: 'render',
                        zlevel: 5,
                        rippleEffect: {
                            period: 5,
                            scale: 4,
                            brushType: 'fill'
                        },

                        hoverAnimation: true,
                        itemStyle: {
                            normal: {
                                color: 'yellow',
                                shadowBlur: 10,
                                shadowColor: '#333'
                            }
                        },
                        symbolSize: 16,
                        data: [{ name: '北京市', value: [116.405285, 39.904989] },
                            { name: '成都', value: [104.0657, 30.6598] },
                            { name: '上海', value: [121.4737, 31.2304] },
                            { name: '拉萨', value: [91.11, 29.97] },
                        ]
                    },
                    {
                        type: 'lines',
                        zlevel: 6,
                        effect: {
                            show: true,
                            period: 4, //箭头指向速度,值越小速度越快
                            trailLength: 0.4, //特效尾迹长度[0,1]值越大,尾迹越长重
                            symbol: 'arrow', //箭头图标
                            symbolSize: 7, //图标大小
                        },
                        lineStyle: {
                            normal: {
                                color:'#1DE9B6', //尾迹线条颜色
                                width: 3,
                                opacity: 0.6,
                                // opacity: 0.2, //尾迹线条透明度
                                curveness: .3 //尾迹线条曲直度
                            }
                        },
                            data: [
                                {coords: [[104.0657, 30.6598],[116.405285, 39.904989]]}
                            , {coords: [[121.4737, 31.2304],[116.405285, 39.904989]]}
                            , {coords: [[91.11, 29.97],[116.405285, 39.904989]]}
                            ]
                        }

                ]
            }

            return chartOption;
        }
    }
}
</script>

六、总结

本项目通过 ECharts-GL 实现了高质量的3D中国地图可视化,集成了贴图、分层、动画等多种高级效果,适合用于地理数据分析、流向展示等多种场景。开发过程中,合理利用 ECharts 的配置项和资源管理,可以高效实现复杂的可视化需求。

相关推荐
蓝婷儿30 分钟前
每天一个前端小知识 Day 27 - WebGL / WebGPU 数据可视化引擎设计与实践
前端·信息可视化·webgl
然我37 分钟前
面试官:如何判断元素是否出现过?我:三种哈希方法任你选
前端·javascript·算法
OpenTiny社区1 小时前
告别代码焦虑,单元测试让你代码自信力一路飙升!
前端·github
pe7er1 小时前
HTTPS:本地开发绕不开的设置指南
前端
晨枫阳1 小时前
前端VUE项目-day1
前端·javascript·vue.js
江山如画,佳人北望1 小时前
SLAM 前端
前端
患得患失9491 小时前
【前端】【Iconify图标库】【vben3】createIconifyIcon 实现图标组件的自动封装
前端
颜酱1 小时前
抽离ant-design后台的公共查询设置
前端·javascript·ant design
用户95251151401552 小时前
js最简单的解密分析
前端
FogLetter2 小时前
深入浅出React-Router-Dom:从前端路由到SPA架构的华丽转身
前端·react.js