短松江月

Echarts 基本使用教程

· simons ·
Echarts JavaScript 图表 数据可视化 教程

示例

🎯 为什么选择 Echarts?

Apache ECharts 是一个基于 JavaScript 的开源可视化库,由百度团队贡献并捐赠给 Apache 基金会。它具有以下核心优势:

  • 📈 图表类型丰富:覆盖 30+ 常见图表类型
  • ⚡ 高性能渲染:Canvas / SVG 双引擎,支持大数据量
  • 🎨 高度可定制:灵活的配置项系统
  • 📱 响应式设计:完美适配移动端与桌面端
  • 🌍 活跃的社区:持续更新,中文文档完善

🚀 快速上手:5分钟创建第一个图表

1. 环境准备

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ECharts 入门</title>
    <!-- 引入 ECharts -->
    <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
</head>
<body>
    <!-- 准备一个具有宽高的 DOM -->
    <div id="main" style="width: 600px;height:400px;"></div>
    
    <script type="text/javascript">
        // 你的代码将在这里
    </script>
</body>
</html>

2. 基础三步曲

// 步骤1:初始化实例
const chartDom = document.getElementById('main');
const myChart = echarts.init(chartDom);

// 步骤2:准备配置项
const option = {
    title: {
        text: '月度销售额',
        left: 'center'
    },
    tooltip: {
        trigger: 'item'
    },
    xAxis: {
        type: 'category',
        data: ['1月', '2月', '3月', '4月', '5月', '6月']
    },
    yAxis: {
        type: 'value'
    },
    series: [{
        name: '销售额',
        type: 'bar',
        data: [820, 932, 901, 934, 1290, 1330],
        itemStyle: {
            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                { offset: 0, color: '#83bff6' },
                { offset: 0.5, color: '#188df0' },
                { offset: 1, color: '#188df0' }
            ])
        }
    }]
};

// 步骤3:渲染图表
myChart.setOption(option);

📊 实战图表类型详解

1. 组合图表:折线+柱状图

const option = {
    tooltip: {
        trigger: 'axis',
        axisPointer: {
            type: 'cross'
        }
    },
    legend: {
        data: ['蒸发量', '降水量', '平均温度']
    },
    xAxis: [{
        type: 'category',
        data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月']
    }],
    yAxis: [{
        type: 'value',
        name: '水量',
        min: 0,
        max: 250,
        position: 'left'
    }, {
        type: 'value',
        name: '温度',
        min: 0,
        max: 25,
        position: 'right'
    }],
    series: [{
        name: '蒸发量',
        type: 'bar',
        yAxisIndex: 0,
        data: [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6]
    }, {
        name: '降水量',
        type: 'bar',
        yAxisIndex: 0,
        data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6]
    }, {
        name: '平均温度',
        type: 'line',
        yAxisIndex: 1,
        data: [2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3],
        smooth: true
    }]
};

2. 交互式饼图

const option = {
    title: {
        text: '用户访问来源',
        subtext: '纯属虚构',
        left: 'center'
    },
    tooltip: {
        trigger: 'item',
        formatter: '{a} <br/>{b}: {c} ({d}%)'
    },
    legend: {
        orient: 'vertical',
        left: 'left',
        top: 'middle'
    },
    series: [{
        name: '访问来源',
        type: 'pie',
        radius: ['40%', '70%'],  // 环形图
        avoidLabelOverlap: false,
        itemStyle: {
            borderRadius: 10,
            borderColor: '#fff',
            borderWidth: 2
        },
        label: {
            show: false,
            position: 'center'
        },
        emphasis: {
            label: {
                show: true,
                fontSize: 20,
                fontWeight: 'bold'
            },
            scale: true,  // 鼠标悬停放大效果
            scaleSize: 10
        },
        labelLine: {
            show: false
        },
        data: [
            { value: 1048, name: '搜索引擎' },
            { value: 735, name: '直接访问' },
            { value: 580, name: '邮件营销' },
            { value: 484, name: '联盟广告' },
            { value: 300, name: '视频广告' }
        ]
    }]
};

3. 动态数据仪表盘

function updateChart() {
    const now = new Date();
    const data = [];
    
    for (let i = 0; i < 24; i++) {
        data.push(Math.round(Math.random() * 100));
    }
    
    option.series[0].data = data;
    option.title.subtext = `更新时间: ${now.toLocaleTimeString()}`;
    myChart.setOption(option);
}

// 每5秒更新一次数据
setInterval(updateChart, 5000);

⚡ 进阶技巧与最佳实践

1. 响应式设计实现

// 响应式配置函数
function getResponsiveOption() {
    const isMobile = window.innerWidth < 768;
    
    return {
        grid: {
            left: isMobile ? '5%' : '10%',
            right: isMobile ? '5%' : '10%',
            top: isMobile ? '15%' : '10%',
            bottom: isMobile ? '15%' : '10%'
        },
        legend: {
            orient: isMobile ? 'horizontal' : 'vertical',
            top: isMobile ? 'bottom' : 'middle',
            left: isMobile ? 'center' : 'right'
        },
        title: {
            textStyle: {
                fontSize: isMobile ? 14 : 18
            }
        }
    };
}

