Toggle navigation
集客麦麦@谢坤
首页
随笔
首页
>>
创作中心
>>
深入 ECharts...
深入 ECharts 地理可视化:Geo + Graphic + Custom Series 实战指南
[TOC] 在企业级大屏、地理信息系统(GIS)、园区/区域可视化开发中,ECharts 凭借强大的地理渲染能力、灵活的自定义图形和完善的交互体系,成为首选可视化库。本文将深度拆解 **Geo 地理坐标系**、**Graphic 原生图形**、**Custom Series 自定义系列** 三大核心模块,并结合坐标转换这一关键技术,从原理、用法到实战落地,帮你彻底掌握 ECharts 地理可视化的核心逻辑。 --- ## 一、开篇:地理可视化的核心三驾马车 ECharts 实现复杂地理可视化(如自定义地图、可拖拽标注、多边形区域、组合图标),离不开三个核心组件的配合: - **Geo**:地理坐标系底座,承载地图、绑定坐标、支持缩放拖拽; - **Graphic**:原生图形层,绘制基础交互图形(点/线/面/文本); - **Custom Series**:自定义系列,渲染复杂个性化业务图形; - **坐标转换**:连接地理坐标与像素坐标,实现精准交互。 三者各司其职、相互配合,构成了 ECharts 地理可视化的完整技术栈。 --- ## 二、Geo 地理坐标系:地图渲染的底座 ### 1. 核心作用 Geo 是 ECharts 地理可视化的根组件,负责: - 加载/渲染地图(支持 GeoJSON、SVG 两种格式); - 提供地理坐标系,统一所有图形的坐标基准; - 支持地图缩放、拖拽(roam)、视角限制。 ### 2. 关键配置与实战用法 #### (1)自定义地图注册(SVG/GeoJSON) 默认地图仅包含国家/省份,自定义 SVG 地图更适合园区、建筑、厂区等场景: ```javascript import { registerMap } from 'echarts/core'; // 注册 SVG 地图(核心:地图ID + SVG 文本) registerMap('campus-map', { svg: '
...
' // 自定义 SVG 地图内容 }); ``` #### (2)Geo 基础配置 ```javascript option: { geo: { map: 'campus-map', // 绑定已注册的地图ID roam: true, // 开启缩放/拖拽(true=自由,"scale"=仅缩放,"move"=仅拖拽) scaleLimit: { min: 0.5, max: 10 }, // 缩放范围限制 left: 0, right: 0, top: 0, bottom: 0, // 铺满容器 silent: false, // 是否响应鼠标事件 itemStyle: { // 地图默认样式 areaColor: '#122345', borderColor: '#2ab7f8' } } } ``` #### (3)自适应防拉伸(关键) SVG 地图宽高比固定,容器比例不一致会导致拉伸,解决方案: ```javascript // 计算容器与 SVG 宽高比,动态调整 Geo 布局 const wrapperRatio = containerWidth / containerHeight; const svgRatio = svgWidth / svgHeight; const geoLayout = wrapperRatio > svgRatio ? { top: 0, bottom: 0 } // 垂直铺满 : { left: 0, right: 0 }; // 水平铺满 // 合并到 Geo 配置 geo: { ...geoLayout } ``` ### 3. 核心 API:坐标转换(地理 ↔ 像素) Geo 最核心的能力是坐标互转,所有交互(拖拽、点击、绘制)都依赖它: ```javascript const chart = echarts.getInstanceByDom(dom); // 1. 地理坐标 → 像素坐标(绘图用) const pixel = chart.convertToPixel({ geoIndex: 0 }, [116.4, 39.9]); // 2. 像素坐标 → 地理坐标(交互用) const geoCoord = chart.convertFromPixel({ geoIndex: 0 }, [200, 300]); ``` `geoIndex: 0`:对应第一个 Geo 组件(多地图时使用)。 --- ## 三、Graphic 原生图形层:交互基础图形的首选 ### 1. 核心作用 Graphic 是 ECharts 提供的原生图形绘制层,独立于系列(series),适合: - 绘制简单基础图形(圆、线、多边形、文本、图片); - 实现交互需求(拖拽、点击、动画); - 叠加在地图上方,作为辅助标注/控制点。 ### 2. 支持的图形类型 ```typescript type GraphicType = | 'circle' // 圆 | 'polyline' // 折线 | 'polygon' // 多边形 | 'text' // 文本 | 'image' // 图片 | 'path' // 自定义路径 | 'group' // 图形组(组合多个图形) ``` ### 3. 实战核心用法 #### (1)可拖拽控制点(常用) ```javascript option: { graphic: [ { type: 'circle', position: [200, 300], // 像素坐标 draggable: true, // 开启拖拽 shape: { cx: 0, cy: 0, r: 8 }, // 圆心、半径 style: { fill: '#2ab7f8', stroke: '#fff' }, z: 10, // 层级(越大越上层) // 拖拽事件 ondrag: (e) => { const newPixel = [e.target.x, e.target.y]; const newGeo = chart.convertFromPixel({ geoIndex: 0 }, newPixel); console.log('新地理坐标:', newGeo); } } ] } ``` #### (2)动态虚线(流动效果) ```javascript { type: 'polyline', shape: { points: [[100,200], [300,400], [500,300]] }, style: { stroke: '#2ab7f8', lineWidth: 2, lineDash: [6, 3] // 虚线样式 }, // 关键帧动画:虚线流动 keyframeAnimation: { duration: 1400, loop: true, keyframes: [{ percent: 1, style: { lineDashOffset: -9 } }] } } ``` #### (3)多边形区域(高亮/填充) ```javascript { type: 'polygon', shape: { points: [[100,200], [300,400], [500,300]] }, style: { fill: 'rgba(42, 183, 248, 0.2)', // 填充色 stroke: '#2ab7f8', // 边框色 opacity: 0.8 } } ``` ### 4. Graphic 核心特性 - **交互原生支持**:`draggable`、`onclick`、`ondrag` 直接绑定; - **层级控制**:`z`/`zlevel` 控制上下层; - **动画支持**:`keyframeAnimation` 实现渐变、流动、闪烁; - **无数据绑定**:直接用像素坐标,适合临时/辅助图形。 --- ## 四、Custom Series 自定义系列:复杂业务图形的终极方案 ### 1. 核心作用 Custom Series 是 ECharts 最灵活的系列类型,通过 `renderItem` 函数完全接管渲染逻辑,适合: - 绘制组合图形(多边形 + 文字 + 图标、自定义标注); - 绑定业务数据(区域 ID、名称、状态); - 统一管理地理坐标(自动适配 Geo 坐标系)。 ### 2. 核心配置 ```javascript option: { series: [ { type: 'custom', // 自定义系列 coordinateSystem: 'geo', // 绑定 Geo 坐标系 data: [[116.4, 39.9, { name: '北京', id: 1 }]], // 坐标+业务数据 renderItem: (params, api) => { // 核心渲染函数 return 图形对象; } } ] } ``` ### 3. renderItem 核心参数 - **params**:系列参数(数据索引、系列信息); - **api**:核心工具对象: - `api.coord(geoCoord)`:地理坐标 → 像素坐标; - `api.value(index)`:获取 data 中对应索引的数据; - `api.style()`:获取默认样式。 ### 4. 实战:多边形 + 居中文字(区域标注) ```javascript renderItem: (params, api) => { // 1. 获取地理坐标 → 转像素坐标 const points = [[116.4,39.9], [116.5,39.9], [116.5,40.0]]; const pixelPoints = points.map(p => api.coord(p)); // 2. 计算中心点(文字定位) const centerX = pixelPoints.reduce((sum, p) => sum + p[0], 0) / pixelPoints.length; const centerY = pixelPoints.reduce((sum, p) => sum + p[1], 0) / pixelPoints.length; // 3. 返回组合图形(group) return { type: 'group', children: [ // 多边形 { type: 'polygon', shape: { points: pixelPoints }, style: { fill: 'rgba(42, 183, 248, 0.2)', stroke: '#2ab7f8' } }, // 居中文字 { type: 'text', style: { x: centerX, y: centerY, text: '核心区域', textAlign: 'center', textVerticalAlign: 'middle', fill: '#fff', fontSize: 16 } } ] }; } ``` ### 5. Custom Series 优势 - **数据驱动**:图形与业务数据强绑定,便于交互回调; - **组合图形**:`group` 嵌套任意图形,实现复杂 UI; - **坐标系自动适配**:无需手动计算坐标,`api.coord` 一键转换; - **系列化管理**:统一纳入 ECharts 事件、tooltip、动画体系。 --- ## 五、核心技术:坐标转换(Geo ↔ Pixel) ### 1. 为什么必须做坐标转换? - **Geo 坐标**:地理/自定义坐标(如 [116.4, 39.9]),用于数据存储、业务逻辑; - **像素坐标**:画布坐标(如 [200, 300]),用于绘图、交互(拖拽/点击)。 所有交互操作,都必须先转像素坐标,再转回地理坐标存储。 ### 2. 两种转换方式对比 | 方式 | 适用场景 | 语法 | |------|----------|------| | `chart.convertToPixel` | 全局转换(Graphic、外部调用) | `chart.convertToPixel({ geoIndex:0 }, geoCoord)` | | `api.coord` | Custom Series 内部 | `api.coord(geoCoord)` | ### 3. 实战:拖拽同步坐标(闭环逻辑) ```javascript // 1. 拖拽 Graphic 圆 → 获取像素坐标 ondrag: (e) => { const pixel = [e.target.x, e.target.y]; // 2. 转地理坐标 const geo = chart.convertFromPixel({ geoIndex:0 }, pixel); // 3. 更新数据 coords.value = geo; // 4. 重新渲染 updateChartPoints(); } ``` --- ## 六、三大组件配合:实战最佳实践 ### 1. 分工明确 - **Geo**:只负责地图底座、坐标系统; - **Graphic**:负责交互控制点、动态辅助线、临时图形; - **Custom Series**:负责业务图形、区域标注、组合图标。 ### 2. 动态更新策略 ```javascript // 局部更新(不重绘整个图表) function updateChart(chart, graphic, series) { chart.setOption( { graphic, series }, { notMerge: false, // 合并配置 replaceMerge: ['series', 'graphic'] // 仅替换指定模块 } ); } ``` ### 3. 事件统一处理 - **点击/拖拽**:graphic 直接绑定事件; - **业务图形点击**:series 绑定 click 事件,通过 `params.data` 获取业务数据; - **地图缩放/拖拽**:监听 `geoRoam` 事件,同步所有图形坐标。 --- ## 七、总结:ECharts 地理可视化核心心法 - **Geo 是根**:所有地理图形必须绑定 Geo 坐标系,坐标转换是交互基础; - **Graphic 是交互利器**:简单图形、拖拽、动画优先用 Graphic; - **Custom Series 是业务载体**:复杂、数据驱动的业务图形必选 Custom; - **坐标转换是桥梁**:地理坐标存数据,像素坐标做交互; - **分层渲染**:底座(Geo)→ 业务图形(Custom)→ 交互控件(Graphic)。 掌握这套逻辑,无论是园区可视化、地理监控大屏,还是自定义地图标注,都能轻松实现! --- ## 附录:常用工具函数封装 ```javascript // 地理坐标 → 像素坐标 export const geoToPixel = (chart, geoCoord) => { return chart?.convertToPixel({ geoIndex: 0 }, geoCoord) || [0, 0]; }; // 像素坐标 → 地理坐标 export const pixelToGeo = (chart, pixel) => { return chart?.convertFromPixel({ geoIndex: 0 }, pixel) || [0, 0]; }; // 创建可拖拽 Graphic 圆 export const createDragCircle = (pixel, onDrag) => ({ type: 'circle', position: pixel, draggable: true, shape: { cx: 0, cy: 0, r: 8 }, ondrag: onDrag }); ```