简介:ECharts 3.8.5是百度开源的一款基于HTML5 Canvas的数据可视化JavaScript库,支持柱状图、折线图、饼图、散点图、地图等丰富图表类型,并提供悬停高亮、点击事件、缩放等交互能力,具备响应式适配、数据驱动和高效渲染大数据量的特点,适合前端开发者在PC和移动端快速实现可视化展示。该版本为2017年发布的稳定版,资源包内共3个文件,以两个JavaScript库文件和一个docs学习文档压缩包为主,整体大小约15.33MB。其中3.8.5核心库可直接在项目中引入使用,文档包则系统涵盖各图表类型的配置项、API接口、示例代码以及完整的API参考,便于查阅与调试。另附带一个4.0版本的min.js文件,可对比两个版本在性能、图表类型和接口上的差异,帮助开发者了解ECharts的演进方向。已有461人学习下载,适合初中级前端开发者或刚接触数据可视化的读者,借助核心库加文档的方式快速上手,并进一步理解从实例创建到动态更新、事件处理的完整流程。
1. 一份还活着的 3.8.5 源码,比 CDN 上的压缩包多了什么
接手某个老项目时,我第一次遇到echart3.8.5这个分支名。业务跑得好好的,图表却在新版浏览器上出现阴影渲染错位,CDN 上的echarts.min.js又定位不到问题。换成源码一追,才发现是旧版本里一个渐变对象被压缩器改写导致的。之所以要把echart3.8.5单独当做一个主题来写,是因为这个版本号的源码能救两种人:一种是维护 2017 年前后遗留下来的老系统、被锁定不能升大版本的前端;另一种是想基于稳定版做离线定制主题、改内部机制但不想接触新版本破坏性 API 的开发者。从源码拉取到最终产出可用的自定义包,整个链路比想象中短,坑却不少。
2. 先把仓库还原到 echart3.8.5:拉取、校验、目录五件套
2.1 为什么是 3.8.5:一个值得锁死的稳定分支
ECharts 3.x 经历了多次小版本迭代,3.8.5 属于 3.x 生命周期里相当靠后的补丁版。它的价值不在新功能,而在稳定:API 表面和 3.0 时代基本一致,setOption的写法、series的类型体系都定型了,但修掉了一批 3.2 到 3.6 阶段遗留的渲染和动画 bug。
选这个分支而不是直接抓 npm 包,原因很实际:npm 上的echarts@3.8.5只有压缩好的dist/echarts.min.js和dist/echarts.common.min.js,没有theme目录下的主题源码,没有src下的模块化源码,也没有example里的示例页。你要改主题变量、看某个graphic元素为什么偏移、甚至给 legend 加一个自定义 icon 绘制逻辑,都必须回到源码仓库。
常见做法是先从官方仓库拉取完整历史,再切到对应 tag 或分支。这里有个命名注意点:早期仓库里 3.x 的 tag 可能叫v3.8.5,而部分镜像分支直接叫3.8.5。接老项目时先看git tag列表,别凭记忆输入。
2.2 最小拉取命令:从零到本地可读源码
mkdir echarts-385 && cd echarts-385 git init git remote add origin https://github.com/你的镜像地址/echarts.git git fetch origin v3.8.5 --depth=1 git checkout v3.8.5提示:--depth=1是浅克隆,只拉这一个 tag 的文件和历史,几秒就能完成。如果后面要追源码演进或者用git log查某段代码是什么时候改的,就需要去掉--depth=1做全量拉取,代价是仓库体积更大、耗时更久。我一般先浅克隆,确认真要追历史再补拉。
拉完先做两件事:第一,git describe --tags,确认当前 HEAD 指向的版本字符串是v3.8.5,防止仓库里的 tag 名称混乱导致拿到相近版本;第二,打开package.json看version字段,对照是否也是3.8.5。双重校验能避免镜像仓库把 tag 打错位置的情况。
2.3 源码目录五件套:每个文件夹管什么
切到 3.8.5 后,目录结构和 4.x、5.x 有明显差异。你需要关心的是下面五个位置:
| 目录/文件 | 作用 | 在 3.8.5 里的注意点 |
|---|---|---|
src/ | 模块化源码,按echarts、chart、component拆分的 ES5 代码 | 改动后需要重新构建才能生效,不能直接被浏览器引用 |
build/ | 构建脚本和部分预编译产物 | 部分快照里带echarts.js和压缩版,但版本可能不是最新 |
example/ | 官方示例页,含每个图表类型的index.html | 本地直接双击能跑大部分示例,需要地图的示例要额外引 GeoJSON |
theme/ | 主题文件,如dark.js、infographic.js | 这是后期定制主题的重要起点 |
map/ | 部分 GeoJSON 和 JS 版本的地图数据 | 3.8.5 不强制内置地图,加载方式要看具体文件命名 |
第一次接触这个版本的人容易在src和dist之间犯迷糊:src里的代码用了模块化包装,每个图表类型是独立文件,浏览器不能直接识别;浏览器真正加载的是构建后的单文件。所以改源码之后,必须走一遍构建流程,或者至少用require方式把改动后的模块重新打包。后面第 3 章会专门讲构建产物和 CDN 文件的差异。
2.4 校验版本:避免镜像仓库的 tag 陷阱
镜像仓库经常出现 tag 指向错误提交的情况,最稳妥的做法是记录下官方发布时对应的 commit hash,拉取后用git rev-parse HEAD比对。
git rev-parse HEAD git log -1 --format="%H %ci"第一行输出当前 HEAD 的完整 hash,第二行输出该提交的日期和哈希。如果拿到的源码日期和 3.8.5 发布时间差距超过半个月,就要警惕这个 tag 可能被镜像重新打过。实际操作里,我遇到过镜像把v3.8.5挂在了3.8.4的提交上,导致某个折线图动画修复根本没进来。
校验通过后,把package.json里version字段改成一个带业务标识的版本号,比如3.8.5-hotfix.1,这样后续在系统里排查依赖版本时,能一眼看出这是基于官方版本做的补丁,而不是官方原包。
3. 本地产出可用的构建产物:npm 包与源码编译两条路
3.1 先分清两个产物:dist 目录里的 min 文件和源码构建出的文件
很多人拿echart3.8.5源码后第一反应是直接引用src/echarts.js,这是常见的翻车点。3.8.5 的src目录依赖一套内部模块加载机制,浏览器打开会报define is not defined。真正能上线用的是构建产物,而构建产物在 3.x 时代分为两种形态。
第一种是 npm 安装后自带的dist文件,体积小、压缩混淆过,适合直接<script>引入;第二种是用源码仓库里的构建脚本自行编译,生成的是带模块注释、便于排查问题的非压缩文件。老项目接源码时,我一般会两份都要:调试时用非压缩版,上线时用压缩版。
在 3.8.5 这个时间点,官方构建流程是基于 Node 脚本配合grunt实现的,和现在rollup的src结构不同。常见做法是直接执行仓库内的构建命令,而不是自己拼一个 webpack 去编译源码,因为 3.x 的源码里包含不少构建期才解析的宏定义,比如环境判断和性能开关,绕开官方构建很容易踩到变量未定义的坑。
3.2 方案一:npm 包方式锁定版本,最省事
如果不需要改源码,只是想让项目稳定使用 3.8.5,最可靠的方式是直接引入 npm 包。
npm install echarts@3.8.5 --save-exact--save-exact是把package.json里的依赖版本精确写成3.8.5,不加^或~前缀。这一点对老项目很重要:3.x 向后兼容并不完美,如果package.json里写的是"echarts": "^3.8.0",下次npm install可能因为 semver 规则拉到3.8.10或3.9.x,而那个新版本可能在使用Object.assign等新 API 时,让旧浏览器直接白屏。
安装完成后,在页面里引用的路径是node_modules/echarts/dist/echarts.min.js。需要按需加载的可以用echarts.common.min.js,它在dist目录下同样存在。区别在于common不包含map、graphic等扩展能力,但核心的柱状图、折线图、饼图都在,体积会小一些。
3.3 方案二:改源码后自己构建,一条命令跑通
当你要做的改动涉及src目录下的内部逻辑时,就要走源码构建。3.8.5 在 Node 8 到 Node 12 环境下构建成功率最高,Node 14 以上可能遇到node-sass安装失败。先装依赖,再跑构建。
# 推荐用 Node 12.x,避免新版 node-gyp 编译原生模块失败 nvm install 12 nvm use 12 npm install npm run build构建脚本做的事情大致是:把src下所有模块按依赖关系合并,执行语法降级,然后产出非压缩和压缩两份文件。执行完成后,在build目录下能看到类似echarts.js和echarts.min.js的新产物。构建过程少则一分钟,多则三分钟,如果超过五分钟还在跑,多半是某个依赖没装全或者网络卡住,需要把npm install生成的node_modules删掉重来。
参数层面的注意点:如果只想构建非压缩版,可以修改build/build.js或者对应的grunt任务,跳过压缩这一步;但上线前一定要用压缩版做一次回归,因为文件混淆后变量名变短,偶尔会暴露出源码里依赖函数名长度的写法。
3.4 跑通官方示例页:验证构建产物是否可用
构建完成后的第一步验证,不是直接丢进业务系统,而是先把example目录下的示例页跑起来。
# 在源码仓库根目录启动一个静态服务器 python -m SimpleHTTPServer 8000然后打开http://localhost:8000/example/,选择一个包含折线图和柱状图的示例页,比如line1.html。如果页面能正常渲染出图表,说明产物完整;如果报Cannot read property 'xxx' of undefined,优先检查build/echarts.js是不是真的构建成功,时间戳是否为当前时间。3.8.5 的示例页大多能直接双击打开,因为脚本用的是相对路径引用的构建产物,不需要 npm 启动流程。
示例页还有一层价值:它是判断主题、地图、图表组件是否配套的最好参照物。如果某个示例用到map类型但页面空白,大概率是map/目录下的 GeoJSON 没有通过地图注册接口手动注册。
4. echart3.8.5 踩坑清单:地图、主题、构建三处重灾区
4.1 地图不出图:GeoJSON 没有手动注册
现象:在 3.8.5 中使用type: 'map'的 series,只看到坐标轴和默认背景,实际地图轮廓完全不存在。
原因:3.8.5 的内置map机制和 5.x 不同,它不会自动加载中国地图或世界地图的数据,必须先把 GeoJSON 注册成可用的地图类型。很多从 4.x 迁回来的人会下意识写geo: { map: 'china' },但在 3.8.5 里这个写法不会触发任何自动加载。
解决:先引入地图的 JS 文件,再调用注册接口。
// 注册地图数据到 echarts 内部 // 假设 china.js 文件里挂载了全局的中国地图 GeoJSON 变量 var geoJson = window.chinaGeoJson || window.echartsMapData; echarts.registerMap('china', geoJson); var chart = echarts.init(document.getElementById('main')); chart.setOption({ geo: { map: 'china', roam: true } });这里的registerMap在 3.8.5 中是挂在echarts全局对象上的顶层方法,不需要import。参数第一个是地图名称,第二个是 GeoJSON 对象;调动时机必须早于setOption。如果地图数据量较大,建议引入独立的地图 JS 文件而不是内联在页面里,否则首次渲染会阻塞主线程好几秒。
4.2 自定义主题颜色不生效:主题注册时机太晚
现象:用echarts.init(dom, 'customTheme')初始化后,控制台没有报错,但图表的颜色依然是默认色板。
原因:主题注册发生在init之后,或者主题对象里字段结构与 3.8.5 不匹配。3.8.5 的theme目录下提供的是 JS 文件而非 JSON,主题对象里color是数组,backgroundColor是字符串,categoryAxis.splitLine是对象。如果直接把 4.x 的主题 JSON 拿来用,字段对不上,样式就会失效。
解决:从theme目录拷贝dark.js作为基底,改完字段后再注册。
// 把改好的主题对象挂到全局,再执行注册 echarts.registerTheme('customTheme', customThemeObject); // 注册完成后才能初始化 var chart = echarts.init(document.getElementById('main'), 'customTheme');这里有个容易被忽略的顺序问题:registerTheme必须在init之前调用,而且同一个页面里如果有多个图表,每个init都要传入相同的主题名。我遇到过一次只给第一个图表传主题、第二个没传,结果两个图表颜色不一致的情况,排查了很久才发现是初始化参数漏了。
4.3 构建时 node-sass 拉不下来:锁 Node 版本
现象:npm install执行到一半报错,提示node-sass安装失败,错误信息里包含gyp字样。
原因:3.8.5 时代的依赖链里带有node-sass,它对 Node 版本敏感。Node 14 以上的环境通常会触发编译失败,因为node-sass没有预编译二进制。
解决:切到 Node 12 LTS,删除node_modules后重来。
nvm install 12 nvm use 12 rm -rf node_modules package-lock.json npm install如果公司内网限制 npm 源,先设置镜像源再继续。构建工具属于历史遗留依赖,不建议升级到新版本去适配,因为一旦升级,构建产物可能和源码预期不一致。锁定 Node 版本是成本最低的操作。
4.4 容器尺寸为 0 导致图表不渲染:init 时机太早
现象:页面加载完,echarts.init不报错,setOption也执行了,但图表区域空白。
原因:init执行时容器div的宽高属性还没有被浏览器计算出来,或者父元素使用了display: none。3.8.5 在容器尺寸为 0 时不会抛出致命错误,但渲染结果就是一个空画布。
解决:等容器可见后再初始化。
function initChartWhenReady() { var dom = document.getElementById('chartBox'); if (dom.clientWidth === 0 || dom.clientHeight === 0) { setTimeout(initChartWhenReady, 200); return; } chart = echarts.init(dom); chart.setOption(option); }这种轮询方式虽然不优雅,但在老项目里最稳定。另一种做法是监听页面resize,在容器尺寸变化后调用chart.resize(),但 3.8.5 的resize不负责初始化,只能解决已经初始化的图表尺寸自适应问题。遇到弹层里嵌图表的情况,我建议把初始化放到弹层动画结束后再触发。
5. 从 3.8.5 拉出自定义主题包:一次替换主题变量的熟练操作
5.1 复制官方主题并修改颜色体系
打开theme/dark.js,里面是一个名为darkTheme的对象。它的结构大致分为color、backgroundColor、textStyle、legend、categoryAxis、valueAxis几块。复制一份改名为customTheme.js,保留除color外的结构,替换成业务品牌色。
var customTheme = { // 系列颜色循环使用的数组,顺序影响图表里多条线的着色 color: ['#2f6fed', '#19c37d', '#ff9f1c', '#e74c3c'], backgroundColor: '#ffffff', textStyle: { fontFamily: 'PingFang SC, Microsoft YaHei, sans-serif', fontSize: 12 }, legend: { textStyle: { color: '#333333' } }, categoryAxis: { axisLine: { lineStyle: { color: '#d9d9d9' } } }, valueAxis: { splitLine: { lineStyle: { color: '#f0f0f0', type: 'dashed' } } } };color数组的替换是最直接生效的改动。需要注意,3.8.5 里同一系列的itemStyle.color如果写死在series内部,会覆盖主题里的顺序色板,所以改主题只影响没有显式指定颜色的部分。
5.2 验证主题包的正确姿势
在example目录下新建一个测试页,单独引用这份主题文件,用最简单的柱状图和折线图验证颜色、字体、坐标轴是否都符合预期。然后不看渲染结果,直接看window上挂载的主题对象是否完整打印出来——先确认对象结构没问题,再谈样式对不对。
<script src="customTheme.js"></script> <script> echarts.registerTheme('customTheme', customTheme); </script>验证时检查三处:背景色是否为#ffffff,第一条柱子的颜色是否为数组第一个色值,坐标轴分割线是否为虚线。这三处全对了,主题基本可用,再套进老项目页面里做一次回归。
我自己的习惯是,主题文件单独作为一个 JS 文件存放,不混进业务脚本里。这样换主题时,只需要替换文件内容,不需要改动页面里任何init代码。3.8.5 的主题机制决定了它很难做到运行时动态切换,所以提前把主题文件独立出来,是后面最省事的设计。希望帮到你。
本文还有配套的精品资源,点击获取