// 监听窗口变化
window.addEventListener('resize', () => {
    myChart.resize();
    const responsiveOption = getResponsiveOption();
    myChart.setOption(responsiveOption);
});

2. 数据加载与状态管理

class ChartManager {
    constructor(containerId) {
        this.chart = echarts.init(document.getElementById(containerId));
        this.isLoading = false;
        this.dataCache = new Map();
    }
    
    async loadData(endpoint) {
        if (this.dataCache.has(endpoint)) {
            return this.dataCache.get(endpoint);
        }
        
        this.showLoading();
        try {
            const response = await fetch(endpoint);
            const data = await response.json();
            this.dataCache.set(endpoint, data);
            return data;
        } catch (error) {
            console.error('数据加载失败:', error);
            throw error;
        } finally {
            this.hideLoading();
        }
    }
    
    showLoading() {
        if (!this.isLoading) {
            this.chart.showLoading('default', {
                text: '数据加载中...',
                color: '#c23531',
                textColor: '#000',
                maskColor: 'rgba(255, 255, 255, 0.8)'
            });
            this.isLoading = true;
        }
    }
    
    hideLoading() {
        if (this.isLoading) {
            this.chart.hideLoading();
            this.isLoading = false;
        }
    }
}

3. 性能优化策略

// 大数据优化配置
const largeDataOption = {
    dataset: {
        source: largeData // 假设有10万条数据
    },
    series: [{
        type: 'scatter',
        progressive: 2000, // 增量渲染阈值
        progressiveThreshold: 10000, // 开启增量渲染的阈值
        dimensions: ['x', 'y', 'value'],
        encode: {
            x: 'x',
            y: 'y',
            tooltip: 'value'
        },
        large: true, // 开启大数据模式
        itemStyle: {
            opacity: 0.8
        }
    }],
    animation: false, // 大数据关闭动画
    tooltip: {
        trigger: 'item'
    }
};

// 内存管理
function clearChartResources(chart) {
    chart.clear(); // 清除实例
    chart.dispose(); // 释放内存
}

🛠️ 实战项目结构示例

src/
├── charts/
│   ├── BaseChart.js       # 基础图表类
│   ├── LineChart.js       # 折线图组件
│   ├── BarChart.js        # 柱状图组件
│   └── PieChart.js        # 饼图组件
├── utils/
│   ├── chartHelper.js     # 图表工具函数
│   ├── dataProcessor.js   # 数据处理
│   └── responsive.js      # 响应式配置
├── themes/
│   ├── lightTheme.js      # 浅色主题
│   └── darkTheme.js       # 深色主题
└── services/
    └── chartService.js    # 图表服务

模块化组件示例

// BaseChart.js
export class BaseChart {
    constructor(container, theme = 'light') {
        this.container = container;
        this.chart = echarts.init(container, theme);
        this.setupEvents();
    }
    
    setupEvents() {
        // 窗口大小变化时重绘
        window.addEventListener('resize', this.debounce(() => {
            this.chart.resize();
        }, 300));
        
        // 图表点击事件
        this.chart.on('click', (params) => {
            this.handleClick(params);
        });
    }
    
    async render(data) {
        const option = this.buildOption(data);
        this.chart.setOption(option);
        return this.chart;
    }
    
    destroy() {
        this.chart.dispose();
    }
}

// LineChart.js
export class LineChart extends BaseChart {
    buildOption(data) {
        return {
            title: { /* ... */ },
            tooltip: { /* ... */ },
            xAxis: { /* ... */ },
            yAxis: { /* ... */ },
            series: [{
                type: 'line',
                data: data,
                smooth: true,
                lineStyle: {
                    width: 3,
                    shadowColor: 'rgba(0,0,0,0.3)',
                    shadowBlur: 10,
                    shadowOffsetY: 8
                }
            }]
        };
    }
}

🎨 主题定制与设计规范

// 自定义主题
const customTheme = {
    color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de'],
    backgroundColor: 'rgba(255, 255, 255, 0)',
    textStyle: {
        fontFamily: 'Arial, sans-serif'
    },
    title: {
        textStyle: {
            color: '#333',
            fontWeight: 'bold'
        }
    },
    tooltip: {
        backgroundColor: 'rgba(0,0,0,0.7)',
        borderColor: '#333'
    },
    // 注册主题
    category10: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de']
};

// 注册自定义主题
echarts.registerTheme('custom', customTheme);

📚 学习资源推荐

官方资源

  • 📖 ECharts 官方文档- 最全面的学习资料
  • 🎯 配置项手册- API 查询字典
  • ✨ 示例库- 300+ 示例代码

社区资源

  • GitHub Issues- 问题反馈与解决方案
  • Awesome ECharts- 精选资源合集
  • ECharts Gallery- 社区作品展示

工具推荐

  • ECharts Online Editor- 在线编辑调试
  • ECharts Theme Builder- 主题构建工具