ECharts 是一个使用 JavaScript 实现的开源可视化库,涵盖各行业图表,满足各种需求。
ECharts 遵循 Apache-2.0 开源协议,免费商用。
ECharts 兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等)及兼容多种设备,可随时随地任性展示。
目录
ECharts简介
ECharts 安装
ECharts 配置语法
ECharts 饼图
ECharts 样式设置
ECharts 异步加载数据
ECharts 数据集(dataset)
ECharts 交互组件
ECharts 响应式
ECharts 数据的视觉映射
ECharts 事件处理
ECharts 旭日图
ECharts简介
ECharts 包含了以下特性:
丰富的可视化类型: 提供了常规的折线图、柱状图、散点图、饼图、K线图,用于统计的盒形图,用于地理数据可视化的地图、热力图、线图,用于关系数据可视化的关系图、treemap、旭日图,多维数据可视化的平行坐标,还有用于 BI 的漏斗图,仪表盘,并且支持图与图之间的混搭。
多种数据格式无需转换直接使用: 内置的 dataset 属性(4.0+)支持直接传入包括二维表,key-value 等多种格式的数据源,此外还支持输入 TypedArray 格式的数据。
千万数据的前端展现: 通过增量渲染技术(4.0+),配合各种细致的优化,ECharts 能够展现千万级的数据量。
移动端优化: 针对移动端交互做了细致的优化,例如移动端小屏上适于用手指在坐标系中进行缩放、平移。 PC 端也可以用鼠标在图中进行缩放(用鼠标滚轮)、平移等。
多渲染方案,跨平台使用: 支持以 Canvas、SVG(4.0+)、VML 的形式渲染图表。
深度的交互式数据探索: 提供了 图例、视觉映射、数据区域缩放、tooltip、数据刷选等开箱即用的交互组件,可以对数据进行多维度数据筛取、视图缩放、展示细节等交互操作。
多维数据的支持以及丰富的视觉编码手段: 对于传统的散点图等,传入的数据也可以是多个维度的。
动态数据: 数据的改变驱动图表展现的改变。
绚丽的特效: 针对线数据,点数据等地理数据的可视化提供了吸引眼球的特效。
通过 GL 实现更多更强大绚丽的三维可视化: 在 VR,大屏场景里实现三维的可视化效果。
- 无障碍访问(4.0+): 支持自动根据图表配置项智能生成描述,使得盲人可以在朗读设备的帮助下了解图表内容,让图表可以被更多人群访问!
示例
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>孙叫兽演示 ECharts 实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {title: {text: '孙叫兽演示 ECharts 实例'},tooltip: {},legend: {data:['销量']},xAxis: {data: ["孙叫兽","1_bit","敖丙","三太子","哪吒","games"]},yAxis: {},series: [{name: '销量',type: 'bar',data: [5, 20, 36, 10, 10, 20]}]};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script>
</body>
</html>
效果图:
ECharts 安装
直接下载 echarts.min.js 并用 <script> 标签引入。
生产环境echarts.min.js
开发环境下可以使用源代码版本 echarts.js 并用 <script> 标签引入,源码版本包含了常见的错误提示和警告。
开发版echarts.js
ECharts 的官网上直接下载更多丰富的版本,包含了不同主题跟语言,下载地址:https://www.echartsjs.com/zh/download.html。
NPM 方法
安装完成后 ECharts 和 zrender 会放在 node_modules 目录下,我们可以直接在项目代码中使用 require('echarts') 来使用。
var echarts = require('echarts');// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 绘制图表
myChart.setOption({title: {text: 'ECharts 入门示例'},tooltip: {},xAxis: {data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']},yAxis: {},series: [{name: '销量',type: 'bar',data: [5, 20, 36, 10, 10, 20]}]
});
ECharts 配置语法
第一步:创建 HTML 页面
创建一个 HTML 页面,引入 echarts.min.js:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><!-- 引入 ECharts 文件 --><script src="echarts.min.js"></script>
</head>
</html>
第二步: 为 ECharts 准备一个具备高宽的 DOM 容器
实例中 id 为 main 的 div 用于包含 ECharts 绘制的图表:
<body><!-- 为 ECharts 准备一个具备大小(宽高)的 DOM --><div id="main" style="width: 600px;height:400px;"></div>
</body>
第三步: 设置配置信息
ECharts 库使用 json 格式来配置。
echarts.init(document.getElementById('main')).setOption(option);
这里 option 表示使用 json 数据格式的配置来绘制图表。步骤如下:
标题
为图表配置标题:
title: {text: '孙叫兽演示 ECharts 实例'
}
提示信息
配置提示信息:
tooltip: {},
图例组件
图例组件展现了不同系列的标记(symbol),颜色和名字。可以通过点击图例控制哪些系列不显示。
legend: {data: [{name: '系列1',// 强制设置图形为圆。icon: 'circle',// 设置文本为红色textStyle: {color: 'red'}}]
}
X 轴
配置要在 X 轴显示的项:
xAxis: {data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
}
Y 轴
配置要在 Y 轴显示的项。
yAxis: {}
系列列表
每个系列通过 type 决定自己的图表类型:
series: [{name: '销量', // 系列名称type: 'bar', // 系列图表类型data: [5, 20, 36, 10, 10, 20] // 系列中的数据内容
}]
每个系列通过 type 决定自己的图表类型:
- type: 'bar':柱状/条形图
- type: 'line':折线/面积图
- type: 'pie':饼图
- type: 'scatter':散点(气泡)图
- type: 'effectScatter':带有涟漪特效动画的散点(气泡)
- type: 'radar':雷达图
- type: 'tree':树型图
- type: 'treemap':树型图
- type: 'sunburst':旭日图
- type: 'boxplot':箱形图
- type: 'candlestick':K线图
- type: 'heatmap':热力图
- type: 'map':地图
- type: 'parallel':平行坐标系的系列
- type: 'lines':线图
- type: 'graph':关系图
- type: 'sankey':桑基图
- type: 'funnel':漏斗图
- type: 'gauge':仪表盘
- type: 'pictorialBar':象形柱图
- type: 'themeRiver':主题河流
- type: 'custom':自定义系列
配置项总结
theme = {// 全图默认背景// backgroundColor: 'rgba(0,0,0,0)',// 默认色板color: ['#ff7f50','#87cefa','#da70d6','#32cd32','#6495ed','#ff69b4','#ba55d3','#cd5c5c','#ffa500','#40e0d0','#1e90ff','#ff6347','#7b68ee','#00fa9a','#ffd700','#6699FF','#ff6666','#3cb371','#b8860b','#30e0e0'],// 图表标题title: {x: 'left', // 水平安放位置,默认为左对齐,可选为:// 'center' ¦ 'left' ¦ 'right'// ¦ {number}(x坐标,单位px)y: 'top', // 垂直安放位置,默认为全图顶端,可选为:// 'top' ¦ 'bottom' ¦ 'center'// ¦ {number}(y坐标,单位px)//textAlign: null // 水平对齐方式,默认根据x设置自动调整backgroundColor: 'rgba(0,0,0,0)',borderColor: '#ccc', // 标题边框颜色borderWidth: 0, // 标题边框线宽,单位px,默认为0(无边框)padding: 5, // 标题内边距,单位px,默认各方向内边距为5,// 接受数组分别设定上右下左边距,同cssitemGap: 10, // 主副标题纵向间隔,单位px,默认为10,textStyle: {fontSize: 18,fontWeight: 'bolder',color: '#333' // 主标题文字颜色},subtextStyle: {color: '#aaa' // 副标题文字颜色}},// 图例legend: {orient: 'horizontal', // 布局方式,默认为水平布局,可选为:// 'horizontal' ¦ 'vertical'x: 'center', // 水平安放位置,默认为全图居中,可选为:// 'center' ¦ 'left' ¦ 'right'// ¦ {number}(x坐标,单位px)y: 'top', // 垂直安放位置,默认为全图顶端,可选为:// 'top' ¦ 'bottom' ¦ 'center'// ¦ {number}(y坐标,单位px)backgroundColor: 'rgba(0,0,0,0)',borderColor: '#ccc', // 图例边框颜色borderWidth: 0, // 图例边框线宽,单位px,默认为0(无边框)padding: 5, // 图例内边距,单位px,默认各方向内边距为5,// 接受数组分别设定上右下左边距,同cssitemGap: 10, // 各个item之间的间隔,单位px,默认为10,// 横向布局时为水平间隔,纵向布局时为纵向间隔itemWidth: 20, // 图例图形宽度itemHeight: 14, // 图例图形高度textStyle: {color: '#333' // 图例文字颜色}},// 值域dataRange: {orient: 'vertical', // 布局方式,默认为垂直布局,可选为:// 'horizontal' ¦ 'vertical'x: 'left', // 水平安放位置,默认为全图左对齐,可选为:// 'center' ¦ 'left' ¦ 'right'// ¦ {number}(x坐标,单位px)y: 'bottom', // 垂直安放位置,默认为全图底部,可选为:// 'top' ¦ 'bottom' ¦ 'center'// ¦ {number}(y坐标,单位px)backgroundColor: 'rgba(0,0,0,0)',borderColor: '#ccc', // 值域边框颜色borderWidth: 0, // 值域边框线宽,单位px,默认为0(无边框)padding: 5, // 值域内边距,单位px,默认各方向内边距为5,// 接受数组分别设定上右下左边距,同cssitemGap: 10, // 各个item之间的间隔,单位px,默认为10,// 横向布局时为水平间隔,纵向布局时为纵向间隔itemWidth: 20, // 值域图形宽度,线性渐变水平布局宽度为该值 * 10itemHeight: 14, // 值域图形高度,线性渐变垂直布局高度为该值 * 10splitNumber: 5, // 分割段数,默认为5,为0时为线性渐变color:['#1e90ff','#f0ffff'],//颜色 //text:['高','低'], // 文本,默认为数值文本textStyle: {color: '#333' // 值域文字颜色}},toolbox: {orient: 'horizontal', // 布局方式,默认为水平布局,可选为:// 'horizontal' ¦ 'vertical'x: 'right', // 水平安放位置,默认为全图右对齐,可选为:// 'center' ¦ 'left' ¦ 'right'// ¦ {number}(x坐标,单位px)y: 'top', // 垂直安放位置,默认为全图顶端,可选为:// 'top' ¦ 'bottom' ¦ 'center'// ¦ {number}(y坐标,单位px)color : ['#1e90ff','#22bb22','#4b0082','#d2691e'],backgroundColor: 'rgba(0,0,0,0)', // 工具箱背景颜色borderColor: '#ccc', // 工具箱边框颜色borderWidth: 0, // 工具箱边框线宽,单位px,默认为0(无边框)padding: 5, // 工具箱内边距,单位px,默认各方向内边距为5,// 接受数组分别设定上右下左边距,同cssitemGap: 10, // 各个item之间的间隔,单位px,默认为10,// 横向布局时为水平间隔,纵向布局时为纵向间隔itemSize: 16, // 工具箱图形宽度featureImageIcon : {}, // 自定义图片iconfeatureTitle : {mark : '辅助线开关',markUndo : '删除辅助线',markClear : '清空辅助线',dataZoom : '区域缩放',dataZoomReset : '区域缩放后退',dataView : '数据视图',lineChart : '折线图切换',barChart : '柱形图切换',restore : '还原',saveAsImage : '保存为图片'}},// 提示框tooltip: {trigger: 'item', // 触发类型,默认数据触发,见下图,可选为:'item' ¦ 'axis'showDelay: 20, // 显示延迟,添加显示延迟可以避免频繁切换,单位mshideDelay: 100, // 隐藏延迟,单位mstransitionDuration : 0.4, // 动画变换时间,单位sbackgroundColor: 'rgba(0,0,0,0.7)', // 提示背景颜色,默认为透明度为0.7的黑色borderColor: '#333', // 提示边框颜色borderRadius: 4, // 提示边框圆角,单位px,默认为4borderWidth: 0, // 提示边框线宽,单位px,默认为0(无边框)padding: 5, // 提示内边距,单位px,默认各方向内边距为5,// 接受数组分别设定上右下左边距,同cssaxisPointer : { // 坐标轴指示器,坐标轴触发有效type : 'line', // 默认为直线,可选为:'line' | 'shadow'lineStyle : { // 直线指示器样式设置color: '#48b',width: 2,type: 'solid'},shadowStyle : { // 阴影指示器样式设置width: 'auto', // 阴影大小color: 'rgba(150,150,150,0.3)' // 阴影颜色}},textStyle: {color: '#fff'}},// 区域缩放控制器dataZoom: {orient: 'horizontal', // 布局方式,默认为水平布局,可选为:// 'horizontal' ¦ 'vertical'// x: {number}, // 水平安放位置,默认为根据grid参数适配,可选为:// {number}(x坐标,单位px)// y: {number}, // 垂直安放位置,默认为根据grid参数适配,可选为:// {number}(y坐标,单位px)// width: {number}, // 指定宽度,横向布局时默认为根据grid参数适配// height: {number}, // 指定高度,纵向布局时默认为根据grid参数适配backgroundColor: 'rgba(0,0,0,0)', // 背景颜色dataBackgroundColor: '#eee', // 数据背景颜色fillerColor: 'rgba(144,197,237,0.2)', // 填充颜色handleColor: 'rgba(70,130,180,0.8)' // 手柄颜色},// 网格grid: {x: 80,y: 60,x2: 80,y2: 60,// width: {totalWidth} - x - x2,// height: {totalHeight} - y - y2,backgroundColor: 'rgba(0,0,0,0)',borderWidth: 1,borderColor: '#ccc'},// 类目轴categoryAxis: {position: 'bottom', // 位置nameLocation: 'end', // 坐标轴名字位置,支持'start' | 'end'boundaryGap: true, // 类目起始和结束两端空白策略axisLine: { // 坐标轴线show: true, // 默认显示,属性show控制显示与否lineStyle: { // 属性lineStyle控制线条样式color: '#48b',width: 2,type: 'solid'}},axisTick: { // 坐标轴小标记show: true, // 属性show控制显示与否,默认不显示interval: 'auto',// onGap: null,inside : false, // 控制小标记是否在grid里 length :5, // 属性length控制线长lineStyle: { // 属性lineStyle控制线条样式color: '#333',width: 1}},axisLabel: { // 坐标轴文本标签,详见axis.axisLabelshow: true,interval: 'auto',rotate: 0,margin: 8,// formatter: null,textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLEcolor: '#333'}},splitLine: { // 分隔线show: true, // 默认显示,属性show控制显示与否// onGap: null,lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式color: ['#ccc'],width: 1,type: 'solid'}},splitArea: { // 分隔区域show: false, // 默认不显示,属性show控制显示与否// onGap: null,areaStyle: { // 属性areaStyle(详见areaStyle)控制区域样式color: ['rgba(250,250,250,0.3)','rgba(200,200,200,0.3)']}}},// 数值型坐标轴默认参数valueAxis: {position: 'left', // 位置nameLocation: 'end', // 坐标轴名字位置,支持'start' | 'end'nameTextStyle: {}, // 坐标轴文字样式,默认取全局样式boundaryGap: [0, 0], // 数值起始和结束两端空白策略splitNumber: 5, // 分割段数,默认为5axisLine: { // 坐标轴线show: true, // 默认显示,属性show控制显示与否lineStyle: { // 属性lineStyle控制线条样式color: '#48b',width: 2,type: 'solid'}},axisTick: { // 坐标轴小标记show: false, // 属性show控制显示与否,默认不显示inside : false, // 控制小标记是否在grid里 length :5, // 属性length控制线长lineStyle: { // 属性lineStyle控制线条样式color: '#333',width: 1}},axisLabel: { // 坐标轴文本标签,详见axis.axisLabelshow: true,rotate: 0,margin: 8,// formatter: null,textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLEcolor: '#333'}},splitLine: { // 分隔线show: true, // 默认显示,属性show控制显示与否lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式color: ['#ccc'],width: 1,type: 'solid'}},splitArea: { // 分隔区域show: false, // 默认不显示,属性show控制显示与否areaStyle: { // 属性areaStyle(详见areaStyle)控制区域样式color: ['rgba(250,250,250,0.3)','rgba(200,200,200,0.3)']}}},polar : {center : ['50%', '50%'], // 默认全局居中radius : '75%',startAngle : 90,splitNumber : 5,name : {show: true,textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLEcolor: '#333'}},axisLine: { // 坐标轴线show: true, // 默认显示,属性show控制显示与否lineStyle: { // 属性lineStyle控制线条样式color: '#ccc',width: 1,type: 'solid'}},axisLabel: { // 坐标轴文本标签,详见axis.axisLabelshow: false,textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLEcolor: '#333'}},splitArea : {show : true,areaStyle : {color: ['rgba(250,250,250,0.3)','rgba(200,200,200,0.3)']}},splitLine : {show : true,lineStyle : {width : 1,color : '#ccc'}}},// 柱形图默认参数bar: {barMinHeight: 0, // 最小高度改为0// barWidth: null, // 默认自适应barGap: '30%', // 柱间距离,默认为柱形宽度的30%,可设固定值barCategoryGap : '20%', // 类目间柱形距离,默认为类目间距的20%,可设固定值itemStyle: {normal: {// color: '各异',barBorderColor: '#fff', // 柱条边线barBorderRadius: 0, // 柱条边线圆角,单位px,默认为0barBorderWidth: 1, // 柱条边线线宽,单位px,默认为1label: {show: false// position: 默认自适应,水平布局为'top',垂直布局为'right',可选为// 'inside'|'left'|'right'|'top'|'bottom'// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE}},emphasis: {// color: '各异',barBorderColor: 'rgba(0,0,0,0)', // 柱条边线barBorderRadius: 0, // 柱条边线圆角,单位px,默认为0barBorderWidth: 1, // 柱条边线线宽,单位px,默认为1label: {show: false// position: 默认自适应,水平布局为'top',垂直布局为'right',可选为// 'inside'|'left'|'right'|'top'|'bottom'// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE}}}},// 折线图默认参数line: {itemStyle: {normal: {// color: 各异,label: {show: false// position: 默认自适应,水平布局为'top',垂直布局为'right',可选为// 'inside'|'left'|'right'|'top'|'bottom'// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE},lineStyle: {width: 2,type: 'solid',shadowColor : 'rgba(0,0,0,0)', //默认透明shadowBlur: 5,shadowOffsetX: 3,shadowOffsetY: 3}},emphasis: {// color: 各异,label: {show: false// position: 默认自适应,水平布局为'top',垂直布局为'right',可选为// 'inside'|'left'|'right'|'top'|'bottom'// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE}}},//smooth : false,//symbol: null, // 拐点图形类型symbolSize: 2, // 拐点图形大小//symbolRotate : null, // 拐点图形旋转控制showAllSymbol: false // 标志图形默认只有主轴显示(随主轴标签间隔隐藏策略)},// K线图默认参数k: {// barWidth : null // 默认自适应// barMaxWidth : null // 默认自适应 itemStyle: {normal: {color: '#fff', // 阳线填充颜色color0: '#00aa11', // 阴线填充颜色lineStyle: {width: 1,color: '#ff3200', // 阳线边框颜色color0: '#00aa11' // 阴线边框颜色}},emphasis: {// color: 各异,// color0: 各异}}},// 散点图默认参数scatter: {//symbol: null, // 图形类型symbolSize: 4, // 图形大小,半宽(半径)参数,当图形为方向或菱形则总宽度为symbolSize * 2//symbolRotate : null, // 图形旋转控制large: false, // 大规模散点图largeThreshold: 2000,// 大规模阀值,large为true且数据量>largeThreshold才启用大规模模式itemStyle: {normal: {// color: 各异,label: {show: false// position: 默认自适应,水平布局为'top',垂直布局为'right',可选为// 'inside'|'left'|'right'|'top'|'bottom'// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE}},emphasis: {// color: '各异'label: {show: false// position: 默认自适应,水平布局为'top',垂直布局为'right',可选为// 'inside'|'left'|'right'|'top'|'bottom'// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE}}}},// 雷达图默认参数radar : {itemStyle: {normal: {// color: 各异,label: {show: false},lineStyle: {width: 2,type: 'solid'}},emphasis: {// color: 各异,label: {show: false}}},//symbol: null, // 拐点图形类型symbolSize: 2 // 可计算特性参数,空数据拖拽提示图形大小//symbolRotate : null, // 图形旋转控制},// 饼图默认参数pie: {center : ['50%', '50%'], // 默认全局居中radius : [0, '75%'],clockWise : false, // 默认逆时针startAngle: 90,minAngle: 0, // 最小角度改为0selectedOffset: 10, // 选中是扇区偏移量itemStyle: {normal: {// color: 各异,borderColor: '#fff',borderWidth: 1,label: {show: true,position: 'outer'// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE},labelLine: {show: true,length: 20,lineStyle: {// color: 各异,width: 1,type: 'solid'}}},emphasis: {// color: 各异,borderColor: 'rgba(0,0,0,0)',borderWidth: 1,label: {show: false// position: 'outer'// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE},labelLine: {show: false,length: 20,lineStyle: {// color: 各异,width: 1,type: 'solid'}}}}},map: {mapType: 'china', // 各省的mapType暂时都用中文mapLocation: {x : 'center',y : 'center'// width // 自适应// height // 自适应},showLegendSymbol : true, // 显示图例颜色标识(系列标识的小圆点),存在legend时生效itemStyle: {normal: {// color: 各异,borderColor: '#fff',borderWidth: 1,areaStyle: {color: '#ccc'//rgba(135,206,250,0.8)},label: {show: false,textStyle: {color: 'rgba(139,69,19,1)'}}},emphasis: { // 也是选中样式// color: 各异,borderColor: 'rgba(0,0,0,0)',borderWidth: 1,areaStyle: {color: 'rgba(255,215,0,0.8)'},label: {show: false,textStyle: {color: 'rgba(139,69,19,1)'}}}}},force : {// 数据map到圆的半径的最小值和最大值minRadius : 10,maxRadius : 20,density : 1.0,attractiveness : 1.0,// 初始化的随机大小位置initSize : 300,// 向心力因子,越大向心力越大centripetal : 1,// 冷却因子coolDown : 0.99,// 分类里如果有样式会覆盖节点默认样式itemStyle: {normal: {// color: 各异,label: {show: false// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE},nodeStyle : {brushType : 'both',color : '#f08c2e',strokeColor : '#5182ab'},linkStyle : {strokeColor : '#5182ab'}},emphasis: {// color: 各异,label: {show: false// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE},nodeStyle : {},linkStyle : {}}}},chord : {radius : ['65%', '75%'],center : ['50%', '50%'],padding : 2,sort : 'none', // can be 'none', 'ascending', 'descending'sortSub : 'none', // can be 'none', 'ascending', 'descending'startAngle : 90,clockWise : false,showScale : false,showScaleText : false,itemStyle : {normal : {label : {show : true// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE},lineStyle : {width : 0,color : '#000'},chordStyle : {lineStyle : {width : 1,color : '#666'}}},emphasis : {lineStyle : {width : 0,color : '#000'},chordStyle : {lineStyle : {width : 2,color : '#333'}}}}},island: {r: 15,calculateStep: 0.1 // 滚轮可计算步长 0.1 = 10%},markPoint : {symbol: 'pin', // 标注类型symbolSize: 10, // 标注大小,半宽(半径)参数,当图形为方向或菱形则总宽度为symbolSize * 2//symbolRotate : null, // 标注旋转控制itemStyle: {normal: {// color: 各异,// borderColor: 各异, // 标注边线颜色,优先于color borderWidth: 2, // 标注边线线宽,单位px,默认为1label: {show: true,position: 'inside' // 可选为'left'|'right'|'top'|'bottom'// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE}},emphasis: {// color: 各异label: {show: true// position: 'inside' // 'left'|'right'|'top'|'bottom'// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE}}}},markLine : {// 标线起始和结束的symbol介绍类型,如果都一样,可以直接传stringsymbol: ['circle', 'arrow'], // 标线起始和结束的symbol大小,半宽(半径)参数,当图形为方向或菱形则总宽度为symbolSize * 2symbolSize: [2, 4],// 标线起始和结束的symbol旋转控制//symbolRotate : null,itemStyle: {normal: {// color: 各异, // 标线主色,线色,symbol主色// borderColor: 随color, // 标线symbol边框颜色,优先于color borderWidth: 2, // 标线symbol边框线宽,单位px,默认为2label: {show: false,// 可选为 'start'|'end'|'left'|'right'|'top'|'bottom'position: 'inside', textStyle: { // 默认使用全局文本样式,详见TEXTSTYLEcolor: '#333'}},lineStyle: {// color: 随borderColor, // 主色,线色,优先级高于borderColor和color// width: 随borderWidth, // 优先于borderWidthtype: 'solid',shadowColor : 'rgba(0,0,0,0)', //默认透明shadowBlur: 5,shadowOffsetX: 3,shadowOffsetY: 3}},emphasis: {// color: 各异label: {show: false// position: 'inside' // 'left'|'right'|'top'|'bottom'// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE},lineStyle : {}}}},textStyle: {decoration: 'none',fontFamily: 'Arial, Verdana, sans-serif',fontFamily2: '微软雅黑', // IE8- 字体模糊并且不支持不同字体混排,额外指定一份fontSize: 12,fontStyle: 'normal',fontWeight: 'normal'},// 默认标志图形类型列表symbolList : ['circle', 'rectangle', 'triangle', 'diamond','emptyCircle', 'emptyRectangle', 'emptyTriangle', 'emptyDiamond'],loadingText : 'Loading...',// 可计算特性配置,孤岛,提示颜色calculable: false, // 默认关闭可计算特性calculableColor: 'rgba(255,165,0,0.6)', // 拖拽提示边框颜色calculableHolderColor: '#ccc', // 可计算占位提示颜色nameConnector: ' & ',valueConnector: ' : ',animation: true,animationThreshold: 2500, // 动画元素阀值,产生的图形原素超过2500不出动画addDataAnimation: true, // 动态数据接口是否开启动画效果animationDuration: 2000,animationEasing: 'ExponentialOut' //BounceOut
}
ECharts 饼图
饼图主要是通过扇形的弧度表现不同类目的数据在总和中的占比,它的数据格式比柱状图更简单,只有一维的数值,不需要给类目。因为不在直角坐标系上,所以也不需要 xAxis,yAxis。
示例:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>孙叫兽演示 ECharts 柱状图实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));myChart.setOption({series : [{name: '访问来源',type: 'pie', // 设置图表类型为饼图radius: '60%', // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。data:[ // 数据数组,name 为数据项名称,value 为数据项值{value:100, name:'视频广告'},{value:274, name:'联盟广告'},{value:310, name:'邮件营销'},{value:335, name:'直接访问'},{value:400, name:'搜索引擎'}]}]})</script>
</body>
</html>
效果图:
阴影的配置
itemStyle 参数可以设置诸如阴影、透明度、颜色、边框颜色、边框宽度等:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>孙叫兽演示 ECharts 柱状图阴影实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {series : [{name: '访问来源',type: 'pie',radius: '55%',data:[{value:235, name:'视频广告'},{value:274, name:'联盟广告'},{value:310, name:'邮件营销'},{value:335, name:'直接访问'},{value:400, name:'搜索引擎'}],roseType: 'angle',itemStyle: {normal: {shadowBlur: 200,shadowColor: 'rgba(0, 0, 0, 0.5)'}}}]};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script>
</body>
</html>
效果图:
ECharts 样式设置
ECharts 可以通过样式设置来改变图形元素或者文字的颜色、明暗、大小等。
颜色主题
ECharts4 开始,除了默认主题外,内置了两套主题,分别为 light 和 dark。
var chart = echarts.init(dom, 'light');或者var chart = echarts.init(dom, 'dark');
其它主题下载:https://echarts.apache.org/zh/theme-builder.html
目前主题下载提供了 JS 版本和 JSON 版本。
如果你使用 JS 版本,可以将 JS 主题代码保存一个 主题名.js 文件,然后在 HTML 中引用该文件,最后在代码中使用该主题。
<!-- 引入主题 -->
<script src="https://sunmenglei.blog.csdn.net/static/js/wonderland.js"></script>
...// HTML 引入 wonderland.js 文件后,在初始化的时候调用
var myChart = echarts.init(dom, 'wonderland');
// ...
调色盘
调色盘可以在 option 中设置。
调色盘给定了一组颜色,图形、系列会自动从其中选择颜色。
可以设置全局的调色盘,也可以设置系列自己专属的调色盘。
option = {// 全局调色盘。color: ['#c23531','#2f4554', '#61a0a8', '#d48265', '#91c7ae','#749f83', '#ca8622', '#bda29a','#6e7074', '#546570', '#c4ccd3'],series: [{type: 'bar',// 此系列自己的调色盘。color: ['#dd6b66','#759aa0','#e69d87','#8dc1a9','#ea7e53','#eedd78','#73a373','#73b9bc','#7289ab', '#91ca8c','#f49f42'],...}, {type: 'pie',// 此系列自己的调色盘。color: ['#37A2DA', '#32C5E9', '#67E0E3', '#9FE6B8', '#FFDB5C','#ff9f7f', '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF'],...}]
}
直接的样式设置 itemStyle, lineStyle, areaStyle, label, ...
这些的地方可以直接设置图形元素的颜色、线宽、点的大小、标签的文字、标签的样式等等。
高亮的样式:emphasis
在鼠标悬浮到图形元素上时,一般会出现高亮的样式。默认情况下,高亮的样式是根据普通样式自动生成的。
如果要自定义高亮样式可以通过 emphasis 属性来定制:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>第一个 ECharts 实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));myChart.setOption({series : [{name: '访问来源',type: 'pie', // 设置图表类型为饼图radius: '55%', // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。// 高亮样式。emphasis: {itemStyle: {// 高亮时点的颜色color: 'red'},label: {show: true,// 高亮时标签的文字formatter: '高亮时显示的标签内容'}},data:[ // 数据数组,name 为数据项名称,value 为数据项值{value:235, name:'视频广告'},{value:274, name:'联盟广告'},{value:310, name:'邮件营销'},{value:335, name:'直接访问'},{value:400, name:'搜索引擎'}]}]})</script>
</body>
</html>
ECharts 异步加载数据
ECharts 通常数据设置在 setOption 中,如果我们需要异步加载数据,可以配合 jQuery等工具,在异步获取数据后通过 setOption 填入数据和配置项就行。
echarts_test_data.json 数据:
{"data_pie" : [{"value":235, "name":"视频广告"},{"value":274, "name":"联盟广告"},{"value":310, "name":"邮件营销"},{"value":335, "name":"直接访问"},{"value":400, "name":"搜索引擎"}]
}
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>第一个 ECharts 实例</title><script src="https://cdn.staticfile.org/jquery/2.2.4/jquery.min.js"></script><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));$.get('https://sunmenglei.blog.csdn.net/static/js/echarts_test_data.json', function (data) {myChart.setOption({series : [{name: '访问来源',type: 'pie', // 设置图表类型为饼图radius: '55%', // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。data:data.data_pie}]})}, 'json')</script>
</body>
如果异步加载需要一段时间,我们可以添加 loading 效果,ECharts 默认有提供了一个简单的加载动画。只需要调用 showLoading 方法显示。数据加载完成后再调用 hideLoading 方法隐藏加载动画:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>第一个 ECharts 实例</title><script src="https://cdn.staticfile.org/jquery/2.2.4/jquery.min.js"></script><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));myChart.showLoading(); // 开启 loading 效果$.get('https://sunmenglei.blog.csdn.net/static/js/echarts_test_data.json', function (data) {alert("可以看到 loading 字样。"); // 测试代码,用于查看 loading 效果myChart.hideLoading(); // 隐藏 loading 效果myChart.setOption({series : [{name: '访问来源',type: 'pie', // 设置图表类型为饼图radius: '55%', // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。data:data.data_pie}]})}, 'json');</script>
</body>
数据的动态更新
ECharts 由数据驱动,数据的改变驱动图表展现的改变,因此动态数据的实现也变得异常简单。
所有数据的更新都通过 setOption 实现,你只需要定时获取数据,setOption 填入数据,而不用考虑数据到底产生了那些变化,ECharts 会找到两组数据之间的差异然后通过合适的动画去表现数据的变化。
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>第一个 ECharts 实例</title><script src="https://cdn.staticfile.org/jquery/2.2.4/jquery.min.js"></script><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">var base = +new Date(2014, 9, 3);var oneDay = 24 * 3600 * 1000;var date = [];var data = [Math.random() * 150];var now = new Date(base);function addData(shift) {now = [now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/');date.push(now);data.push((Math.random() - 0.4) * 10 + data[data.length - 1]);if (shift) {date.shift();data.shift();}now = new Date(+new Date(now) + oneDay);}for (var i = 1; i < 100; i++) {addData();}option = {xAxis: {type: 'category',boundaryGap: false,data: date},yAxis: {boundaryGap: [0, '50%'],type: 'value'},series: [{name:'成交',type:'line',smooth:true,symbol: 'none',stack: 'a',areaStyle: {normal: {}},data: data}]};setInterval(function () {addData(true);myChart.setOption({xAxis: {data: date},series: [{name:'成交',data: data}]});}, 500);// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));myChart.setOption(option)</script>
</body>
ECharts 数据集(dataset)
ECharts 使用 dataset 管理数据。
dataset 组件用于单独的数据集声明,从而数据可以单独管理,被多个组件复用,并且可以基于数据指定数据到视觉的映射。
下面是一个最简单的 dataset 的例子:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>第一个 ECharts 实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {legend: {},tooltip: {},dataset: {// 提供一份数据。source: [['product', '2015', '2016', '2017'],['Matcha Latte', 43.3, 85.8, 93.7],['Milk Tea', 83.1, 73.4, 55.1],['Cheese Cocoa', 86.4, 65.2, 82.5],['Walnut Brownie', 72.4, 53.9, 39.1]]},// 声明一个 X 轴,类目轴(category)。默认情况下,类目轴对应到 dataset 第一列。xAxis: {type: 'category'},// 声明一个 Y 轴,数值轴。yAxis: {},// 声明多个 bar 系列,默认情况下,每个系列会自动对应到 dataset 的每一列。series: [{type: 'bar'},{type: 'bar'},{type: 'bar'}]};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script>
</body>
</html>
效果图:
示例:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>对象数组格式的数据集</title><!-- 引入 echarts.js --><script src="./js/echarts.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {legend: {},tooltip: {},dataset: {// 这里指定了维度名的顺序,从而可以利用默认的维度到坐标轴的映射。// 如果不指定 dimensions,也可以通过指定 series.encode 完成映射,参见后文。dimensions: ['product', '2019', '2020', '2021'],source: [{product: 'Matcha Latte', '2019': 43.3, '2020': 85.8, '2021': 93.7},{product: 'Milk Tea', '2019': 83.1, '2020': 73.4, '2021': 55.1},{product: 'Cheese Cocoa', '2019': 86.4, '2020': 65.2, '2021': 82.5},{product: 'Walnut Brownie', '2019': 72.4, '2020': 53.9, '2021': 39.1}]},xAxis: {type: 'category'},yAxis: {},series: [{type: 'bar'},{type: 'bar'},{type: 'bar'}]};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script>
</body>
</html>
数据到图形的映射
我们可以在配置项中将数据映射到图形中。
我们可以使用 series.seriesLayoutBy 属性来配置 dataset 是列(column)还是行(row)映射为图形系列(series),默认是按照列(column)来映射。
以下实例我们将通过 seriesLayoutBy 属性来配置数据是使用列显示还是按行显示。
效果图:
示例:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>数据到图形的映射 ECharts 实例</title><!-- 引入 echarts.js --><script src="./js/echarts.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {legend: {},//说明或者解释tooltip: {},//提示信息dataset: {//数据集source: [['product', '2018', '2019', '2020', '2021'],['Matcha Latte', 41.1, 30.4, 65.1, 53.3],['Milk Tea', 86.5, 92.1, 85.7, 83.1],['Cheese Cocoa', 24.1, 67.2, 79.5, 86.4]]},xAxis: [//X轴{type: 'category', gridIndex: 0},{type: 'category', gridIndex: 1}],yAxis: [//y轴{gridIndex: 0},{gridIndex: 1}],grid: [//坐标{bottom: '55%'},{top: '55%'}],series: [// 这几个系列会在第一个直角坐标系中,每个系列对应到 dataset 的每一行。{type: 'bar', seriesLayoutBy: 'row'},{type: 'bar', seriesLayoutBy: 'row'},{type: 'bar', seriesLayoutBy: 'row'},// 这几个系列会在第二个直角坐标系中,每个系列对应到 dataset 的每一列。{type: 'bar', xAxisIndex: 1, yAxisIndex: 1},{type: 'bar', xAxisIndex: 1, yAxisIndex: 1},{type: 'bar', xAxisIndex: 1, yAxisIndex: 1},{type: 'bar', xAxisIndex: 1, yAxisIndex: 1}]}// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script>
</body>
</html>
常用图表所描述的数据大部分是"二维表"结构,我们可以使用 series.encode 属性将对应的数据映射到坐标轴(如 X、Y 轴):
示例:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>series.encode 属性将对应的数据映射到坐标轴(如 X、Y 轴): ECharts 实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {dataset: {source: [['score', 'amount', 'product'],[89.3, 58212, 'Matcha Latte'],[57.1, 78254, 'Milk Tea'],[74.4, 41032, 'Cheese Cocoa'],[50.1, 12755, 'Cheese Brownie'],[89.7, 20145, 'Matcha Cocoa'],[68.1, 79146, 'Tea'],[19.6, 91852, 'Orange Juice'],[10.6, 101852, 'Lemon Juice'],[32.7, 20112, 'Walnut Brownie']]},grid: {containLabel: true},xAxis: {},yAxis: {type: 'category'},series: [{type: 'bar',encode: {// 将 "amount" 列映射到 X 轴。x: 'amount',// 将 "product" 列映射到 Y 轴。y: 'product'}}]};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script>
</body>
</html>
效果图:
encode 声明的基本结构如下,其中冒号左边是坐标系、标签等特定名称,如 'x', 'y', 'tooltip' 等,冒号右边是数据中的维度名(string 格式)或者维度的序号(number 格式,从 0 开始计数),可以指定一个或多个维度(使用数组)。通常情况下,下面各种信息不需要所有的都写,按需写即可。
下面是 encode 支持的属性:
// 在任何坐标系和系列中,都支持: encode: {// 使用 “名为 product 的维度” 和 “名为 score 的维度” 的值在 tooltip 中显示tooltip: ['product', 'score']// 使用 “维度 1” 和 “维度 3” 的维度名连起来作为系列名。(有时候名字比较长,这可以避免在 series.name 重复输入这些名字)seriesName: [1, 3],// 表示使用 “维度2” 中的值作为 id。这在使用 setOption 动态更新数据时有用处,可以使新老数据用 id 对应起来,从而能够产生合适的数据更新动画。itemId: 2,// 指定数据项的名称使用 “维度3” 在饼图等图表中有用,可以使这个名字显示在图例(legend)中。itemName: 3 }// 直角坐标系(grid/cartesian)特有的属性: encode: {// 把 “维度1”、“维度5”、“名为 score 的维度” 映射到 X 轴:x: [1, 5, 'score'],// 把“维度0”映射到 Y 轴。y: 0 }// 单轴(singleAxis)特有的属性: encode: {single: 3 }// 极坐标系(polar)特有的属性: encode: {radius: 3,angle: 2 }// 地理坐标系(geo)特有的属性: encode: {lng: 3,lat: 2 }// 对于一些没有坐标系的图表,例如饼图、漏斗图等,可以是: encode: {value: 3 }
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>ECharts 实例</title><script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据$.get('https://www.sunjiaoshou.top/static/js/life-expectancy-table.json', function (data) {var sizeValue = '57%';var symbolSize = 2.5;option = {legend: {},tooltip: {},toolbox: {left: 'center',feature: {dataZoom: {}}},grid: [{right: sizeValue, bottom: sizeValue},{left: sizeValue, bottom: sizeValue},{right: sizeValue, top: sizeValue},{left: sizeValue, top: sizeValue}],xAxis: [{type: 'value', gridIndex: 0, name: 'Income', axisLabel: {rotate: 50, interval: 0}},{type: 'category', gridIndex: 1, name: 'Country', boundaryGap: false, axisLabel: {rotate: 50, interval: 0}},{type: 'value', gridIndex: 2, name: 'Income', axisLabel: {rotate: 50, interval: 0}},{type: 'value', gridIndex: 3, name: 'Life Expectancy', axisLabel: {rotate: 50, interval: 0}}],yAxis: [{type: 'value', gridIndex: 0, name: 'Life Expectancy'},{type: 'value', gridIndex: 1, name: 'Income'},{type: 'value', gridIndex: 2, name: 'Population'},{type: 'value', gridIndex: 3, name: 'Population'}],dataset: {dimensions: ['Income','Life Expectancy','Population','Country',{name: 'Year', type: 'ordinal'}],source: data},series: [{type: 'scatter',symbolSize: symbolSize,xAxisIndex: 0,yAxisIndex: 0,encode: {x: 'Income',y: 'Life Expectancy',tooltip: [0, 1, 2, 3, 4]}},{type: 'scatter',symbolSize: symbolSize,xAxisIndex: 1,yAxisIndex: 1,encode: {x: 'Country',y: 'Income',tooltip: [0, 1, 2, 3, 4]}},{type: 'scatter',symbolSize: symbolSize,xAxisIndex: 2,yAxisIndex: 2,encode: {x: 'Income',y: 'Population',tooltip: [0, 1, 2, 3, 4]}},{type: 'scatter',symbolSize: symbolSize,xAxisIndex: 3,yAxisIndex: 3,encode: {x: 'Life Expectancy',y: 'Population',tooltip: [0, 1, 2, 3, 4]}}]};myChart.setOption(option);});</script>
</body>
</html>
视觉通道(颜色、尺寸等)的映射
我们可以使用 visualMap 组件进行视觉通道的映射。
视觉元素可以是:
- symbol: 图元的图形类别。
- symbolSize: 图元的大小。
- color: 图元的颜色。
- colorAlpha: 图元的颜色的透明度。
- opacity: 图元以及其附属物(如文字标签)的透明度。
- colorLightness: 颜色的明暗度。
- colorSaturation: 颜色的饱和度。
- colorHue: 颜色的色调。
visualMap 组件可以定义多个,从而可以同时对数据中的多个维度进行视觉映射。
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>ECharts 实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));var option = {dataset: {source: [['score', 'amount', 'product'],[89.3, 58212, 'Matcha Latte'],[57.1, 78254, 'Milk Tea'],[74.4, 41032, 'Cheese Cocoa'],[50.1, 12755, 'Cheese Brownie'],[89.7, 20145, 'Matcha Cocoa'],[68.1, 79146, 'Tea'],[19.6, 91852, 'Orange Juice'],[10.6, 101852, 'Lemon Juice'],[32.7, 20112, 'Walnut Brownie']]},grid: {containLabel: true},xAxis: {name: 'amount'},yAxis: {type: 'category'},visualMap: {orient: 'horizontal',left: 'center',min: 10,max: 100,text: ['High Score', 'Low Score'],// Map the score column to colordimension: 0,inRange: {color: ['#D7DA8B', '#E15457']}},series: [{type: 'bar',encode: {// Map the "amount" column to X axis.x: 'amount',// Map the "product" column to Y axisy: 'product'}}]};myChart.setOption(option);</script>
</body>
</html>
效果图:
交互联动
以下实例多个图表共享一个 dataset,并带有联动交互
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>联动交互 ECharts 实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));setTimeout(function () {option = {legend: {},tooltip: {trigger: 'axis',showContent: false},dataset: {source: [['product', '2017', '2018', '2019', '2020', '2021', '2022'],['Matcha Latte', 41.1, 30.4, 65.1, 53.3, 83.8, 98.7],['Milk Tea', 86.5, 92.1, 85.7, 83.1, 73.4, 55.1],['Cheese Cocoa', 24.1, 67.2, 79.5, 86.4, 65.2, 82.5],['Walnut Brownie', 55.2, 67.1, 69.2, 72.4, 53.9, 39.1]]},xAxis: {type: 'category'},yAxis: {gridIndex: 0},grid: {top: '55%'},series: [{type: 'line', smooth: true, seriesLayoutBy: 'row'},{type: 'line', smooth: true, seriesLayoutBy: 'row'},{type: 'line', smooth: true, seriesLayoutBy: 'row'},{type: 'line', smooth: true, seriesLayoutBy: 'row'},{type: 'pie',id: 'pie',radius: '30%',center: ['50%', '25%'],label: {formatter: '{b}: {@2012} ({d}%)'},encode: {itemName: 'product',value: '2012',tooltip: '2012'}}]};myChart.on('updateAxisPointer', function (event) {var xAxisInfo = event.axesInfo[0];if (xAxisInfo) {var dimension = xAxisInfo.value + 1;myChart.setOption({series: {id: 'pie',label: {formatter: '{b}: {@[' + dimension + ']} ({d}%)'},encode: {value: dimension,tooltip: dimension}}});}});myChart.setOption(option);});</script>
</body>
</html>
效果图:
ECharts 交互组件
ECharts 提供了很多交互组件:例组件 legend、标题组件 title、视觉映射组件 visualMap、数据区域缩放组件 dataZoom、时间线组件 timeline。
接下来的内容我们将介绍如何使用数据区域缩放组件 dataZoom。
dataZoom 组件可以实现通过鼠标滚轮滚动,放大缩小图表的功能。
默认情况下 dataZoom 控制 x 轴,即对 x 轴进行数据窗口缩放和数据窗口平移操作。
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>孙叫兽dataZoom组件ECharts 实例</title><!-- 引入 echarts.js --><script src="js/echarts.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {xAxis: {type: 'value'},yAxis: {type: 'value'},dataZoom: [{ // 这个dataZoom组件,默认控制x轴。type: 'slider', // 这个 dataZoom 组件是 slider 型 dataZoom 组件start: 10, // 左边在 10% 的位置。end: 60 // 右边在 60% 的位置。}],series: [{type: 'scatter', // 这是个『散点图』itemStyle: {opacity: 0.8},symbolSize: function (val) {return val[2] * 40;},data: [["14.616","7.241","0.896"],["3.958","5.701","0.955"],["2.768","8.971","0.669"],["9.051","9.710","0.171"],["14.046","4.182","0.536"],["12.295","1.429","0.962"],["4.417","8.167","0.113"],["0.492","4.771","0.785"],["7.632","2.605","0.645"],["14.242","5.042","0.368"]]}]}// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script>
</body>
</html>
效果图:
上面的实例只能拖动 dataZoom 组件来缩小或放大图表。如果想在坐标系内进行拖动,以及用鼠标滚轮(或移动触屏上的两指滑动)进行缩放,那么需要 再再加上一个 inside 型的 dataZoom 组件。
在以上实例基础上我们再增加 type: 'inside' 的配置信息:
dataZoom: [{ // 这个dataZoom组件,默认控制x轴。type: 'slider', // 这个 dataZoom 组件是 slider 型 dataZoom 组件start: 10, // 左边在 10% 的位置。end: 60 // 右边在 60% 的位置。},{ // 这个dataZoom组件,也控制x轴。type: 'inside', // 这个 dataZoom 组件是 inside 型 dataZoom 组件start: 10, // 左边在 10% 的位置。end: 60 // 右边在 60% 的位置。}],
我们可以通过 dataZoom.xAxisIndex 或 dataZoom.yAxisIndex 来指定 dataZoom 控制哪个或哪些数轴。
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>ECharts 实例</title><!-- 引入 echarts.js --><script src="./js/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var data1 = [];var data2 = [];var data3 = [];var random = function (max) {return (Math.random() * max).toFixed(3);};for (var i = 0; i < 500; i++) {data1.push([random(15), random(10), random(1)]);data2.push([random(10), random(10), random(1)]);data3.push([random(15), random(10), random(1)]);}option = {animation: false,legend: {data: ['scatter', 'scatter2', 'scatter3']},tooltip: {},xAxis: {type: 'value',min: 'dataMin',max: 'dataMax',splitLine: {show: true}},yAxis: {type: 'value',min: 'dataMin',max: 'dataMax',splitLine: {show: true}},dataZoom: [{type: 'slider',show: true,xAxisIndex: [0],start: 1,end: 35},{type: 'slider',show: true,yAxisIndex: [0],left: '93%',start: 29,end: 36},{type: 'inside',xAxisIndex: [0],start: 1,end: 35},{type: 'inside',yAxisIndex: [0],start: 29,end: 36}],series: [{name: 'scatter',type: 'scatter',itemStyle: {normal: {opacity: 0.8}},symbolSize: function (val) {return val[2] * 40;},data: data1},{name: 'scatter2',type: 'scatter',itemStyle: {normal: {opacity: 0.8}},symbolSize: function (val) {return val[2] * 40;},data: data2},{name: 'scatter3',type: 'scatter',itemStyle: {normal: {opacity: 0.8,}},symbolSize: function (val) {return val[2] * 40;},data: data3}]}// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script>
</body>
</html>
效果图:
ECharts 响应式
ECharts 图表显示在用户指定高宽的 DOM 节点(容器)中。
有时候我们希望在 PC 和 移动设备上都能够很好的展示图表的内容,实现响应式的设计,为了解决这个问题,ECharts 完善了组件的定位设置,并实现了自适应能力。
ECharts 组件的定位和布局
大部分『组件』和『系列』会遵循两种定位方式。
left/right/top/bottom/width/height 定位方式
这六个量中,每个量都可以是『绝对值』或者『百分比』或者『位置描述』。
绝对值
单位是浏览器像素(px),用
number
形式书写(不写单位)。例如{left: 23, height: 400}
。百分比
表示占 DOM 容器高宽的百分之多少,用
string
形式书写。例如{right: '30%', bottom: '40%'}
。位置描述
- 可以设置
left: 'center'
,表示水平居中。- 可以设置
top: 'middle'
,表示垂直居中。这六个量的概念,和 CSS 中六个量的概念类似:
- left:距离 DOM 容器左边界的距离。
- right:距离 DOM 容器右边界的距离。
- top:距离 DOM 容器上边界的距离。
- bottom:距离 DOM 容器下边界的距离。
- width:宽度。
- height:高度。
在横向,left、right、width 三个量中,只需两个量有值即可,因为任两个量可以决定组件的位置和大小,例如 left 和 right 或者 right 和 width 都可以决定组件的位置和大小。 纵向,top、bottom、height 三个量,和横向类同不赘述。
center / radius 定位方式
center
是一个数组,表示
[x, y]
,其中,x
、y
可以是『绝对值』或者『百分比』,含义和前述相同。
radius
是一个数组,表示
[内半径, 外半径]
,其中,内外半径可以是『绝对值』或者『百分比』,含义和前述相同。在自适应容器大小时,百分比设置是很有用的。
横向(horizontal)和纵向(vertical)
ECharts的『外观狭长』型的组件(如 legend、visualMap、dataZoom、timeline等),大多提供了『横向布局』『纵向布局』的选择。例如,在细长的移动端屏幕上,可能适合使用『纵向布局』;在PC宽屏上,可能适合使用『横向布局』。
横纵向布局的设置,一般在『组件』或者『系列』的 orient 或者 layout 配置项上,设置为 'horizontal' 或者 'vertical'。
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>ECharts 实例</title><script src="https://cdn.staticfile.org/jquery/2.2.4/jquery.min.js"></script><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));$.when($.getScript('https://www.sunjia0shou.com/static/js/timelineGDP.js'),$.getScript('https://www.sunjiaoshou.com/static/js/draggable.js')).done(function () {draggable.init($('div[_echarts_instance_]')[0],myChart,{width: 700,height: 400,throttle: 70});myChart.hideLoading();option = {baseOption: {title : {text: '南丁格尔玫瑰图',subtext: '纯属虚构',x:'center'},tooltip : {trigger: 'item',formatter: "{a} <br/>{b} : {c} ({d}%)"},legend: {data:['rose1','rose2','rose3','rose4','rose5','rose6','rose7','rose8']},toolbox: {show : true,feature : {mark : {show: true},dataView : {show: true, readOnly: false},magicType : {show: true,type: ['pie', 'funnel']},restore : {show: true},saveAsImage : {show: true}}},calculable : true,series : [{name:'半径模式',type:'pie',roseType : 'radius',label: {normal: {show: false},emphasis: {show: true}},lableLine: {normal: {show: false},emphasis: {show: true}},data:[{value:10, name:'rose1'},{value:5, name:'rose2'},{value:15, name:'rose3'},{value:25, name:'rose4'},{value:20, name:'rose5'},{value:35, name:'rose6'},{value:30, name:'rose7'},{value:40, name:'rose8'}]},{name:'面积模式',type:'pie',roseType : 'area',data:[{value:10, name:'rose1'},{value:5, name:'rose2'},{value:15, name:'rose3'},{value:25, name:'rose4'},{value:20, name:'rose5'},{value:35, name:'rose6'},{value:30, name:'rose7'},{value:40, name:'rose8'}]}]},media: [{option: {legend: {right: 'center',bottom: 0,orient: 'horizontal'},series: [{radius: [20, '50%'],center: ['25%', '50%']},{radius: [30, '50%'],center: ['75%', '50%']}]}},{query: {minAspectRatio: 1},option: {legend: {right: 'center',bottom: 0,orient: 'horizontal'},series: [{radius: [20, '50%'],center: ['25%', '50%']},{radius: [30, '50%'],center: ['75%', '50%']}]}},{query: {maxAspectRatio: 1},option: {legend: {right: 'center',bottom: 0,orient: 'horizontal'},series: [{radius: [20, '50%'],center: ['50%', '30%']},{radius: [30, '50%'],center: ['50%', '70%']}]}},{query: {maxWidth: 500},option: {legend: {right: 10,top: '15%',orient: 'vertical'},series: [{radius: [20, '50%'],center: ['50%', '30%']},{radius: [30, '50%'],center: ['50%', '75%']}]}}]};myChart.setOption(option);});</script>
</body>
</html>
要在 option 中设置 Media Query 须遵循如下格式:
option = {baseOption: { // 这里是基本的『原子option』。title: {...},legend: {...},series: [{...}, {...}, ...],...},media: [ // 这里定义了 media query 的逐条规则。{query: {...}, // 这里写规则。option: { // 这里写此规则满足下的option。legend: {...},...}},{query: {...}, // 第二个规则。option: { // 第二个规则对应的option。legend: {...},...}},{ // 这条里没有写规则,表示『默认』,option: { // 即所有规则都不满足时,采纳这个option。legend: {...},...}}] };
上面的例子中,baseOption、以及 media 每个 option 都是『原子 option』,即普通的含有各组件、系列定义的 option。而由『原子option』组合成的整个 option,我们称为『复合 option』。baseOption 是必然被使用的,此外,满足了某个 query 条件时,对应的 option 会被使用 chart.mergeOption() 来 merge 进去。
query
每个 query 类似于这样:
{minWidth: 200,maxHeight: 300,minAspectRatio: 1.3
}
现在支持三个属性:width、height、aspectRatio(长宽比)。每个属性都可以加上 min 或 max 前缀。比如,minWidth: 200 表示『大于等于200px宽度』。两个属性一起写表示『并且』,比如:{minWidth: 200, maxHeight: 300} 表示『大于等于200px宽度,并且小于等于300px高度』。
option
media中的 option 既然是『原子 option』,理论上可以写任何 option 的配置项。但是一般我们只写跟布局定位相关的,例如截取上面例子中的一部分 query option:
media: [...,{query: {maxAspectRatio: 1 // 当长宽比小于1时。},option: {legend: { // legend 放在底部中间。right: 'center',bottom: 0,orient: 'horizontal' // legend 横向布局。},series: [ // 两个饼图左右布局。{radius: [20, '50%'],center: ['50%', '30%']},{radius: [30, '50%'],center: ['50%', '70%']}]}},{query: {maxWidth: 500 // 当容器宽度小于 500 时。},option: {legend: {right: 10, // legend 放置在右侧中间。top: '15%',orient: 'vertical' // 纵向布局。},series: [ // 两个饼图上下布局。{radius: [20, '50%'],center: ['50%', '30%']},{radius: [30, '50%'],center: ['50%', '75%']}]}},... ]
多个 query 被满足时的优先级
注意,可以有多个 query 同时被满足,会都被 mergeOption,定义在后的后被 merge(即优先级更高)。
默认 query
如果 media 中有某项不写 query,则表示『默认值』,即所有规则都不满足时,采纳这个option。
容器大小实时变化时的注意事项
在不少情况下,并不需要容器DOM节点任意随着拖拽变化大小,而是只是根据不同终端设置几个典型尺寸。
但是如果容器DOM节点需要能任意随着拖拽变化大小,那么目前使用时需要注意这件事:某个配置项,如果在某一个 query option 中出现,那么在其他 query option 中也必须出现,否则不能够回归到原来的状态。(left/right/top/bottom/width/height 不受这个限制。)
『复合 option』 中的 media 不支持 merge
也就是说,当第二(或三、四、五 ...)次 chart.setOption(rawOption) 时,如果 rawOption 是 复合option(即包含 media 列表),那么新的 rawOption.media 列表不会和老的 media 列表进行 merge,而是简单替代。当然,rawOption.baseOption 仍然会正常和老的 option 进行merge。 其实,很少有场景需要使用『复合 option』来多次 setOption,而我们推荐的做法是,使用 mediaQuery 时,第一次setOption使用『复合 option』,后面 setOption 时仅使用 『原子 option』,也就是仅仅用 setOption 来改变 baseOption。
以下中我们使用了 jQuery 来加载外部数据,使用时我们需要引入 jQuery 库。该实例是一个和时间轴结合的例子:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>ECharts 实例</title><script src="https://cdn.staticfile.org/jquery/2.2.4/jquery.min.js"></script><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));$.when($.getScript('https://www.sunjiaoshou.com/static/js/timelineGDP.js'),$.getScript('https://www.sunjiaoshou.com/static/js/draggable.js')).done(function () {draggable.init($('div[_echarts_instance_]')[0],myChart,{width: 700,height: 630,lockY: true,throttle: 70});myChart.hideLoading();var categoryData = ['北京','天津','河北','山西','内蒙古','辽宁','吉林','黑龙江','上海','江苏','浙江','安徽','福建','江西','山东','河南','湖北','湖南','广东','广西','海南','重庆','四川','贵州','云南','西藏','陕西','甘肃','青海','宁夏','新疆'];option = {baseOption: {timeline: {axisType: 'category',autoPlay: true,playInterval: 1000,data: ['2012-01-01', '2013-01-01', '2014-01-01','2015-01-01', '2016-01-01', '2017-01-01','2018-01-01', '2019-01-01', '2020-01-01','2021-01-01'],label: {formatter : function(s) {return (new Date(s)).getFullYear();}}},title: {subtext: 'Media Query 示例'},tooltip: {trigger:'axis',axisPointer: {type: 'shadow'}},xAxis: {type: 'value',name: 'GDP(亿元)',max: 30000,data: null},yAxis: {type: 'category',data: categoryData,axisLabel: {interval: 0},splitLine: {show: false}},legend: {data: ['第一产业', '第二产业', '第三产业', 'GDP', '金融', '房地产'],selected: {'GDP': false, '金融': false, '房地产': false}},calculable : true,series: [{name: 'GDP', type: 'bar'},{name: '金融', type: 'bar'},{name: '房地产', type: 'bar'},{name: '第一产业', type: 'bar'},{name: '第二产业', type: 'bar'},{name: '第三产业', type: 'bar'},{name: 'GDP占比', type: 'pie'}]},media: [{option: {legend: {orient: 'horizontal',left: 'right',itemGap: 10},grid: {left: '10%',top: 80,right: 90,bottom: 100},xAxis: {nameLocation: 'end',nameGap: 10,splitNumber: 5,splitLine: {show: true}},timeline: {orient: 'horizontal',inverse: false,left: '20%',right: '20%',bottom: 10,height: 40},series: [{name: 'GDP占比', center: ['75%', '30%'], radius: '28%'}]}},{query: {maxWidth: 670, minWidth: 550},option: {legend: {orient: 'horizontal',left: 200,itemGap: 5},grid: {left: '10%',top: 80,right: 90,bottom: 100},xAxis: {nameLocation: 'end',nameGap: 10,splitNumber: 5,splitLine: {show: true}},timeline: {orient: 'horizontal',inverse: false,left: '20%',right: '20%',bottom: 10,height: 40},series: [{name: 'GDP占比', center: ['75%', '30%'], radius: '28%'}]}},{query: {maxWidth: 550},option: {legend: {orient: 'vertical',left: 'right',itemGap: 5},grid: {left: 55,top: '32%',right: 100,bottom: 50},xAxis: {nameLocation: 'middle',nameGap: 25,splitNumber: 3},timeline: {orient: 'vertical',inverse: true,right: 10,top: 150,bottom: 10,width: 55},series: [{name: 'GDP占比', center: ['45%', '20%'], radius: '28%'}]}}],options: [{title: {text: '2012全国宏观经济指标'},series: [{data: dataMap.dataGDP['2012']},{data: dataMap.dataFinancial['2012']},{data: dataMap.dataEstate['2012']},{data: dataMap.dataPI['2012']},{data: dataMap.dataSI['2012']},{data: dataMap.dataTI['2012']},{data: [{name: '第一产业', value: dataMap.dataPI['2012sum']},{name: '第二产业', value: dataMap.dataSI['2012sum']},{name: '第三产业', value: dataMap.dataTI['2012sum']}]}]},{title : {text: '2013全国宏观经济指标'},series : [{data: dataMap.dataGDP['2013']},{data: dataMap.dataFinancial['2013']},{data: dataMap.dataEstate['2013']},{data: dataMap.dataPI['2013']},{data: dataMap.dataSI['2013']},{data: dataMap.dataTI['2013']},{data: [{name: '第一产业', value: dataMap.dataPI['2013sum']},{name: '第二产业', value: dataMap.dataSI['2013sum']},{name: '第三产业', value: dataMap.dataTI['2013sum']}]}]},{title : {text: '2004全国宏观经济指标'},series : [{data: dataMap.dataGDP['2004']},{data: dataMap.dataFinancial['2004']},{data: dataMap.dataEstate['2004']},{data: dataMap.dataPI['2004']},{data: dataMap.dataSI['2004']},{data: dataMap.dataTI['2004']},{data: [{name: '第一产业', value: dataMap.dataPI['2004sum']},{name: '第二产业', value: dataMap.dataSI['2004sum']},{name: '第三产业', value: dataMap.dataTI['2004sum']}]}]},{title : {text: '2005全国宏观经济指标'},series : [{data: dataMap.dataGDP['2005']},{data: dataMap.dataFinancial['2005']},{data: dataMap.dataEstate['2005']},{data: dataMap.dataPI['2005']},{data: dataMap.dataSI['2005']},{data: dataMap.dataTI['2005']},{data: [{name: '第一产业', value: dataMap.dataPI['2005sum']},{name: '第二产业', value: dataMap.dataSI['2005sum']},{name: '第三产业', value: dataMap.dataTI['2005sum']}]}]},{title : {text: '2006全国宏观经济指标'},series : [{data: dataMap.dataGDP['2006']},{data: dataMap.dataFinancial['2006']},{data: dataMap.dataEstate['2006']},{data: dataMap.dataPI['2006']},{data: dataMap.dataSI['2006']},{data: dataMap.dataTI['2006']},{data: [{name: '第一产业', value: dataMap.dataPI['2006sum']},{name: '第二产业', value: dataMap.dataSI['2006sum']},{name: '第三产业', value: dataMap.dataTI['2006sum']}]}]},{title : {text: '2007全国宏观经济指标'},series : [{data: dataMap.dataGDP['2007']},{data: dataMap.dataFinancial['2007']},{data: dataMap.dataEstate['2007']},{data: dataMap.dataPI['2007']},{data: dataMap.dataSI['2007']},{data: dataMap.dataTI['2007']},{data: [{name: '第一产业', value: dataMap.dataPI['2007sum']},{name: '第二产业', value: dataMap.dataSI['2007sum']},{name: '第三产业', value: dataMap.dataTI['2007sum']}]}]},{title : {text: '2008全国宏观经济指标'},series : [{data: dataMap.dataGDP['2008']},{data: dataMap.dataFinancial['2008']},{data: dataMap.dataEstate['2008']},{data: dataMap.dataPI['2008']},{data: dataMap.dataSI['2008']},{data: dataMap.dataTI['2008']},{data: [{name: '第一产业', value: dataMap.dataPI['2008sum']},{name: '第二产业', value: dataMap.dataSI['2008sum']},{name: '第三产业', value: dataMap.dataTI['2008sum']}]}]},{title : {text: '2009全国宏观经济指标'},series : [{data: dataMap.dataGDP['2009']},{data: dataMap.dataFinancial['2009']},{data: dataMap.dataEstate['2009']},{data: dataMap.dataPI['2009']},{data: dataMap.dataSI['2009']},{data: dataMap.dataTI['2009']},{data: [{name: '第一产业', value: dataMap.dataPI['2009sum']},{name: '第二产业', value: dataMap.dataSI['2009sum']},{name: '第三产业', value: dataMap.dataTI['2009sum']}]}]},{title : {text: '2010全国宏观经济指标'},series : [{data: dataMap.dataGDP['2010']},{data: dataMap.dataFinancial['2010']},{data: dataMap.dataEstate['2010']},{data: dataMap.dataPI['2010']},{data: dataMap.dataSI['2010']},{data: dataMap.dataTI['2010']},{data: [{name: '第一产业', value: dataMap.dataPI['2010sum']},{name: '第二产业', value: dataMap.dataSI['2010sum']},{name: '第三产业', value: dataMap.dataTI['2010sum']}]}]},{title : {text: '2011全国宏观经济指标'},series : [{data: dataMap.dataGDP['2011']},{data: dataMap.dataFinancial['2011']},{data: dataMap.dataEstate['2011']},{data: dataMap.dataPI['2011']},{data: dataMap.dataSI['2011']},{data: dataMap.dataTI['2011']},{data: [{name: '第一产业', value: dataMap.dataPI['2011sum']},{name: '第二产业', value: dataMap.dataSI['2011sum']},{name: '第三产业', value: dataMap.dataTI['2011sum']}]}]}]};myChart.setOption(option);});</script>
</body>
</html>
ECharts 数据的视觉映射
数据可视化简单来讲就是将数据用图表的形式来展示,专业的表达方式就是数据到视觉元素的映射过程。
ECharts 的每种图表本身就内置了这种映射过程,我们之前学习到的柱形图就是将数据映射到长度。
此外,ECharts 还提供了 visualMap 组件 来提供通用的视觉映射。visualMap 组件中可以使用的视觉元素有:
- 图形类别(symbol)
- 图形大小(symbolSize)
- 颜色(color)
- 透明度(opacity)
- 颜色透明度(colorAlpha)
- 颜色明暗度(colorLightness)
- 颜色饱和度(colorSaturation)
- 色调(colorHue)
数据和维度
ECharts 中的数据,一般存放于 series.data 中。
不同的图表类型,数据格式有所不一样,但是他们的共同特点就都是数据项(dataItem) 的集合。每个数据项含有 数据值(value) 和其他信息(可选)。每个数据值,可以是单一的数值(一维)或者一个数组(多维)。
series.data 最常见的形式 是线性表,即一个普通数组:
series: {
data: [
{ // 这里每一个项就是数据项(dataItem)
value: 2323, // 这是数据项的数据值(value)
itemStyle: {...}
},
1212, // 也可以直接是 dataItem 的 value,这更常见。
2323, // 每个 value 都是『一维』的。
4343,
3434
]
}
series: {
data: [
{ // 这里每一个项就是数据项(dataItem)
value: [3434, 129, '圣马力诺'], // 这是数据项的数据值(value)
itemStyle: {...}
},
[1212, 5454, '梵蒂冈'], // 也可以直接是 dataItem 的 value,这更常见。
[2323, 3223, '瑙鲁'], // 每个 value 都是『三维』的,每列是一个维度。
[4343, 23, '图瓦卢'] // 假如是『气泡图』,常见第一维度映射到x轴,
// 第二维度映射到y轴,
// 第三维度映射到气泡半径(symbolSize)
]
}
在图表中,往往默认把 value 的前一两个维度进行映射,比如取第一个维度映射到x轴,取第二个维度映射到y轴。如果想要把更多的维度展现出来,可以借助 visualMap 。
visualMap 组件
visualMap 组件定义了把数据的指定维度映射到对应的视觉元素上。
visualMap 组件可以定义多个,从而可以同时对数据中的多个维度进行视觉映射。
visualMap 组件可以定义为 分段型(visualMapPiecewise) 或 连续型(visualMapContinuous),通过 type 来区分。例如:
option = {
visualMap: [
{ // 第一个 visualMap 组件
type: 'continuous', // 定义为连续型 visualMap
...
},
{ // 第二个 visualMap 组件
type: 'piecewise', // 定义为分段型 visualMap
...
}
],
...
};
分段型视觉映射组件,有三种模式:
- 连续型数据平均分段: 依据 visualMap-piecewise.splitNumber 来自动平均分割成若干块。
- 连续型数据自定义分段: 依据 visualMap-piecewise.pieces 来定义每块范围。
- 离散数据根据类别分段: 类别定义在 visualMap-piecewise.categories 中。
分段型视觉映射组件,展现形式如下图:
示例:
<!DOCTYPE html>
<html style="height: 100%"><head><meta charset="utf-8"></head><body style="height: 100%; margin: 0"><div id="container" style="height: 100%"></div><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts-gl/dist/echarts-gl.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts-stat/dist/ecStat.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts/dist/extension/dataTool.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts/map/js/china.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts/map/js/world.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts/dist/extension/bmap.min.js"></script><script type="text/javascript">
var dom = document.getElementById("container");
var myChart = echarts.init(dom);
var app = {};
option = null;
var geoCoordMap = {"海门":[121.15,31.89],"鄂尔多斯":[109.781327,39.608266],"招远":[120.38,37.35],"舟山":[122.207216,29.985295],"齐齐哈尔":[123.97,47.33],"盐城":[120.13,33.38],"赤峰":[118.87,42.28],"青岛":[120.33,36.07],"乳山":[121.52,36.89],"金昌":[102.188043,38.520089],"泉州":[118.58,24.93],"莱西":[120.53,36.86],"日照":[119.46,35.42],"胶南":[119.97,35.88],"南通":[121.05,32.08],"拉萨":[91.11,29.97],"云浮":[112.02,22.93],"梅州":[116.1,24.55],"文登":[122.05,37.2],"上海":[121.48,31.22],"攀枝花":[101.718637,26.582347],"威海":[122.1,37.5],"承德":[117.93,40.97],"厦门":[118.1,24.46],"汕尾":[115.375279,22.786211],"潮州":[116.63,23.68],"丹东":[124.37,40.13],"太仓":[121.1,31.45],"曲靖":[103.79,25.51],"烟台":[121.39,37.52],"福州":[119.3,26.08],"瓦房店":[121.979603,39.627114],"即墨":[120.45,36.38],"抚顺":[123.97,41.97],"玉溪":[102.52,24.35],"张家口":[114.87,40.82],"阳泉":[113.57,37.85],"莱州":[119.942327,37.177017],"湖州":[120.1,30.86],"汕头":[116.69,23.39],"昆山":[120.95,31.39],"宁波":[121.56,29.86],"湛江":[110.359377,21.270708],"揭阳":[116.35,23.55],"荣成":[122.41,37.16],"连云港":[119.16,34.59],"葫芦岛":[120.836932,40.711052],"常熟":[120.74,31.64],"东莞":[113.75,23.04],"河源":[114.68,23.73],"淮安":[119.15,33.5],"泰州":[119.9,32.49],"南宁":[108.33,22.84],"营口":[122.18,40.65],"惠州":[114.4,23.09],"江阴":[120.26,31.91],"蓬莱":[120.75,37.8],"韶关":[113.62,24.84],"嘉峪关":[98.289152,39.77313],"广州":[113.23,23.16],"延安":[109.47,36.6],"太原":[112.53,37.87],"清远":[113.01,23.7],"中山":[113.38,22.52],"昆明":[102.73,25.04],"寿光":[118.73,36.86],"盘锦":[122.070714,41.119997],"长治":[113.08,36.18],"深圳":[114.07,22.62],"珠海":[113.52,22.3],"宿迁":[118.3,33.96],"咸阳":[108.72,34.36],"铜川":[109.11,35.09],"平度":[119.97,36.77],"佛山":[113.11,23.05],"海口":[110.35,20.02],"江门":[113.06,22.61],"章丘":[117.53,36.72],"肇庆":[112.44,23.05],"大连":[121.62,38.92],"临汾":[111.5,36.08],"吴江":[120.63,31.16],"石嘴山":[106.39,39.04],"沈阳":[123.38,41.8],"苏州":[120.62,31.32],"茂名":[110.88,21.68],"嘉兴":[120.76,30.77],"长春":[125.35,43.88],"胶州":[120.03336,36.264622],"银川":[106.27,38.47],"张家港":[120.555821,31.875428],"三门峡":[111.19,34.76],"锦州":[121.15,41.13],"南昌":[115.89,28.68],"柳州":[109.4,24.33],"三亚":[109.511909,18.252847],"自贡":[104.778442,29.33903],"吉林":[126.57,43.87],"阳江":[111.95,21.85],"泸州":[105.39,28.91],"西宁":[101.74,36.56],"宜宾":[104.56,29.77],"呼和浩特":[111.65,40.82],"成都":[104.06,30.67],"大同":[113.3,40.12],"镇江":[119.44,32.2],"桂林":[110.28,25.29],"张家界":[110.479191,29.117096],"宜兴":[119.82,31.36],"北海":[109.12,21.49],"西安":[108.95,34.27],"金坛":[119.56,31.74],"东营":[118.49,37.46],"牡丹江":[129.58,44.6],"遵义":[106.9,27.7],"绍兴":[120.58,30.01],"扬州":[119.42,32.39],"常州":[119.95,31.79],"潍坊":[119.1,36.62],"重庆":[106.54,29.59],"台州":[121.420757,28.656386],"南京":[118.78,32.04],"滨州":[118.03,37.36],"贵阳":[106.71,26.57],"无锡":[120.29,31.59],"本溪":[123.73,41.3],"克拉玛依":[84.77,45.59],"渭南":[109.5,34.52],"马鞍山":[118.48,31.56],"宝鸡":[107.15,34.38],"焦作":[113.21,35.24],"句容":[119.16,31.95],"北京":[116.46,39.92],"徐州":[117.2,34.26],"衡水":[115.72,37.72],"包头":[110,40.58],"绵阳":[104.73,31.48],"乌鲁木齐":[87.68,43.77],"枣庄":[117.57,34.86],"杭州":[120.19,30.26],"淄博":[118.05,36.78],"鞍山":[122.85,41.12],"溧阳":[119.48,31.43],"库尔勒":[86.06,41.68],"安阳":[114.35,36.1],"开封":[114.35,34.79],"济南":[117,36.65],"德阳":[104.37,31.13],"温州":[120.65,28.01],"九江":[115.97,29.71],"邯郸":[114.47,36.6],"临安":[119.72,30.23],"兰州":[103.73,36.03],"沧州":[116.83,38.33],"临沂":[118.35,35.05],"南充":[106.110698,30.837793],"天津":[117.2,39.13],"富阳":[119.95,30.07],"泰安":[117.13,36.18],"诸暨":[120.23,29.71],"郑州":[113.65,34.76],"哈尔滨":[126.63,45.75],"聊城":[115.97,36.45],"芜湖":[118.38,31.33],"唐山":[118.02,39.63],"平顶山":[113.29,33.75],"邢台":[114.48,37.05],"德州":[116.29,37.45],"济宁":[116.59,35.38],"荆州":[112.239741,30.335165],"宜昌":[111.3,30.7],"义乌":[120.06,29.32],"丽水":[119.92,28.45],"洛阳":[112.44,34.7],"秦皇岛":[119.57,39.95],"株洲":[113.16,27.83],"石家庄":[114.48,38.03],"莱芜":[117.67,36.19],"常德":[111.69,29.05],"保定":[115.48,38.85],"湘潭":[112.91,27.87],"金华":[119.64,29.12],"岳阳":[113.09,29.37],"长沙":[113,28.21],"衢州":[118.88,28.97],"廊坊":[116.7,39.53],"菏泽":[115.480656,35.23375],"合肥":[117.27,31.86],"武汉":[114.31,30.52],"大庆":[125.03,46.58]
};var convertData = function (data) {var res = [];for (var i = 0; i < data.length; i++) {var geoCoord = geoCoordMap[data[i].name];if (geoCoord) {res.push(geoCoord.concat(data[i].value));}}return res;
};option = {backgroundColor: '#404a59',title: {text: '全国主要城市空气质量',subtext: 'data from PM25.in',sublink: 'http://www.pm25.in',left: 'center',textStyle: {color: '#fff'}},tooltip: {trigger: 'item'},legend: {orient: 'vertical',top: 'bottom',left: 'right',data:['pm2.5'],textStyle: {color: '#fff'}},visualMap: {min: 0,max: 300,splitNumber: 5,color: ['#d94e5d','#eac736','#50a3ba'],textStyle: {color: '#fff'}},geo: {map: 'china',label: {emphasis: {show: false}},itemStyle: {normal: {areaColor: '#323c48',borderColor: '#111'},emphasis: {areaColor: '#2a333d'}}},series: [{name: 'pm2.5',type: 'scatter',coordinateSystem: 'geo',data: convertData([{name: "海门", value: 9},{name: "鄂尔多斯", value: 12},{name: "招远", value: 12},{name: "舟山", value: 12},{name: "齐齐哈尔", value: 14},{name: "盐城", value: 15},{name: "赤峰", value: 16},{name: "青岛", value: 18},{name: "乳山", value: 18},{name: "金昌", value: 19},{name: "泉州", value: 21},{name: "莱西", value: 21},{name: "日照", value: 21},{name: "胶南", value: 22},{name: "南通", value: 23},{name: "拉萨", value: 24},{name: "云浮", value: 24},{name: "梅州", value: 25},{name: "文登", value: 25},{name: "上海", value: 25},{name: "攀枝花", value: 25},{name: "威海", value: 25},{name: "承德", value: 25},{name: "厦门", value: 26},{name: "汕尾", value: 26},{name: "潮州", value: 26},{name: "丹东", value: 27},{name: "太仓", value: 27},{name: "曲靖", value: 27},{name: "烟台", value: 28},{name: "福州", value: 29},{name: "瓦房店", value: 30},{name: "即墨", value: 30},{name: "抚顺", value: 31},{name: "玉溪", value: 31},{name: "张家口", value: 31},{name: "阳泉", value: 31},{name: "莱州", value: 32},{name: "湖州", value: 32},{name: "汕头", value: 32},{name: "昆山", value: 33},{name: "宁波", value: 33},{name: "湛江", value: 33},{name: "揭阳", value: 34},{name: "荣成", value: 34},{name: "连云港", value: 35},{name: "葫芦岛", value: 35},{name: "常熟", value: 36},{name: "东莞", value: 36},{name: "河源", value: 36},{name: "淮安", value: 36},{name: "泰州", value: 36},{name: "南宁", value: 37},{name: "营口", value: 37},{name: "惠州", value: 37},{name: "江阴", value: 37},{name: "蓬莱", value: 37},{name: "韶关", value: 38},{name: "嘉峪关", value: 38},{name: "广州", value: 38},{name: "延安", value: 38},{name: "太原", value: 39},{name: "清远", value: 39},{name: "中山", value: 39},{name: "昆明", value: 39},{name: "寿光", value: 40},{name: "盘锦", value: 40},{name: "长治", value: 41},{name: "深圳", value: 41},{name: "珠海", value: 42},{name: "宿迁", value: 43},{name: "咸阳", value: 43},{name: "铜川", value: 44},{name: "平度", value: 44},{name: "佛山", value: 44},{name: "海口", value: 44},{name: "江门", value: 45},{name: "章丘", value: 45},{name: "肇庆", value: 46},{name: "大连", value: 47},{name: "临汾", value: 47},{name: "吴江", value: 47},{name: "石嘴山", value: 49},{name: "沈阳", value: 50},{name: "苏州", value: 50},{name: "茂名", value: 50},{name: "嘉兴", value: 51},{name: "长春", value: 51},{name: "胶州", value: 52},{name: "银川", value: 52},{name: "张家港", value: 52},{name: "三门峡", value: 53},{name: "锦州", value: 54},{name: "南昌", value: 54},{name: "柳州", value: 54},{name: "三亚", value: 54},{name: "自贡", value: 56},{name: "吉林", value: 56},{name: "阳江", value: 57},{name: "泸州", value: 57},{name: "西宁", value: 57},{name: "宜宾", value: 58},{name: "呼和浩特", value: 58},{name: "成都", value: 58},{name: "大同", value: 58},{name: "镇江", value: 59},{name: "桂林", value: 59},{name: "张家界", value: 59},{name: "宜兴", value: 59},{name: "北海", value: 60},{name: "西安", value: 61},{name: "金坛", value: 62},{name: "东营", value: 62},{name: "牡丹江", value: 63},{name: "遵义", value: 63},{name: "绍兴", value: 63},{name: "扬州", value: 64},{name: "常州", value: 64},{name: "潍坊", value: 65},{name: "重庆", value: 66},{name: "台州", value: 67},{name: "南京", value: 67},{name: "滨州", value: 70},{name: "贵阳", value: 71},{name: "无锡", value: 71},{name: "本溪", value: 71},{name: "克拉玛依", value: 72},{name: "渭南", value: 72},{name: "马鞍山", value: 72},{name: "宝鸡", value: 72},{name: "焦作", value: 75},{name: "句容", value: 75},{name: "北京", value: 79},{name: "徐州", value: 79},{name: "衡水", value: 80},{name: "包头", value: 80},{name: "绵阳", value: 80},{name: "乌鲁木齐", value: 84},{name: "枣庄", value: 84},{name: "杭州", value: 84},{name: "淄博", value: 85},{name: "鞍山", value: 86},{name: "溧阳", value: 86},{name: "库尔勒", value: 86},{name: "安阳", value: 90},{name: "开封", value: 90},{name: "济南", value: 92},{name: "德阳", value: 93},{name: "温州", value: 95},{name: "九江", value: 96},{name: "邯郸", value: 98},{name: "临安", value: 99},{name: "兰州", value: 99},{name: "沧州", value: 100},{name: "临沂", value: 103},{name: "南充", value: 104},{name: "天津", value: 105},{name: "富阳", value: 106},{name: "泰安", value: 112},{name: "诸暨", value: 112},{name: "郑州", value: 113},{name: "哈尔滨", value: 114},{name: "聊城", value: 116},{name: "芜湖", value: 117},{name: "唐山", value: 119},{name: "平顶山", value: 119},{name: "邢台", value: 119},{name: "德州", value: 120},{name: "济宁", value: 120},{name: "荆州", value: 127},{name: "宜昌", value: 130},{name: "义乌", value: 132},{name: "丽水", value: 133},{name: "洛阳", value: 134},{name: "秦皇岛", value: 136},{name: "株洲", value: 143},{name: "石家庄", value: 147},{name: "莱芜", value: 148},{name: "常德", value: 152},{name: "保定", value: 153},{name: "湘潭", value: 154},{name: "金华", value: 157},{name: "岳阳", value: 169},{name: "长沙", value: 175},{name: "衢州", value: 177},{name: "廊坊", value: 193},{name: "菏泽", value: 194},{name: "合肥", value: 229},{name: "武汉", value: 273},{name: "大庆", value: 279}]),symbolSize: 12,label: {normal: {show: false},emphasis: {show: false}},itemStyle: {emphasis: {borderColor: '#fff',borderWidth: 1}}}]
};
if (option && typeof option === "object") {myChart.setOption(option, true);
}</script></body>
</html>
视觉映射方式的配置
visualMap 中可以指定数据的指定维度映射到对应的视觉元素上。
option = {visualMap: [{type: 'piecewise'min: 0,max: 5000,dimension: 3, // series.data 的第四个维度(即 value[3])被映射seriesIndex: 4, // 对第四个系列进行映射。inRange: { // 选中范围中的视觉配置color: ['blue', '#121122', 'red'], // 定义了图形颜色映射的颜色列表,// 数据最小值映射到'blue'上,// 最大值映射到'red'上,// 其余自动线性计算。symbolSize: [30, 100] // 定义了图形尺寸的映射范围,// 数据最小值映射到30上,// 最大值映射到100上,// 其余自动线性计算。},outOfRange: { // 选中范围外的视觉配置symbolSize: [30, 100]}},...]
};
option = {visualMap: [{...,inRange: { // 选中范围中的视觉配置colorLightness: [0.2, 1], // 映射到明暗度上。也就是对本来的颜色进行明暗度处理。// 本来的颜色可能是从全局色板中选取的颜色,visualMap组件并不关心。symbolSize: [30, 100]},...},...]
};
ECharts 事件处理
ECharts 中我们可以通过监听用户的操作行为来回调对应的函数。
ECharts 通过 on 方法来监听用户的行为,例如监控用户的点击行为。
ECharts 中事件分为两种类型:
用户鼠标操作点击,如 'click'、'dblclick'、'mousedown'、'mousemove'、'mouseup'、'mouseover'、'mouseout'、'globalout'、'contextmenu' 事件。
还有一种是用户在使用可以交互的组件后触发的行为事件,例如在切换图例开关时触发的 'legendselectchanged' 事件),数据区域缩放时触发的 'datazoom' 事件等等。
myChart.on('click', function (params) {// 在用户点击后控制台打印数据的名称console.log(params);
});myChart.on('legendselectchanged', function (params) {console.log(params);
});chart.on('click', 'series.line', function (params) {console.log(params);
});chart.on('mouseover', {seriesIndex: 1, name: 'xx'}, function (params) {console.log(params);
});
鼠标事件
ECharts 支持的鼠标事件类型,包括 'click'、'dblclick'、'mousedown'、'mousemove'、'mouseup'、'mouseover'、'mouseout'、'globalout'、'contextmenu' 事件。
以下实例在点击柱形图时会弹出对话框:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>ECharts 实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化ECharts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {xAxis: {data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]},yAxis: {},series: [{name: '销量',type: 'bar',data: [5, 20, 36, 10, 10, 20]}]};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);// 处理点击事件并且弹出数据名称myChart.on('click', function (params) {alert(params.name);});</script>
</body>
</html>
所有的鼠标事件包含参数 params,这是一个包含点击图形的数据信息的对象,格式如下:
{// 当前点击的图形元素所属的组件名称,// 其值如 'series'、'markLine'、'markPoint'、'timeLine' 等。componentType: string,// 系列类型。值可能为:'line'、'bar'、'pie' 等。当 componentType 为 'series' 时有意义。seriesType: string,// 系列在传入的 option.series 中的 index。当 componentType 为 'series' 时有意义。seriesIndex: number,// 系列名称。当 componentType 为 'series' 时有意义。seriesName: string,// 数据名,类目名name: string,// 数据在传入的 data 数组中的 indexdataIndex: number,// 传入的原始数据项data: Object,// sankey、graph 等图表同时含有 nodeData 和 edgeData 两种 data,// dataType 的值会是 'node' 或者 'edge',表示当前点击在 node 还是 edge 上。// 其他大部分图表中只有一种 data,dataType 无意义。dataType: string,// 传入的数据值value: number|Array// 数据图形的颜色。当 componentType 为 'series' 时有意义。color: string }
如何区分鼠标点击到了哪里:
myChart.on('click', function (params) {if (params.componentType === 'markPoint') {// 点击到了 markPoint 上if (params.seriesIndex === 5) {// 点击到了 index 为 5 的 series 的 markPoint 上。}}else if (params.componentType === 'series') {if (params.seriesType === 'graph') {if (params.dataType === 'edge') {// 点击到了 graph 的 edge(边)上。}else {// 点击到了 graph 的 node(节点)上。}}} });
使用 query 只对指定的组件的图形元素的触发回调:
chart.on(eventName, query, handler);
query 可为 string 或者 Object。
如果为 string 表示组件类型。格式可以是 'mainType' 或者 'mainType.subType'。例如:
chart.on('click', 'series', function () {...}); chart.on('click', 'series.line', function () {...}); chart.on('click', 'dataZoom', function () {...}); chart.on('click', 'xAxis.category', function () {...});
如果为 Object,可以包含以下一个或多个属性,每个属性都是可选的:
chart.setOption({// ...series: {// ...type: 'custom',renderItem: function (params, api) {return {type: 'group',children: [{type: 'circle',name: 'my_el',// ...}, {// ...}]}},data: [[12, 33]]} }) chart.on('mouseup', {element: 'my_el'}, function () {// name 为 'my_el' 的元素被 'mouseup' 时,此方法被回调。 });
代码触发 ECharts 中组件的行为
上面我们只说明了用户的交互操作,但有时候我们也会需要在程序里调用方法并触发图表的行为,比如显示 tooltip。
ECharts 通过 dispatchAction({ type: '' }) 来触发图表行为,统一管理了所有动作,也可以根据需要去记录用户的行为路径。
以上实例用于轮播饼图中的 tooltip:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>ECharts 实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="height: 100%;min-height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化ECharts实例var myChart = echarts.init(document.getElementById('main'));var app = {};option = null;// 指定图表的配置项和数据var option = {title : {text: '饼图程序调用高亮示例',x: 'center'},tooltip: {trigger: 'item',formatter: "{a} <br/>{b} : {c} ({d}%)"},legend: {orient: 'vertical',left: 'left',data: ['直接访问','邮件营销','联盟广告','视频广告','搜索引擎']},series : [{name: '访问来源',type: 'pie',radius : '55%',center: ['50%', '60%'],data:[{value:335, name:'直接访问'},{value:310, name:'邮件营销'},{value:234, name:'联盟广告'},{value:135, name:'视频广告'},{value:1548, name:'搜索引擎'}],itemStyle: {emphasis: {shadowBlur: 10,shadowOffsetX: 0,shadowColor: 'rgba(0, 0, 0, 0.5)'}}}]};app.currentIndex = -1;setInterval(function () {var dataLen = option.series[0].data.length;// 取消之前高亮的图形myChart.dispatchAction({type: 'downplay',seriesIndex: 0,dataIndex: app.currentIndex});app.currentIndex = (app.currentIndex + 1) % dataLen;// 高亮当前图形myChart.dispatchAction({type: 'highlight',seriesIndex: 0,dataIndex: app.currentIndex});// 显示 tooltipmyChart.dispatchAction({type: 'showTip',seriesIndex: 0,dataIndex: app.currentIndex});}, 1000);if (option && typeof option === "object") {myChart.setOption(option, true);}</script>
</body>
</html>
效果图:
ECharts 旭日图
旭日图(Sunburst)由多层的环形图组成,在数据结构上,内圈是外圈的父节点。因此,它既能像饼图一样表现局部和整体的占比,又能像矩形树图一样表现层级关系。
ECharts 创建旭日图很简单,只需要在 series 配置项中声明类型为 sunburst 即可,data 数据结构以树形结构声明,看下一个简单的实例:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>ECharts 实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {series: {type: 'sunburst',data: [{name: 'A',value: 10,children: [{value: 3,name: 'Aa'}, {value: 5,name: 'Ab'}]}, {name: 'B',children: [{name: 'Ba',value: 4}, {name: 'Bb',value: 2}]}, {name: 'C',value: 3}]}};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script>
</body>
</html>
效果图:
颜色等样式调整
默认情况下会使用全局调色盘 color 分配最内层的颜色,其余层则与其父元素同色。
在旭日图中,扇形块的颜色有以下三种设置方式:
- 在 series.data.itemStyle 中设置每个扇形块的样式。
- 在 series.levels.itemStyle 中设置每一层的样式。
- 在 series.itemStyle 中设置整个旭日图的样式。
上述三者的优先级是从高到低的,也就是说,配置了 series.data.itemStyle 的扇形块将会覆盖 series.levels.itemStyle 和 series.itemStyle 的设置。
下面,我们将整体的颜色设为灰色 #aaa,将最内层的颜色设为蓝色 blue,将 Aa、B 这两块设为红色 red。
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>ECharts 实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {series: {type: 'sunburst',data: [{name: 'A',value: 10,children: [{value: 3,name: 'Aa',itemStyle: {color: 'red'}}, {value: 5,name: 'Ab'}]}, {name: 'B',children: [{name: 'Ba',value: 4}, {name: 'Bb',value: 2}],itemStyle: {color: 'red'}}, {name: 'C',value: 3}],itemStyle: {color: '#aaa'},levels: [{// 留给数据下钻的节点属性}, {itemStyle: {color: 'blue'}}]}};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script>
</body>
</html>
按层配置样式是一个很常用的功能,能够很大程度上提高配置的效率。
数据下钻
旭日图默认支持数据下钻,也就是说,当点击了扇形块之后,将以该扇形块的数据作为根节点,进一步显示该数据的细节。
在数据下钻后,图形的中间会出现一个用于返回上一层的图形,该图形的样式可以通过 levels[0] 配置。
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>ECharts 实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));var data = [{name: 'Grandpa',children: [{name: 'Uncle Leo',value: 15,children: [{name: 'Cousin Jack',value: 2}, {name: 'Cousin Mary',value: 5,children: [{name: 'Jackson',value: 2}]}, {name: 'Cousin Ben',value: 4}]}, {name: 'Father',value: 10,children: [{name: 'Me',value: 5}, {name: 'Brother Peter',value: 1}]}]}, {name: 'Nancy',children: [{name: 'Uncle Nike',children: [{name: 'Cousin Betty',value: 1}, {name: 'Cousin Jenny',value: 2}]}]}];option = {series: {type: 'sunburst',// highlightPolicy: 'ancestor',data: data,radius: [0, '90%'],label: {rotate: 'radial'}}};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script>
</body>
</html>
如果不需要数据下钻功能,可以通过将 nodeClick 设置为 false 来关闭,也可以设为 'link',并将 data.link 设为点击扇形块对应打开的链接。
高亮相关扇形块
旭日图支持鼠标移动到某扇形块时,高亮相关数据块的操作,可以通过设置 highlightPolicy,包括以下几种高亮方式:
- 'descendant'(默认值):高亮鼠标移动所在扇形块与其后代元素;
- 'ancestor':高亮鼠标所在扇形块与其祖先元素;
- 'self':仅高亮鼠标所在扇形块;
- 'none':不会淡化(downplay)其他元素。
上面提到的"高亮",对于鼠标所在的扇形块,会使用 emphasis 样式;对于其他相关扇形块,则会使用 highlight 样式。通过这种方式,可以很方便地实现突出显示相关数据的需求。
具体来说,对于配置项:
itemStyle: {color: 'yellow',borderWidth: 2,emphasis: {color: 'red'},highlight: {color: 'orange'},downplay: {color: '#ccc'} }
highlightPolicy 为 'descendant':
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>ECharts 实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));option = {silent: true,series: {radius: ['15%', '95%'],center: ['50%', '60%'],type: 'sunburst',sort: null,highlightPolicy: 'descendant',data: [{value: 10,children: [{name: 'target',value: 4,children: [{value: 2,children: [{value: 1}]}, {value: 1}, {value: 0.5}]}, {value: 2}]}, {value: 4,children: [{children: [{value: 2}]}]}],label: {normal: {rotate: 'none',color: '#fff'}},levels: [],itemStyle: {color: 'yellow',borderWidth: 2},emphasis: {itemStyle: {color: 'red'}},highlight: {itemStyle: {color: 'orange'}},downplay: {itemStyle: {color: '#ccc'}}}};setTimeout(function () {myChart.dispatchAction({type: 'sunburstHighlight',targetNodeId: 'target'});});// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script>
</body>
</html>
highlightPolicy 为 'ancestor' :
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>ECharts 实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));option = {silent: true,series: {radius: ['15%', '95%'],center: ['50%', '60%'],type: 'sunburst',sort: null,highlightPolicy: 'ancestor',data: [{value: 10,children: [{value: 4,children: [{value: 2,children: [{name: 'target',value: 1}]}, {value: 1}, {value: 0.5}]}, {value: 2}]}, {value: 4,children: [{children: [{value: 2}]}]}],label: {normal: {rotate: 'none',color: '#fff'}},levels: [],itemStyle: {color: 'yellow',borderWidth: 2},emphasis: {itemStyle: {color: 'red'}},highlight: {itemStyle: {color: 'orange'}},downplay: {itemStyle: {color: '#ccc'}}}};setTimeout(function () {myChart.dispatchAction({type: 'sunburstHighlight',targetNodeId: 'target'});});// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script>
</body>
</html>
经典旭日图1
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>ECharts 实例</title><!-- 引入 echarts.js --><script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body><!-- 为ECharts准备一个具备大小(宽高)的Dom --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));var colors = ['#FFAE57', '#FF7853', '#EA5151', '#CC3F57', '#9A2555'];var bgColor = '#2E2733';var itemStyle = {star5: {color: colors[0]},star4: {color: colors[1]},star3: {color: colors[2]},star2: {color: colors[3]}};var data = [{name: '虚构',itemStyle: {normal: {color: colors[1]}},children: [{name: '小说',children: [{name: '5☆',children: [{name: '疼'}, {name: '慈悲'}, {name: '楼下的房客'}]}, {name: '4☆',children: [{name: '虚无的十字架'}, {name: '无声告白'}, {name: '童年的终结'}]}, {name: '3☆',children: [{name: '疯癫老人日记'}]}]}, {name: '其他',children: [{name: '5☆',children: [{name: '纳博科夫短篇小说全集'}]}, {name: '4☆',children: [{name: '安魂曲'}, {name: '人生拼图版'}]}, {name: '3☆',children: [{name: '比起爱你,我更需要你'}]}]}]}, {name: '非虚构',itemStyle: {color: colors[2]},children: [{name: '设计',children: [{name: '5☆',children: [{name: '无界面交互'}]}, {name: '4☆',children: [{name: '数字绘图的光照与渲染技术'}, {name: '日本建筑解剖书'}]}, {name: '3☆',children: [{name: '奇幻世界艺术\n&RPG地图绘制讲座'}]}]}, {name: '社科',children: [{name: '5☆',children: [{name: '痛点'}]}, {name: '4☆',children: [{name: '卓有成效的管理者'}, {name: '进化'}, {name: '后物欲时代的来临',}]}, {name: '3☆',children: [{name: '疯癫与文明'}]}]}, {name: '心理',children: [{name: '5☆',children: [{name: '我们时代的神经症人格'}]}, {name: '4☆',children: [{name: '皮格马利翁效应'}, {name: '受伤的人'}]}, {name: '3☆',}, {name: '2☆',children: [{name: '迷恋'}]}]}, {name: '居家',children: [{name: '4☆',children: [{name: '把房子住成家'}, {name: '只过必要生活'}, {name: '北欧简约风格'}]}]}, {name: '绘本',children: [{name: '5☆',children: [{name: '设计诗'}]}, {name: '4☆',children: [{name: '假如生活糊弄了你'}, {name: '博物学家的神秘动物图鉴'}]}, {name: '3☆',children: [{name: '方向'}]}]}, {name: '哲学',children: [{name: '4☆',children: [{name: '人生的智慧'}]}]}, {name: '技术',children: [{name: '5☆',children: [{name: '代码整洁之道'}]}, {name: '4☆',children: [{name: 'Three.js 开发指南'}]}]}]}];for (var j = 0; j < data.length; ++j) {var level1 = data[j].children;for (var i = 0; i < level1.length; ++i) {var block = level1[i].children;var bookScore = [];var bookScoreId;for (var star = 0; star < block.length; ++star) {var style = (function (name) {switch (name) {case '5☆':bookScoreId = 0;return itemStyle.star5;case '4☆':bookScoreId = 1;return itemStyle.star4;case '3☆':bookScoreId = 2;return itemStyle.star3;case '2☆':bookScoreId = 3;return itemStyle.star2;}})(block[star].name);block[star].label = {color: style.color,downplay: {opacity: 0.5}};if (block[star].children) {style = {opacity: 1,color: style.color};block[star].children.forEach(function (book) {book.value = 1;book.itemStyle = style;book.label = {color: style.color};var value = 1;if (bookScoreId === 0 || bookScoreId === 3) {value = 5;}if (bookScore[bookScoreId]) {bookScore[bookScoreId].value += value;}else {bookScore[bookScoreId] = {color: colors[bookScoreId],value: value};}});}}level1[i].itemStyle = {color: data[j].itemStyle.color};}}option = {backgroundColor: bgColor,color: colors,series: [{type: 'sunburst',center: ['50%', '48%'],data: data,sort: function (a, b) {if (a.depth === 1) {return b.getValue() - a.getValue();}else {return a.dataIndex - b.dataIndex;}},label: {rotate: 'radial',color: bgColor},itemStyle: {borderColor: bgColor,borderWidth: 2},levels: [{}, {r0: 0,r: 40,label: {rotate: 0}}, {r0: 40,r: 105}, {r0: 115,r: 140,itemStyle: {shadowBlur: 2,shadowColor: colors[2],color: 'transparent'},label: {rotate: 'tangential',fontSize: 10,color: colors[0]}}, {r0: 140,r: 145,itemStyle: {shadowBlur: 80,shadowColor: colors[0]},label: {position: 'outside',textShadowBlur: 5,textShadowColor: '#333',},downplay: {label: {opacity: 0.5}}}]}]};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script>
</body>
</html>
效果图: