ECharts 高级功能 #

本章将介绍 ECharts 的高级功能,帮助你实现更复杂的数据可视化需求。

地图可视化 #

地图基础 #

javascript
// 引入中国地图数据
import 'echarts/map/js/china.js';

const option = {
  title: {
    text: '中国地图',
    left: 'center'
  },
  tooltip: {
    trigger: 'item'
  },
  visualMap: {
    min: 0,
    max: 100,
    left: 'left',
    top: 'bottom',
    text: ['高', '低'],
    calculable: true
  },
  series: [{
    name: '数据',
    type: 'map',
    map: 'china',
    roam: true,
    label: {
      show: true
    },
    data: [
      { name: '北京', value: 80 },
      { name: '上海', value: 90 },
      { name: '广东', value: 70 }
    ]
  }]
};

地图样式 #

javascript
series: [{
  type: 'map',
  map: 'china',
  
  // 地图区域样式
  itemStyle: {
    areaColor: '#f3f3f3',
    borderColor: '#999',
    borderWidth: 0.5
  },
  
  // 高亮样式
  emphasis: {
    itemStyle: {
      areaColor: '#e0e0e0',
      borderColor: '#666',
      borderWidth: 1
    },
    label: {
      show: true,
      color: '#333'
    }
  },
  
  // 选中样式
  select: {
    itemStyle: {
      areaColor: '#ccc'
    }
  },
  
  // 标签
  label: {
    show: false,
    color: '#333',
    fontSize: 10
  }
}]

散点地图 #

javascript
const option = {
  geo: {
    map: 'china',
    roam: true,
    label: { show: false },
    itemStyle: {
      areaColor: '#f3f3f3',
      borderColor: '#999'
    }
  },
  series: [{
    name: '城市',
    type: 'scatter',
    coordinateSystem: 'geo',
    data: [
      { name: '北京', value: [116.46, 39.92, 100] },
      { name: '上海', value: [121.48, 31.22, 200] },
      { name: '广州', value: [113.23, 23.16, 150] }
    ],
    symbolSize: function(val) {
      return val[2] / 10;
    },
    itemStyle: {
      color: '#5470c6'
    }
  }]
};

热力地图 #

javascript
const option = {
  geo: {
    map: 'china',
    roam: true
  },
  visualMap: {
    min: 0,
    max: 100,
    calculable: true,
    inRange: {
      color: ['#50a3ba', '#eac736', '#d94e5d']
    }
  },
  series: [{
    name: '热力',
    type: 'heatmap',
    coordinateSystem: 'geo',
    data: [
      [116.46, 39.92, 80],
      [121.48, 31.22, 90],
      [113.23, 23.16, 70]
    ]
  }]
};

迁徙图 #

javascript
const option = {
  geo: {
    map: 'china',
    roam: true
  },
  series: [{
    name: '迁徙',
    type: 'lines',
    coordinateSystem: 'geo',
    zlevel: 2,
    effect: {
      show: true,
      period: 6,
      trailLength: 0.7,
      color: '#fff',
      symbolSize: 3
    },
    lineStyle: {
      color: '#a6c84c',
      width: 1,
      curveness: 0.2
    },
    data: [
      {
        fromName: '北京',
        toName: '上海',
        coords: [[116.46, 39.92], [121.48, 31.22]]
      },
      {
        fromName: '北京',
        toName: '广州',
        coords: [[116.46, 39.92], [113.23, 23.16]]
      }
    ]
  }]
};

3D 图表 #

3D 柱状图 #

javascript
// 需要引入 echarts-gl
import 'echarts-gl';

const option = {
  title: {
    text: '3D 柱状图'
  },
  xAxis3D: {
    type: 'category',
    data: ['A', 'B', 'C', 'D']
  },
  yAxis3D: {
    type: 'category',
    data: ['X', 'Y', 'Z']
  },
  zAxis3D: {
    type: 'value'
  },
  grid3D: {
    boxWidth: 100,
    boxHeight: 50,
    boxDepth: 80,
    viewControl: {
      autoRotate: true
    }
  },
  series: [{
    type: 'bar3D',
    data: [
      ['A', 'X', 10],
      ['A', 'Y', 20],
      ['A', 'Z', 30],
      ['B', 'X', 15],
      ['B', 'Y', 25],
      ['B', 'Z', 35]
    ],
    shading: 'lambert',
    label: {
      show: true
    },
    itemStyle: {
      opacity: 0.8
    }
  }]
};

3D 散点图 #

javascript
const option = {
  xAxis3D: { type: 'value' },
  yAxis3D: { type: 'value' },
  zAxis3D: { type: 'value' },
  grid3D: {
    viewControl: {
      autoRotate: true
    }
  },
  series: [{
    type: 'scatter3D',
    data: [
      [10, 20, 30],
      [15, 25, 35],
      [20, 30, 40]
    ],
    symbolSize: 12,
    itemStyle: {
      color: '#5470c6',
      opacity: 0.8
    }
  }]
};

