ECharts图表插件官网下载 安装配置及常见使用问题解决方案
大家好,今天我们来好好聊聊ECharts这个图表利器。如果你曾经在网页上见过那些酷炫的柱状图、折线图、饼图,那十有八九就是它干的活儿。这篇文章我会从实际使用的角度,带你把ECharts从头到尾摸清楚,包括下载、安装、配置,还有那些让人头疼的问题怎么解决。
ECharts是啥玩意儿
ECharts是百度开源的一个纯JavaScript图表库,现在由Apache软件基金会维护(官方仓库地址是 apache/echarts),支持浏览器和Node.js环境。它的特点是:
- 功能强大:支持折线图、柱状图、散点图、饼图、雷达图、地图、K线图、热力图等等几十种图表类型
- 跨平台:兼容主流浏览器,也支持SSR服务端渲染
- 性能好:大规模数据渲染流畅,Canvas和SVG两种渲染模式可选
- 配置简单:通过option配置项就能快速搭建图表
官网地址是 https://echarts.apache.org/ ,目前最新版本已经是 5.5.x 系列了(截至2024年),比起早年的3.x版本,性能优化和功能完善都有质的飞跃。
下载ECharts
方式一:直接下载官方打包文件(适合新手)
打开官网 https://echarts.apache.org/zh/download.html ,你会看到几个选项:
- ECharts 主文件:下载
echarts.min.js(压缩版)或echarts.js(完整版) - ECharts 含地图:如果用到地图功能,需要额外下载
echarts-world.js或特定地区的地图文件 - ECharts GL:如果需要3D图表效果,下载
echarts-gl.min.js
推荐使用压缩版,文件更小,加载更快。完整版的代码可读性更好,适合学习和调试。
方式二:通过包管理器安装(推荐前端项目使用)
如果你在用npm、yarn或pnpm管理依赖,这是最规范的做法:
# 使用npm安装
npm install echarts --save
# 使用yarn安装
yarn add echarts
# 使用pnpm安装
pnpm add echarts
安装完成后,你可以在项目 node_modules 目录下看到ECharts的文件结构:
node_modules/echarts/
├── dist/
│ ├── echarts.min.js # 压缩版
│ └── echarts.js # 完整版
├── package.json
└── index.js
方式三:CDN引入(最快捷)
不想下载?直接用CDN引用,在项目HTML里加一行:
<!-- 官方CDN -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
<!-- 或官方镜像 -->
<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
<!-- 或UNPKG -->
<script src="https://unpkg.com/echarts@5/dist/echarts.min.js"></script>
注意版本号 5.5.0 可以换成你需要的版本,建议在CDN服务上锁死版本,避免意外升级导致的问题。
方式四:TypeScript项目安装类型声明
如果你用TypeScript,还需要安装类型定义文件,否则IDE里会报类型错误:
npm install @types/echarts --save-dev
安装后,在tsconfig.json里确保类型声明被包含:
{
"compilerOptions": {
"types": ["echarts", "node"]
}
}
安装配置
基础配置(HTML + 原生JS)
这是最简单的用法,任何网页都能用:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>ECharts Demo</title>
<!-- 引入ECharts -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script>
<style>
/* 容器必须有明确的高度,这是很多人踩的坑 */
#chart-container {
width: 800px;
height: 500px;
border: 1px solid #ddd;
border-radius: 8px;
}
</style>
</head>
<body>
<h2>我的第一个ECharts图表</h2>
<!-- 准备一个DOM容器 -->
<div id="chart-container"></div>
<script>
// 初始化ECharts实例,传入容器DOM元素
var chartDom = document.getElementById('chart-container');
var myChart = echarts.init(chartDom);
// 配置项
var option = {
// 标题
title: {
text: '2024年各季度销售额',
left: 'center',
textStyle: { fontSize: 18, fontWeight: 'bold' }
},
// 提示框组件
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' }
},
// 图例
legend: {
data: ['A产品', 'B产品'],
top: 30
},
// 工具箱
toolbox: {
show: true,
feature: {
saveAsImage: {}, // 保存图片
dataView: {}, // 数据视图
restore: {}, // 还原
dataZoom: {} // 数据缩放
}
},
// X轴
xAxis: {
type: 'category',
data: ['Q1', 'Q2', 'Q3', 'Q4'],
axisLabel: { fontSize: 14 }
},
// Y轴
yAxis: {
type: 'value',
name: '销售额(万元)',
axisLabel: { formatter: '{value} 万' }
},
// 系列数据
series: [
{
name: 'A产品',
type: 'bar',
data: [1200, 1500, 1800, 2100],
itemStyle: { color: '#5470c6' },
barWidth: '40%'
},
{
name: 'B产品',
type: 'bar',
data: [800, 1100, 900, 1300],
itemStyle: { color: '#91cc75' },
barWidth: '40%'
}
]
};
// 使用配置项
myChart.setOption(option);
// 监听窗口大小变化,实现响应式
window.addEventListener('resize', function () {
myChart.resize();
});
</script>
</body>
</html>
这个例子涵盖了标题、tooltip、图例、工具箱、坐标轴、系列数据等核心配置,跑起来就是一个带交互功能的柱状图。
Vue项目中使用
现在Vue项目非常普遍,我们来看看在Vue 3中怎么用:
<!-- Chart.vue -->
<template>
<div ref="chartRef" class="chart-container"></div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
import * as echarts from 'echarts'
const chartRef = ref(null)
let chartInstance = null
const initChart = () => {
if (!chartRef.value) return
// 初始化实例
chartInstance = echarts.init(chartRef.value)
// 配置项
const option = {
title: { text: '数据趋势', left: 'center' },
tooltip: { trigger: 'axis' },
legend: { data: ['访问量', '注册量'] },
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: { type: 'value' },
series: [
{
name: '访问量',
type: 'line',
smooth: true,
data: [120, 200, 150, 80, 70, 110, 130],
itemStyle: { color: '#5470c6' },
areaStyle: { opacity: 0.3 }
},
{
name: '注册量',
type: 'line',
smooth: true,
data: [50, 80, 60, 40, 30, 60, 70],
itemStyle: { color: '#91cc75' }
}
]
}
chartInstance.setOption(option)
}
// 监听数据变化,动态更新图表
watch(
() => props.chartData,
(newData) => {
if (chartInstance && newData) {
chartInstance.setOption({ series: newData })
}
},
{ deep: true }
)
// 窗口大小变化时自动适配
const handleResize = () => {
chartInstance?.resize()
}
onMounted(() => {
initChart()
window.addEventListener('resize', handleResize)
})
onBeforeUnmount(() => {
// 销毁实例,防止内存泄漏
chartInstance?.dispose()
window.removeEventListener('resize', handleResize)
})
</script>
<style scoped>
.chart-container {
width: 100%;
height: 400px;
}
</style>
Vue 2的写法稍有不同,用this.$echarts或手动import都可以,原理是一样的。
React项目中使用
// Chart.jsx
import React, { useRef, useEffect } from 'react'
import * as echarts from 'echarts'
const Chart = ({ option }) => {
const chartRef = useRef(null)
const instanceRef = useRef(null)
useEffect(() => {
if (!chartRef.current) return
// 初始化
instanceRef.current = echarts.init(chartRef.current)
// 设置配置
instanceRef.current.setOption(option)
// 响应式
const handleResize = () => instanceRef.current?.resize()
window.addEventListener('resize', handleResize)
// 清理
return () => {
window.removeEventListener('resize', handleResize)
instanceRef.current?.dispose()
instanceRef.current = null
}
}, [option])
// option变化时更新
useEffect(() => {
if (instanceRef.current && option) {
instanceRef.current.setOption(option, true) // true表示不合并,完全替换
}
}, [option])
return <div ref={chartRef} style={{ width: '100%', height: '400px' }} />
}
export default Chart
使用方式:
<Chart option={{
title: { text: 'React + ECharts' },
tooltip: { trigger: 'axis' },
xAxis: { type: 'category', data: ['A', 'B', 'C', 'D'] },
yAxis: { type: 'value' },
series: [{ type: 'bar', data: [100, 200, 150, 80] }]
}} />
Angular项目中使用
// chart.component.ts
import { Component, OnInit, OnDestroy, ElementRef, ViewChild } from '@angular/core'
import * as echarts from 'echarts'
@Component({
selector: 'app-chart',
template: `<div #chartContainer style="width:100%;height:400px"></div>`
})
export class ChartComponent implements OnInit, OnDestroy {
@ViewChild('chartContainer') chartContainer!: ElementRef
private chart: echarts.ECharts | null = null
ngOnInit() {
this.chart = echarts.init(this.chartContainer.nativeElement)
this.chart.setOption({
title: { text: 'Angular + ECharts' },
tooltip: { trigger: 'axis' },
xAxis: { type: 'category', data: ['一月', '二月', '三月', '四月'] },
yAxis: { type: 'value' },
series: [{ type: 'line', data: [820, 932, 901, 934] }]
})
window.addEventListener('resize', this.handleResize)
}
private handleResize = () => {
this.chart?.resize()
}
ngOnDestroy() {
this.chart?.dispose()
window.removeEventListener('resize', this.handleResize)
}
}
常见配置场景
地图 + 散点图(电商分布可视化)
// 需要先加载地图数据
// 在HTML中先引入 echarts 和 世界地图 或 中国地图
// 这里用中国地图为例
fetch('https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json')
.then(res => res.json())
.then(geoJson => {
echarts.registerMap('china', geoJson)
const chart = echarts.init(document.getElementById('map-chart'))
chart.setOption({
tooltip: { trigger: 'item' },
visualMap: {
min: 0,
max: 10000,
left: 'left',
top: 'bottom',
text: ['高', '低'],
calculable: true,
inRange: { color: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'] }
},
series: [
{
name: '各省份订单量',
type: 'map',
map: 'china',
roam: true,
emphasis: { label: { show: true } },
data: [
{ name: '广东', value: 9500 },
{ name: '浙江', value: 8200 },
{ name: '江苏', value: 7800 },
{ name: '北京', value: 6500 },
{ name: '上海', value: 6200 },
{ name: '山东', value: 5100 },
{ name: '河南', value: 4200 },
{ name: '四川', value: 3800 },
{ name: '湖北', value: 3200 },
{ name: '福建', value: 2900 }
]
},
{
name: '主要城市',
type: 'effectScatter',
coordinateSystem: 'geo',
symbolSize: 10,
rippleEffect: { brushType: 'stroke', scale: 3 },
label: { show: true, position: 'right', formatter: '{b}' },
data: [
{ name: '北京', value: [116.407526, 39.90403, 6500] },
{ name: '上海', value: [121.473701, 31.230416, 6200] },
{ name: '广州', value: [113.264384, 23.129162, 5800] },
{ name: '深圳', value: [114.057561, 22.543099, 5500] },
{ name: '杭州', value: [120.15507, 30.274154, 4800] }
]
}
]
})
})
实时数据更新
// 模拟实时数据流
const chart = echarts.init(document.getElementById('realtime-chart'))
let data = []
let now = new Date()
let value = Math.random() * 1000
for (let i = 0; i < 100; i++) {
data.push({
name: now.toString(),
value: [
[now.getHours(), now.getMinutes(), now.getSeconds()].join(':'),
Math.round(value + Math.random() * 10 - 5)
]
})
now = new Date(+now - 1000)
}
data.reverse()
chart.setOption({
title: { text: '实时温度监控' },
tooltip: {
trigger: 'axis',
formatter: p => `${p[0].data[0]}<br/>温度: ${p[0].data[1]}°C`
},
xAxis: { type: 'category', boundaryGap: false, data: data.map(d => d.value[0]) },
yAxis: { type: 'value', scale: true, name: '温度(°C)' },
series: [{
type: 'line',
showSymbol: false,
smooth: true,
data: data.map(d => d.value[1]),
areaStyle: { opacity: 0.3 }
}]
})
// 定时更新
setInterval(() => {
value = value + Math.random() * 20 - 10
const now = new Date()
const timeStr = [now.getHours(), now.getMinutes(), now.getSeconds()].join(':')
// 移除最老的数据
data.shift()
// 添加新数据
data.push({
name: now.toString(),
value: [timeStr, Math.round(value)]
})
chart.setOption({
xAxis: { data: data.map(d => d.value[0]) },
series: [{ data: data.map(d => d.value[1]) }]
})
}, 1000)
大屏适配(1920×1080分辨率)
做数据大屏时,ECharts的适配很重要:
// 大屏适配方案
function initChart(domId) {
const chart = echarts.init(document.getElementById(domId))
// 获取大屏的实际宽高
const screenWidth = window.screen.width
const screenHeight = window.screen.height
// 设计稿基准尺寸(假设设计稿是1920×1080)
const designWidth = 1920
const designHeight = 1080
// 计算缩放比例
const scaleX = screenWidth / designWidth
const scaleY = screenHeight / designHeight
const scale = Math.min(scaleX, scaleY) // 保持比例不拉伸
// 监听窗口变化
window.addEventListener('resize', () => {
const newScaleX = window.screen.width / designWidth
const newScaleY = window.screen.height / designHeight
const newScale = Math.min(newScaleX, newScaleY)
// 通过CSS缩放整个容器
document.getElementById(domId).style.transform = `scale(${newScale / scale})`
scale = newScale
chart.resize()
})
return chart
}
常见问题解决方案
问题一:图表不显示 / 空白
这是新手最容易遇到的坑,原因几乎100%是容器高度为0。
// ❌ 错误:容器没有高度,默认是0
<div id="chart"></div>
// ✅ 正确:给容器指定高度
<style>
#chart { width: 100%; height: 400px; }
</style>
还有一种情况是容器一开始是隐藏状态(display: none),ECharts初始化时无法获取正确的尺寸,解决方法:
// 在容器变为可见之后再初始化,或者强制resize
chart.resize()
// Vue中用watch监听显示状态
watch(showFlag, (val) => {
if (val) {
nextTick(() => {
chart.resize()
})
}
})
问题二:resize失效 / 图表变形
// ❌ 错误写法:只resize不监听
window.addEventListener('resize', () => {
chart.resize()
})
// ✅ 正确写法:去抖处理,避免频繁触发
let resizeTimer = null
window.addEventListener('resize', () => {
clearTimeout(resizeTimer)
resizeTimer = setTimeout(() => {
chart.resize()
}, 200)
})
在Vue项目中,更规范的做法是在beforeUnmount中移除监听:
onMounted(() => {
window.addEventListener('resize', handleResize)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize)
})
问题三:TypeScript报类型错误
// ❌ 错误:没有类型声明
import * as echarts from 'echarts'
const chart = echarts.init(dom) // 报错
// ✅ 解决方案1:安装类型声明
npm install -D @types/echarts
// ✅ 解决方案2:在代码中指定类型
import * as echarts from 'echarts'
const chart: echarts.ECharts = echarts.init(dom)
// ✅ 解决方案3:如果用了自定义模块声明
// typings/echarts.d.ts
declare module 'echarts' {
export = echarts
}
问题四:数据更新后图表不刷新
// ❌ 错误:直接修改数据对象,ECharts不会感知
option.series[0].data.push(100)
chart.setOption(option) // 可能不生效
// ✅ 正确:用setOption传入增量配置
chart.setOption({
series: [{ data: newData }]
})
// ✅ 或者强制合并
chart.setOption(option, { notMerge: true }) // 完全替换,不合并
问题五:地图不显示 / 报错
// ❌ 错误:没有注册地图就直接用
chart.setOption({
series: [{ type: 'map', map: 'china' }]
})
// ✅ 正确:先注册地图
// 方式1:用官方CDN
<script src="https://cdn.jsdelivr.net/npm/echarts@5/map/js/china.js"></script>
// 方式2:动态加载GeoJSON
fetch('https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json')
.then(res => res.json())
.then(geoJson => {
echarts.registerMap('china', geoJson)
chart.setOption({ ... })
})
// 方式3:本地文件
import chinaMap from './map/china.json'
echarts.registerMap('china', chinaMap)
问题六:图表渲染性能差
当数据量大(比如上万条折线点)时,性能问题会很明显:
// ✅ 方案1:开启硬件加速
const chart = echarts.init(dom, null, {
renderer: 'canvas' // 强制使用Canvas渲染
})
// ✅ 方案2:大数据用dataZoom分段展示
chart.setOption({
dataZoom: [
{ type: 'inside', start: 0, end: 100 },
{ type: 'slider', start: 0, end: 100 }
]
})
// ✅ 方案3:关闭不必要的动画
chart.setOption({
animation: false, // 或 animationDuration: 300
// 对大数据量禁用逐点动画
series: [{
type: 'line',
animation: false
}]
})
// ✅ 方案4:用dataset代替series.data
chart.setOption({
dataset: {
source: [['product', '2015', '2016'], ['A', 120, 130], ['B', 200, 210]]
},
series: [{ type: 'bar' }, { type: 'bar' }]
})
问题七:在弹窗/Tab中图表显示异常
// ❌ 错误:弹窗打开前就初始化了,此时DOM尺寸是0
const chart = echarts.init(document.getElementById('modal-chart'))
// ✅ 正确:等弹窗可见后再初始化
const showModal = () => {
const modal = document.getElementById('modal')
modal.style.display = 'block'
// 下一帧再初始化,确保DOM已渲染
setTimeout(() => {
const chart = echarts.init(document.getElementById('modal-chart'))
chart.resize()
}, 100)
}
// ✅ 更好的做法:监听弹窗显示事件
modalEl.addEventListener('shown.bs.modal', () => {
chart.resize()
})
问题八:中文乱码
// ❌ 错误:HTML文件编码不对或字体缺失
// 文件头没有声明UTF-8
// ✅ 正确:确保HTML声明UTF-8
<meta charset="UTF-8">
// ✅ 在fontFamily中指定支持中文的字体
chart.setOption({
textStyle: {
fontFamily: 'Microsoft YaHei, SimHei, sans-serif'
},
// 或者在title中单独指定
title: {
textStyle: { fontFamily: 'Microsoft YaHei' }
}
})
问题九:图表点击事件不生效
// ❌ 错误:没有正确绑定事件
chart.on('click', (params) => {
console.log(params)
})
// ✅ 正确:确保有交互组件开启
chart.setOption({
series: [{
type: 'pie',
// 饼图默认就支持点击,但柱状图/折线图需要确认
itemStyle: { cursor: 'pointer' }
}]
})
chart.on('click', (params) => {
console.log(`点击了: ${params.name}`, params)
// params.componentType: 'series' | 'xAxis' | 'yAxis' | 'legend'
// params.seriesType: 'bar' | 'line' | 'pie' ...
// params.seriesIndex: 系列索引
// params.dataIndex: 数据索引
})
// ✅ 双击事件
chart.on('dblclick', (params) => {
console.log('双击', params)
})
问题十:导出图片后白屏
// ❌ 错误:直接导出,容器在屏幕外或尺寸为0
chart.getDataURL({ type: 'png' })
// ✅ 正确:确保容器有尺寸,或临时扩展
const originalWidth = chartDom.offsetWidth
const originalHeight = chartDom.offsetHeight
// 如果需要导出隐藏区域的图表
chartDom.style.width = '1920px'
chartDom.style.height = '1080px'
chart.resize()
const imgUrl = chart.getDataURL({
type: 'png',
pixelRatio: 2, // 高清导出
backgroundColor: '#fff'
})
// 导出后恢复
chartDom.style.width = originalWidth + 'px'
chartDom.style.height = originalHeight + 'px'
chart.resize()
版本选择和升级建议
| 版本 | 说明 | 建议 |
|---|---|---|
| 4.x | 较老版本,功能够用但性能不如5.x | 新项目不要选,老项目可暂不升级 |
| 5.0+ | 当前主流,性能大幅提升,支持更多图表类型 | 新项目首选 |
| 5.5.x | 最新稳定版 | 推荐,bug修复最多 |
升级时注意:
// 从4.x升级到5.x的兼容性处理
// 1. 移除deprecated API
// - xAxis.dataZoom (已移除,用独立dataZoom组件)
// - visualMap.inRange.color(5.x用inRange.color)
// 2. 配置项语法有变化
// 4.x: series[i].itemStyle.normal.color
// 5.x: series[i].itemStyle.color(去掉了normal/emphasis的外层)
// 3. 地图加载方式变化
// 4.x用echarts.registerMap,5.x同样支持,但官方推荐用GeoJSON动态加载
最佳实践总结
- 容器高度必须显式设置,不要依赖默认值
- 组件销毁时要dispose,防止内存泄漏,特别是在SPA应用中
- 响应式一定要处理,窗口resize时调用
chart.resize() - 大数据量用dataZoom,不要一次性渲染上万条数据
- 用TypeScript项目一定要装
@types/echarts - 地图功能按需加载,不要一次性引入所有地图
- CDN引用时锁死版本,避免意外升级破坏现有功能
- 弹窗/Tab中的图表要等DOM可见后再resize
- 频繁更新数据时避免全量setOption,用增量配置
- 导出高清图片时设置
pixelRatio: 2或更高
官方资源
- 官方文档:https://echarts.apache.org/zh/index.html
- API手册:https://echarts.apache.org/zh/api.html#echarts.init
- 配置项手册:https://echarts.apache.org/zh/option.html
- 示例库:https://echarts.apache.org/examples/zh/index.html
- GitHub:https://github.com/apache/echarts
好了,关于ECharts的下载、安装配置以及常见坑的解决方案,我就讲这么多。ECharts其实不难,大多数问题都是配置细节没注意导致的。只要把容器高度、resize、dispose这三个关键点记住了,90%的问题都不会遇到。如果你在实际项目里遇到了什么奇怪的问题,欢迎来评论区交流,大家一起排查。