3D 曲面图 #

javascript
const option = {
  visualMap: {
    show: false,
    dimension: 2,
    min: -1,
    max: 1,
    inRange: {
      color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8']
    }
  },
  xAxis3D: { type: 'value' },
  yAxis3D: { type: 'value' },
  zAxis3D: { type: 'value' },
  grid3D: {
    viewControl: {
      autoRotate: true
    }
  },
  series: [{
    type: 'surface',
    wireframe: {
      show: false
    },
    shading: 'color',
    equation: {
      x: { step: 0.05 },
      y: { step: 0.05 },
      z: function(x, y) {
        return Math.sin(x) * Math.cos(y);
      }
    }
  }]
};

3D 地图 #

javascript
const option = {
  geo3D: {
    map: 'china',
    roam: true,
    itemStyle: {
      areaColor: '#5470c6',
      opacity: 0.8
    },
    emphasis: {
      itemStyle: {
        color: '#91cc75'
      }
    },
    light: {
      main: {
        intensity: 1.2,
        shadow: true
      },
      ambient: {
        intensity: 0.3
      }
    },
    viewControl: {
      autoRotate: true,
      distance: 100
    }
  }
};

大数据优化 #

增量渲染 #

javascript
// 分批添加数据
function appendDataInBatches(chart, data, batchSize = 1000) {
  let index = 0;
  
  function appendNextBatch() {
    const batch = data.slice(index, index + batchSize);
    
    chart.appendData({
      seriesIndex: 0,
      data: batch
    });
    
    index += batchSize;
    
    if (index < data.length) {
      requestAnimationFrame(appendNextBatch);
    }
  }
  
  appendNextBatch();
}

大数据模式 #

javascript
option = {
  series: [{
    type: 'line',
    data: largeData,
    
    // 开启大数据优化
    large: true,
    largeThreshold: 2000,
    
    // 简化样式
    symbol: 'none',
    sampling: 'lttb',  // 'lttb', 'average', 'max', 'min', 'sum'
    
    // 简化动画
    animation: false
  }]
};

数据采样 #

javascript
// LTTB 采样算法
option = {
  series: [{
    type: 'line',
    data: largeData,
    sampling: 'lttb'
  }]
};

// 自定义采样
function sampleData(data, maxPoints) {
  if (data.length <= maxPoints) return data;
  
  const step = Math.ceil(data.length / maxPoints);
  const sampled = [];
  
  for (let i = 0; i < data.length; i += step) {
    sampled.push(data[i]);
  }
  
  return sampled;
}

性能优化配置 #

javascript
option = {
  // 关闭动画
  animation: false,
  animationThreshold: 2000,
  
  // 关闭渐进渲染
  progressive: 0,
  progressiveThreshold: 3000,
  
  series: [{
    type: 'scatter',
    data: largeData,
    
    // 大数据模式
    large: true,
    largeThreshold: 2000,
    
    // 简化样式
    symbol: 'circle',
    symbolSize: 3,
    
    // 简化渲染
    itemStyle: {
      opacity: 0.6
    }
  }]
};

自定义系列 #

基础自定义系列 #

javascript
option = {
  series: [{
    type: 'custom',
    renderItem: function(params, api) {
      // 获取数据
      const value = api.value(0);
      const coord = api.coord([value, 0]);
      
      // 返回图形元素
      return {
        type: 'circle',
        shape: {
          cx: coord[0],
          cy: coord[1],
          r: 10
        },
        style: {
          fill: '#5470c6'
        }
      };
    },
    data: [10, 20, 30, 40, 50]
  }]
};

自定义柱状图 #

javascript
option = {
  xAxis: {
    type: 'category',
    data: ['A', 'B', 'C', 'D']
  },
  yAxis: { type: 'value' },
  series: [{
    type: 'custom',
    renderItem: function(params, api) {
      const categoryIndex = api.value(0);
      const value = api.value(1);
      
      const start = api.coord([categoryIndex, 0]);
      const end = api.coord([categoryIndex, value]);
      const width = api.size([1, 0])[0] * 0.6;
      
      return {
        type: 'rect',
        shape: {
          x: end[0] - width / 2,
          y: end[1],
          width: width,
          height: start[1] - end[1]
        },
        style: {
          fill: api.visual('color')
        }
      };
    },
    encode: {
      x: 0,
      y: 1
    },
    data: [
      ['A', 10],
      ['B', 20],
      ['C', 30],
      ['D', 40]
    ]
  }]
};

自定义动画 #

javascript
option = {
  series: [{
    type: 'custom',
    renderItem: function(params, api) {
      const point = api.coord([api.value(0), api.value(1)]);
      
      return {
        type: 'circle',
        shape: {
          cx: point[0],
          cy: point[1],
          r: 0
        },
        style: {
          fill: '#5470c6'
        },
        // 入场动画
        during: function(apiDuring) {
          apiDuring.setStyle('r', apiDuring.r * 10);
        },
        // 更新动画
        transition: ['shape'],
        enterFrom: { style: { opacity: 0 } }
      };
    },
    data: [[0, 10], [1, 20], [2, 30]]
  }]
};

多图表联动 #

connect 方法 #

javascript
// 创建多个图表
const chart1 = echarts.init(document.getElementById('chart1'));
const chart2 = echarts.init(document.getElementById('chart2'));

// 设置配置
chart1.setOption(option1);
chart2.setOption(option2);

// 联动
echarts.connect([chart1, chart2]);

group 联动 #

javascript
// 设置分组
const chart1 = echarts.init(document.getElementById('chart1'));
const chart2 = echarts.init(document.getElementById('chart2'));

chart1.group = 'group1';
chart2.group = 'group1';

echarts.connect('group1');

事件联动 #

javascript
// 通过事件实现联动
chart1.on('datazoom', function(params) {
  chart2.dispatchAction({
    type: 'dataZoom',
    start: params.start,
    end: params.end
  });
});

chart1.on('highlight', function(params) {
  chart2.dispatchAction({
    type: 'highlight',
    seriesIndex: params.seriesIndex,
    dataIndex: params.dataIndex
  });
});

动态数据更新 #

实时数据 #

javascript
// WebSocket 实时数据
const ws = new WebSocket('ws://example.com/data');

ws.onmessage = function(event) {
  const data = JSON.parse(event.data);
  
  chart.setOption({
    series: [{
      data: data
    }]
  });
};

// 轮询更新
setInterval(function() {
  fetch('/api/data')
    .then(response => response.json())
    .then(data => {
      chart.setOption({
        series: [{ data: data }]
      });
    });
}, 3000);

数据滚动 #

javascript
const data = [];
const maxPoints = 100;

setInterval(function() {
  // 添加新数据
  data.push(Math.random() * 100);
  
  // 保持最大数量
  if (data.length > maxPoints) {
    data.shift();
  }
  
  chart.setOption({
    series: [{
      data: data
    }]
  });
}, 1000);

动态添加系列 #

javascript
function addSeries(chart, name, data) {
  const option = chart.getOption();
  
  option.series.push({
    name: name,
    type: 'line',
    data: data
  });
  
  option.legend[0].data.push(name);
  
  chart.setOption(option);
}

导出功能 #

导出图片 #

javascript
// 获取图片数据 URL
const imageDataURL = chart.getDataURL({
  type: 'png',  // 'png', 'jpeg', 'svg'
  pixelRatio: 2,
  backgroundColor: '#fff'
});

// 下载图片
const link = document.createElement('a');
link.download = 'chart.png';
link.href = imageDataURL;
link.click();

导出 SVG #

javascript
// 需要使用 SVG 渲染器
const chart = echarts.init(dom, null, {
  renderer: 'svg'
});

// 获取 SVG
const svgData = chart.getDataURL({
  type: 'svg'
});

导出数据 #

javascript
// 获取图表数据
const option = chart.getOption();
const data = option.series[0].data;

// 导出为 JSON
const jsonData = JSON.stringify(data, null, 2);
const blob = new Blob([jsonData], { type: 'application/json' });
const url = URL.createObjectURL(blob);

const link = document.createElement('a');
link.download = 'data.json';
link.href = url;
link.click();

最佳实践 #

1. 性能优化清单 #

text
□ 关闭不必要的动画
□ 使用大数据模式
□ 合理设置采样
□ 分批加载数据
□ 使用增量渲染
□ 优化数据结构
□ 减少重绘次数

2. 内存管理 #

javascript
// 及时销毁不需要的图表
function destroyChart(chart) {
  if (chart) {
    chart.clear();
    chart.dispose();
  }
}

// 页面卸载时清理
window.addEventListener('beforeunload', function() {
  destroyChart(chart);
});

3. 错误处理 #

javascript
try {
  chart.setOption(option);
} catch (error) {
  console.error('ECharts 配置错误:', error);
  // 显示错误提示
  chart.showLoading({
    text: '图表加载失败',
    color: '#ee6666'
  });
}

总结 #

恭喜你完成了 ECharts 完全指南的学习!现在你已经掌握了:

  • ECharts 的基础概念和安装配置
  • 各种常见图表的实现方法
  • 丰富的交互功能
  • 主题和样式定制
  • 地图可视化和 3D 图表
  • 大数据优化和性能调优
  • 自定义系列和高级功能

继续实践和探索,你将成为数据可视化专家!

资源推荐 #

最后更新:2026-03-28