活动公告

系统通知
05-18 21:22
系统通知
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,资源失效请在帖子内回复要求补档,会尽快处理!
10-23 09:31

echarts图表叠加文字技巧详解如何在不同图表类型中添加标签注释和数据说明提升数据可视化效果与用户体验

SunJu_FaceMall

3万

主题

2860

科技点

3万

积分

白金月票

碾压王

积分
32872

塔罗立华奏

<font color=白金月票" /> 发表于 2025-9-25 19:20:01 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
引言

在数据可视化领域,ECharts作为一款功能强大的图表库,被广泛应用于各类数据展示场景。然而,仅仅呈现图表本身往往不足以传达完整的信息,适当的文字标注、标签注释和数据说明能够极大地提升数据可视化的效果和用户体验。文字元素可以帮助观众更准确地理解数据含义、突出关键信息、提供额外上下文,从而使数据故事更加完整和有说服力。本文将详细介绍如何在ECharts的各种图表类型中巧妙地添加文字元素,以实现更高效、更美观的数据可视化。

ECharts文字标注基础

在深入探讨各种图表类型的文字标注技巧之前,我们需要了解ECharts中文字标注的基础知识和通用方法。

文字标注的基本配置

ECharts提供了多种方式来添加文字标注,其中最常用的是通过label和textStyle属性。以下是一个基本的文字标注配置示例:
  1. option = {
  2.   series: [{
  3.     type: 'bar',
  4.     data: [120, 200, 150, 80, 70, 110, 130],
  5.     label: {
  6.       show: true, // 显示标签
  7.       position: 'top', // 标签位置
  8.       formatter: '{c}', // 标签内容格式
  9.       textStyle: {
  10.         color: '#333', // 文字颜色
  11.         fontSize: 12, // 文字大小
  12.         fontWeight: 'bold' // 文字粗细
  13.       }
  14.     }
  15.   }]
  16. };
复制代码

标签位置控制

ECharts允许我们精确控制标签的位置,常用的位置选项包括:

• 'top'- 图形上方
• 'left'- 图形左侧
• 'right'- 图形右侧
• 'bottom'- 图形下方
• 'inside'- 图形内部
• 'insideLeft'- 图形内部左侧
• 'insideRight'- 图形内部右侧
• 'insideTop'- 图形内部上方
• 'insideBottom'- 图形内部下方
• [x, y]- 使用具体坐标定位

标签内容格式化

ECharts提供了强大的标签内容格式化功能,可以通过formatter属性实现。formatter可以是字符串模板或回调函数:
  1. // 字符串模板
  2. formatter: '{b}: {c}' // {b}表示数据名,{c}表示数据值
  3. // 回调函数
  4. formatter: function(params) {
  5.   // params是数据项的参数
  6.   return params.name + ': ' + params.value;
  7. }
复制代码

柱状图和条形图中的文字标注

柱状图和条形图是最常用的图表类型之一,合理的文字标注可以极大地提升其可读性和信息量。

基础数据标签

在柱状图中添加数据标签是最基本的需求:
  1. option = {
  2.   xAxis: {
  3.     type: 'category',
  4.     data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  5.   },
  6.   yAxis: {
  7.     type: 'value'
  8.   },
  9.   series: [{
  10.     data: [120, 200, 150, 80, 70, 110, 130],
  11.     type: 'bar',
  12.     label: {
  13.       show: true,
  14.       position: 'top',
  15.       formatter: '{c}'
  16.     }
  17.   }]
  18. };
复制代码

条件格式化标签

有时我们需要根据数据值的不同显示不同的标签格式:
  1. option = {
  2.   xAxis: {
  3.     type: 'category',
  4.     data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  5.   },
  6.   yAxis: {
  7.     type: 'value'
  8.   },
  9.   series: [{
  10.     data: [120, 200, 150, 80, 70, 110, 130],
  11.     type: 'bar',
  12.     label: {
  13.       show: true,
  14.       position: 'top',
  15.       formatter: function(params) {
  16.         // 如果值大于150,显示警告样式
  17.         if (params.value > 150) {
  18.           return '{a|' + params.value + '}';
  19.         }
  20.         return params.value;
  21.       },
  22.       rich: {
  23.         a: {
  24.           color: 'red',
  25.           fontWeight: 'bold'
  26.         }
  27.       }
  28.     }
  29.   }]
  30. };
复制代码

添加单位说明

为数据添加单位说明可以使数据更加清晰:
  1. option = {
  2.   xAxis: {
  3.     type: 'category',
  4.     data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  5.   },
  6.   yAxis: {
  7.     type: 'value',
  8.     axisLabel: {
  9.       formatter: '{value} °C' // 为Y轴添加单位
  10.     }
  11.   },
  12.   series: [{
  13.     data: [12, 20, 15, 8, 7, 11, 13],
  14.     type: 'bar',
  15.     label: {
  16.       show: true,
  17.       position: 'top',
  18.       formatter: '{c} °C' // 为数据标签添加单位
  19.     }
  20.   }]
  21. };
复制代码

堆叠柱状图的标签处理

堆叠柱状图的标签处理需要特别注意,通常我们需要显示总和或各部分的值:
  1. option = {
  2.   xAxis: {
  3.     type: 'category',
  4.     data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  5.   },
  6.   yAxis: {
  7.     type: 'value'
  8.   },
  9.   series: [
  10.     {
  11.       name: 'Email',
  12.       type: 'bar',
  13.       stack: 'total',
  14.       data: [120, 132, 101, 134, 90, 230, 210],
  15.       label: {
  16.         show: true,
  17.         position: 'inside',
  18.         formatter: '{c}'
  19.       }
  20.     },
  21.     {
  22.       name: 'Union Ads',
  23.       type: 'bar',
  24.       stack: 'total',
  25.       data: [220, 182, 191, 234, 290, 330, 310],
  26.       label: {
  27.         show: true,
  28.         position: 'inside',
  29.         formatter: '{c}'
  30.       }
  31.     },
  32.     {
  33.       name: 'Video Ads',
  34.       type: 'bar',
  35.       stack: 'total',
  36.       data: [150, 232, 201, 154, 190, 330, 410],
  37.       label: {
  38.         show: true,
  39.         position: 'inside',
  40.         formatter: '{c}'
  41.       }
  42.     },
  43.     {
  44.       name: 'Total',
  45.       type: 'bar',
  46.       stack: 'total',
  47.       data: [0, 0, 0, 0, 0, 0, 0], // 不显示柱子,只用于显示总和
  48.       label: {
  49.         show: true,
  50.         position: 'top',
  51.         formatter: function(params) {
  52.           // 计算总和
  53.           const sum = params.dataIndex === 0 ? 490 :
  54.                      params.dataIndex === 1 ? 546 :
  55.                      params.dataIndex === 2 ? 493 :
  56.                      params.dataIndex === 3 ? 522 :
  57.                      params.dataIndex === 4 ? 570 :
  58.                      params.dataIndex === 5 ? 890 :
  59.                      930;
  60.           return 'Total: ' + sum;
  61.         }
  62.       }
  63.     }
  64.   ]
  65. };
复制代码

折线图中的文字标注

折线图通常用于展示趋势变化,文字标注可以帮助突出关键点和变化。

数据点标注

在折线图中标注关键数据点:
  1. option = {
  2.   xAxis: {
  3.     type: 'category',
  4.     data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  5.   },
  6.   yAxis: {
  7.     type: 'value'
  8.   },
  9.   series: [{
  10.     data: [150, 230, 224, 218, 135, 147, 260],
  11.     type: 'line',
  12.     label: {
  13.       show: true,
  14.       position: 'top',
  15.       formatter: function(params) {
  16.         // 只在最高点和最低点显示标签
  17.         const data = [150, 230, 224, 218, 135, 147, 260];
  18.         const max = Math.max(...data);
  19.         const min = Math.min(...data);
  20.         if (params.value === max) {
  21.           return '{max|Max: ' + params.value + '}';
  22.         } else if (params.value === min) {
  23.           return '{min|Min: ' + params.value + '}';
  24.         }
  25.         return '';
  26.       },
  27.       rich: {
  28.         max: {
  29.           color: '#ff0000',
  30.           fontWeight: 'bold'
  31.         },
  32.         min: {
  33.           color: '#0000ff',
  34.           fontWeight: 'bold'
  35.         }
  36.       }
  37.     },
  38.     markPoint: {
  39.       data: [
  40.         {type: 'max', name: '最大值'},
  41.         {type: 'min', name: '最小值'}
  42.       ]
  43.     }
  44.   }]
  45. };
复制代码

趋势说明和预测

在折线图中添加趋势说明和预测:
  1. option = {
  2.   xAxis: {
  3.     type: 'category',
  4.     data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul']
  5.   },
  6.   yAxis: {
  7.     type: 'value'
  8.   },
  9.   series: [{
  10.     data: [820, 932, 901, 934, 1290, 1330, 1320],
  11.     type: 'line',
  12.     markLine: {
  13.       silent: true,
  14.       lineStyle: {
  15.         color: '#5470C6'
  16.       },
  17.       data: [
  18.         {
  19.           type: 'average',
  20.           name: '平均值'
  21.         }
  22.       ],
  23.       label: {
  24.         formatter: '平均值: {c}'
  25.       }
  26.     },
  27.     markArea: {
  28.       data: [
  29.         [
  30.           {
  31.             name: '预测区间',
  32.             xAxis: 'Jul',
  33.             itemStyle: {
  34.               color: 'rgba(255, 173, 177, 0.2)'
  35.             }
  36.           },
  37.           {
  38.             xAxis: 'Sep'
  39.           }
  40.         ]
  41.       ]
  42.     }
  43.   }]
  44. };
复制代码

多条折线的图例和标注

处理多条折线时的图例和标注:
  1. option = {
  2.   legend: {
  3.     data: ['Email', 'Union Ads', 'Video Ads', 'Direct']
  4.   },
  5.   xAxis: {
  6.     type: 'category',
  7.     data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  8.   },
  9.   yAxis: {
  10.     type: 'value'
  11.   },
  12.   series: [
  13.     {
  14.       name: 'Email',
  15.       type: 'line',
  16.       data: [120, 132, 101, 134, 90, 230, 210],
  17.       label: {
  18.         show: true,
  19.         position: 'top',
  20.         formatter: function(params) {
  21.           // 只在最后一个数据点显示标签
  22.           if (params.dataIndex === 6) {
  23.             return params.seriesName + ': ' + params.value;
  24.           }
  25.           return '';
  26.         }
  27.       }
  28.     },
  29.     {
  30.       name: 'Union Ads',
  31.       type: 'line',
  32.       data: [220, 182, 191, 234, 290, 330, 310],
  33.       label: {
  34.         show: true,
  35.         position: 'top',
  36.         formatter: function(params) {
  37.           if (params.dataIndex === 6) {
  38.             return params.seriesName + ': ' + params.value;
  39.           }
  40.           return '';
  41.         }
  42.       }
  43.     },
  44.     {
  45.       name: 'Video Ads',
  46.       type: 'line',
  47.       data: [150, 232, 201, 154, 190, 330, 410],
  48.       label: {
  49.         show: true,
  50.         position: 'top',
  51.         formatter: function(params) {
  52.           if (params.dataIndex === 6) {
  53.             return params.seriesName + ': ' + params.value;
  54.           }
  55.           return '';
  56.         }
  57.       }
  58.     },
  59.     {
  60.       name: 'Direct',
  61.       type: 'line',
  62.       data: [320, 332, 301, 334, 390, 330, 320],
  63.       label: {
  64.         show: true,
  65.         position: 'top',
  66.         formatter: function(params) {
  67.           if (params.dataIndex === 6) {
  68.             return params.seriesName + ': ' + params.value;
  69.           }
  70.           return '';
  71.         }
  72.       }
  73.     }
  74.   ]
  75. };
复制代码

饼图中的文字标注

饼图用于展示部分与整体的关系,文字标注可以帮助识别各个部分及其占比。

基础标签和引导线

在饼图中添加标签和引导线:
  1. option = {
  2.   series: [
  3.     {
  4.       name: '访问来源',
  5.       type: 'pie',
  6.       radius: '50%',
  7.       data: [
  8.         {value: 1048, name: '搜索引擎'},
  9.         {value: 735, name: '直接访问'},
  10.         {value: 580, name: '邮件营销'},
  11.         {value: 484, name: '联盟广告'},
  12.         {value: 300, name: '视频广告'}
  13.       ],
  14.       label: {
  15.         show: true,
  16.         formatter: '{b}: {c} ({d}%)' // {b}数据名,{c}数据值,{d}百分比
  17.       },
  18.       labelLine: {
  19.         show: true
  20.       }
  21.     }
  22.   ]
  23. };
复制代码

突出显示特定扇区

突出显示特定扇区并添加详细说明:
  1. option = {
  2.   series: [
  3.     {
  4.       name: '访问来源',
  5.       type: 'pie',
  6.       radius: ['40%', '70%'], // 环形图
  7.       avoidLabelOverlap: false,
  8.       itemStyle: {
  9.         borderRadius: 10,
  10.         borderColor: '#fff',
  11.         borderWidth: 2
  12.       },
  13.       label: {
  14.         show: false,
  15.         position: 'center'
  16.       },
  17.       emphasis: {
  18.         label: {
  19.           show: true,
  20.           fontSize: '40',
  21.           fontWeight: 'bold'
  22.         }
  23.       },
  24.       labelLine: {
  25.         show: false
  26.       },
  27.       data: [
  28.         {value: 1048, name: '搜索引擎'},
  29.         {value: 735, name: '直接访问'},
  30.         {value: 580, name: '邮件营销'},
  31.         {value: 484, name: '联盟广告'},
  32.         {value: 300, name: '视频广告'}
  33.       ]
  34.     }
  35.   ]
  36. };
复制代码

自定义富文本标签

使用富文本标签创建更丰富的饼图标注:
  1. option = {
  2.   series: [
  3.     {
  4.       name: '访问来源',
  5.       type: 'pie',
  6.       radius: ['40%', '70%'],
  7.       data: [
  8.         {value: 1048, name: '搜索引擎'},
  9.         {value: 735, name: '直接访问'},
  10.         {value: 580, name: '邮件营销'},
  11.         {value: 484, name: '联盟广告'},
  12.         {value: 300, name: '视频广告'}
  13.       ],
  14.       label: {
  15.         formatter: function(params) {
  16.           return [
  17.             '{name|' + params.name + '}',
  18.             '{value|' + params.value + '}',
  19.             '{percent|' + params.percent + '%}'
  20.           ].join('\n');
  21.         },
  22.         rich: {
  23.           name: {
  24.             fontSize: 16,
  25.             lineHeight: 22,
  26.             color: '#666'
  27.           },
  28.           value: {
  29.             fontSize: 18,
  30.             lineHeight: 22,
  31.             color: '#333',
  32.             fontWeight: 'bold'
  33.           },
  34.           percent: {
  35.             fontSize: 14,
  36.             lineHeight: 22,
  37.             color: '#999'
  38.           }
  39.         }
  40.       }
  41.     }
  42.   ]
  43. };
复制代码

散点图中的文字标注

散点图用于展示两个变量之间的关系,文字标注可以帮助识别特定数据点。

基础数据点标注

在散点图中标注数据点:
  1. option = {
  2.   xAxis: {},
  3.   yAxis: {},
  4.   series: [{
  5.     symbolSize: 20,
  6.     data: [
  7.       [10.0, 8.04],
  8.       [8.0, 6.95],
  9.       [13.0, 7.58],
  10.       [9.0, 8.81],
  11.       [11.0, 8.33],
  12.       [14.0, 9.96],
  13.       [6.0, 7.24],
  14.       [4.0, 4.26],
  15.       [12.0, 10.84],
  16.       [7.0, 4.82],
  17.       [5.0, 5.68]
  18.     ],
  19.     type: 'scatter',
  20.     label: {
  21.       show: true,
  22.       formatter: function(params) {
  23.         return '[' + params.data[0] + ', ' + params.data[1] + ']';
  24.       },
  25.       position: 'top'
  26.     }
  27.   }]
  28. };
复制代码

突出显示异常点

突出显示散点图中的异常点:
  1. option = {
  2.   xAxis: {},
  3.   yAxis: {},
  4.   series: [{
  5.     symbolSize: function (data) {
  6.       return Math.sqrt(data[2]) * 5;
  7.     },
  8.     data: [
  9.       [10.0, 8.04, 10],
  10.       [8.0, 6.95, 8],
  11.       [13.0, 7.58, 13],
  12.       [9.0, 8.81, 9],
  13.       [11.0, 8.33, 11],
  14.       [14.0, 9.96, 14],
  15.       [6.0, 7.24, 6],
  16.       [4.0, 4.26, 4],
  17.       [12.0, 10.84, 12],
  18.       [7.0, 4.82, 7],
  19.       [5.0, 5.68, 5]
  20.     ],
  21.     type: 'scatter',
  22.     label: {
  23.       show: true,
  24.       formatter: function(params) {
  25.         // 如果Y值大于9,标记为异常点
  26.         if (params.data[1] > 9) {
  27.           return '{abnormal|异常点}';
  28.         }
  29.         return '';
  30.       },
  31.       rich: {
  32.         abnormal: {
  33.           color: 'red',
  34.           fontWeight: 'bold'
  35.         }
  36.       }
  37.     },
  38.     itemStyle: {
  39.       color: function(params) {
  40.         // 异常点使用红色
  41.         if (params.data[1] > 9) {
  42.           return 'red';
  43.         }
  44.         return '#5470C6';
  45.       }
  46.     }
  47.   }]
  48. };
复制代码

添加分类标签

为散点图添加分类标签:
  1. option = {
  2.   xAxis: {},
  3.   yAxis: {},
  4.   legend: {
  5.     data: ['类别A', '类别B', '类别C']
  6.   },
  7.   series: [
  8.     {
  9.       name: '类别A',
  10.       type: 'scatter',
  11.       data: [
  12.         [1.0, 2.0],
  13.         [1.2, 1.8],
  14.         [1.5, 2.2],
  15.         [1.8, 1.5]
  16.       ],
  17.       label: {
  18.         show: true,
  19.         formatter: 'A',
  20.         position: 'inside'
  21.       }
  22.     },
  23.     {
  24.       name: '类别B',
  25.       type: 'scatter',
  26.       data: [
  27.         [3.0, 4.0],
  28.         [3.2, 3.8],
  29.         [3.5, 4.2],
  30.         [3.8, 3.5]
  31.       ],
  32.       label: {
  33.         show: true,
  34.         formatter: 'B',
  35.         position: 'inside'
  36.       }
  37.     },
  38.     {
  39.       name: '类别C',
  40.       type: 'scatter',
  41.       data: [
  42.         [5.0, 6.0],
  43.         [5.2, 5.8],
  44.         [5.5, 6.2],
  45.         [5.8, 5.5]
  46.       ],
  47.       label: {
  48.         show: true,
  49.         formatter: 'C',
  50.         position: 'inside'
  51.       }
  52.     }
  53.   ]
  54. };
复制代码

地图中的文字标注

地图可视化中,文字标注对于识别地理位置和展示区域数据至关重要。

基础地图标注

在地图中添加基础标注:
  1. // 假设已经加载了中国地图数据
  2. option = {
  3.   geo: {
  4.     map: 'china',
  5.     label: {
  6.       show: true
  7.     },
  8.     itemStyle: {
  9.       areaColor: '#eee',
  10.       borderColor: '#777'
  11.     }
  12.   },
  13.   series: [
  14.     {
  15.       type: 'scatter',
  16.       coordinateSystem: 'geo',
  17.       data: [
  18.         {name: '北京', value: [116.46, 39.92, 100]},
  19.         {name: '上海', value: [121.48, 31.22, 80]},
  20.         {name: '广州', value: [113.23, 23.16, 60]},
  21.         {name: '深圳', value: [114.07, 22.62, 50]}
  22.       ],
  23.       symbolSize: function (val) {
  24.         return val[2] / 10;
  25.       },
  26.       label: {
  27.         show: true,
  28.         formatter: '{b}'
  29.       }
  30.     }
  31.   ]
  32. };
复制代码

自定义区域标签

自定义地图区域的标签样式:
  1. option = {
  2.   geo: {
  3.     map: 'china',
  4.     label: {
  5.       show: true,
  6.       color: '#333',
  7.       fontSize: 12,
  8.       formatter: function(params) {
  9.         // 只显示特定省份的标签
  10.         const provinces = ['北京', '上海', '广东', '浙江'];
  11.         if (provinces.includes(params.name)) {
  12.           return params.name;
  13.         }
  14.         return '';
  15.       }
  16.     },
  17.     itemStyle: {
  18.       areaColor: '#eee',
  19.       borderColor: '#777'
  20.     },
  21.     emphasis: {
  22.       label: {
  23.         show: true,
  24.         color: '#fff',
  25.         fontSize: 14,
  26.         fontWeight: 'bold'
  27.       },
  28.       itemStyle: {
  29.         areaColor: '#389BB7'
  30.       }
  31.     }
  32.   },
  33.   series: [
  34.     {
  35.       type: 'map',
  36.       map: 'china',
  37.       geoIndex: 0,
  38.       data: [
  39.         {name: '北京', value: 100},
  40.         {name: '上海', value: 80},
  41.         {name: '广东', value: 60},
  42.         {name: '浙江', value: 50}
  43.       ],
  44.       label: {
  45.         show: false
  46.       }
  47.     }
  48.   ]
  49. };
复制代码

添加数据标签和说明

在地图中添加数据标签和说明:
  1. option = {
  2.   geo: {
  3.     map: 'china',
  4.     label: {
  5.       show: false
  6.     },
  7.     itemStyle: {
  8.       areaColor: '#eee',
  9.       borderColor: '#777'
  10.     }
  11.   },
  12.   series: [
  13.     {
  14.       type: 'map',
  15.       map: 'china',
  16.       geoIndex: 0,
  17.       data: [
  18.         {name: '北京', value: 100},
  19.         {name: '上海', value: 80},
  20.         {name: '广东', value: 60},
  21.         {name: '浙江', value: 50}
  22.       ],
  23.       label: {
  24.         show: true,
  25.         formatter: function(params) {
  26.           return params.name + '\n{value|' + params.value + '}';
  27.         },
  28.         rich: {
  29.           value: {
  30.             color: '#fff',
  31.             fontSize: 14,
  32.             fontWeight: 'bold',
  33.             backgroundColor: 'rgba(0,0,0,0.5)',
  34.             padding: [2, 4],
  35.             borderRadius: 2
  36.           }
  37.         }
  38.       },
  39.       emphasis: {
  40.         label: {
  41.           show: true,
  42.           formatter: function(params) {
  43.             return params.name + '\n{value|' + params.value + '}';
  44.           },
  45.           rich: {
  46.             value: {
  47.               color: '#fff',
  48.               fontSize: 16,
  49.               fontWeight: 'bold',
  50.               backgroundColor: 'rgba(0,0,0,0.7)',
  51.               padding: [3, 6],
  52.               borderRadius: 3
  53.             }
  54.           }
  55.         }
  56.       }
  57.     }
  58.   ]
  59. };
复制代码

高级文字标注技巧

掌握了基础图表类型的文字标注方法后,我们可以探索一些更高级的技巧,以创建更具吸引力和信息量的可视化效果。

动态文字标注

动态更新文字标注,实现数据变化时的平滑过渡:
  1. // 初始数据
  2. let data = [120, 200, 150, 80, 70, 110, 130];
  3. // 初始化图表
  4. const myChart = echarts.init(document.getElementById('chart'));
  5. const option = {
  6.   xAxis: {
  7.     type: 'category',
  8.     data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  9.   },
  10.   yAxis: {
  11.     type: 'value'
  12.   },
  13.   series: [{
  14.     data: data,
  15.     type: 'bar',
  16.     label: {
  17.       show: true,
  18.       position: 'top',
  19.       formatter: function(params) {
  20.         // 动态计算变化百分比
  21.         if (params.dataIndex > 0) {
  22.           const prevValue = data[params.dataIndex - 1];
  23.           const currentValue = params.value;
  24.           const changePercent = ((currentValue - prevValue) / prevValue * 100).toFixed(1);
  25.          
  26.           if (parseFloat(changePercent) > 0) {
  27.             return '{value|' + currentValue + '}\n{up|↑ ' + changePercent + '%}';
  28.           } else if (parseFloat(changePercent) < 0) {
  29.             return '{value|' + currentValue + '}\n{down|↓ ' + Math.abs(changePercent) + '%}';
  30.           } else {
  31.             return '{value|' + currentValue + '}\n{equal|— ' + changePercent + '%}';
  32.           }
  33.         }
  34.         return '{value|' + params.value + '}';
  35.       },
  36.       rich: {
  37.         value: {
  38.           fontSize: 14,
  39.           fontWeight: 'bold'
  40.         },
  41.         up: {
  42.           color: '#ff0000'
  43.         },
  44.         down: {
  45.           color: '#00ff00'
  46.         },
  47.         equal: {
  48.           color: '#888888'
  49.         }
  50.       }
  51.     }
  52.   }]
  53. };
  54. myChart.setOption(option);
  55. // 模拟数据更新
  56. setInterval(() => {
  57.   // 随机更新一个数据点
  58.   const index = Math.floor(Math.random() * data.length);
  59.   const change = Math.floor(Math.random() * 50) - 25; // -25到25之间的随机变化
  60.   data[index] = Math.max(10, data[index] + change); // 确保值不小于10
  61.   
  62.   // 更新图表
  63.   myChart.setOption({
  64.     series: [{
  65.       data: data
  66.     }]
  67.   });
  68. }, 2000);
复制代码

交互式文字标注

实现与用户交互的文字标注效果:
  1. option = {
  2.   xAxis: {
  3.     type: 'category',
  4.     data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  5.   },
  6.   yAxis: {
  7.     type: 'value'
  8.   },
  9.   series: [{
  10.     data: [120, 200, 150, 80, 70, 110, 130],
  11.     type: 'bar',
  12.     label: {
  13.       show: true,
  14.       position: 'top',
  15.       formatter: function(params) {
  16.         return params.value;
  17.       }
  18.     }
  19.   }],
  20.   tooltip: {
  21.     trigger: 'axis',
  22.     axisPointer: {
  23.       type: 'shadow'
  24.     },
  25.     formatter: function(params) {
  26.       // 自定义tooltip内容
  27.       let result = params[0].name + '<br/>';
  28.       params.forEach(item => {
  29.         // 计算占总和的百分比
  30.         const total = params.reduce((sum, p) => sum + p.value, 0);
  31.         const percent = (item.value / total * 100).toFixed(1);
  32.         result += item.marker + item.seriesName + ': ' + item.value + ' (' + percent + '%)<br/>';
  33.       });
  34.       return result;
  35.     }
  36.   }
  37. };
  38. // 添加点击事件
  39. myChart.on('click', function(params) {
  40.   // 点击时显示详细信息
  41.   const detail = document.getElementById('detail');
  42.   detail.innerHTML = `
  43.     <h3>${params.name}</h3>
  44.     <p>数值: ${params.value}</p>
  45.     <p>数据索引: ${params.dataIndex}</p>
  46.     <p>系列名称: ${params.seriesName}</p>
  47.   `;
  48. });
复制代码

自定义文字样式和动画

使用富文本和动画效果增强文字标注:
  1. option = {
  2.   xAxis: {
  3.     type: 'category',
  4.     data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  5.   },
  6.   yAxis: {
  7.     type: 'value'
  8.   },
  9.   series: [{
  10.     data: [120, 200, 150, 80, 70, 110, 130],
  11.     type: 'bar',
  12.     label: {
  13.       show: true,
  14.       position: 'top',
  15.       distance: 10,
  16.       formatter: function(params) {
  17.         // 使用富文本创建复杂标签
  18.         return [
  19.           '{title|' + params.name + '}',
  20.           '{value|' + params.value + '}'
  21.         ].join('\n');
  22.       },
  23.       rich: {
  24.         title: {
  25.           color: '#333',
  26.           fontSize: 12,
  27.           lineHeight: 16,
  28.           align: 'center'
  29.         },
  30.         value: {
  31.           color: '#5470C6',
  32.           fontSize: 16,
  33.           fontWeight: 'bold',
  34.           lineHeight: 20,
  35.           align: 'center',
  36.           textBorderColor: '#fff',
  37.           textBorderWidth: 2
  38.         }
  39.       },
  40.       // 添加动画效果
  41.       animationDuration: 1000,
  42.       animationEasing: 'elasticOut'
  43.     },
  44.     itemStyle: {
  45.       color: function(params) {
  46.         // 根据值设置不同颜色
  47.         const colorList = ['#5470C6', '#91CC75', '#FAC858', '#EE6666', '#73C0DE', '#3BA272', '#FC8452'];
  48.         return colorList[params.dataIndex % colorList.length];
  49.       }
  50.     }
  51.   }]
  52. };
复制代码

文字标注的最佳实践

在实际应用中,合理使用文字标注可以显著提升数据可视化的效果。以下是一些最佳实践建议:

1. 保持简洁明了

文字标注应该简洁明了,避免过多文字干扰视觉体验:
  1. // 不好的做法:标签内容过多
  2. label: {
  3.   show: true,
  4.   formatter: '2023年销售数据: {c}万元,同比增长15.3%,环比增长2.1%'
  5. }
  6. // 好的做法:标签内容简洁
  7. label: {
  8.   show: true,
  9.   formatter: '{c}万元'
  10. }
复制代码

2. 合理使用颜色和样式

通过颜色和样式区分不同类型的文字信息:
  1. option = {
  2.   xAxis: {
  3.     type: 'category',
  4.     data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  5.   },
  6.   yAxis: {
  7.     type: 'value'
  8.   },
  9.   series: [{
  10.     data: [120, 200, 150, 80, 70, 110, 130],
  11.     type: 'bar',
  12.     label: {
  13.       show: true,
  14.       position: 'top',
  15.       formatter: function(params) {
  16.         // 使用不同颜色区分高于和低于平均值的数据
  17.         const avg = 130; // 平均值
  18.         if (params.value > avg) {
  19.           return '{high|' + params.value + '}';
  20.         } else if (params.value < avg) {
  21.           return '{low|' + params.value + '}';
  22.         } else {
  23.           return '{equal|' + params.value + '}';
  24.         }
  25.       },
  26.       rich: {
  27.         high: {
  28.           color: '#ff0000',
  29.           fontWeight: 'bold'
  30.         },
  31.         low: {
  32.           color: '#0000ff'
  33.         },
  34.         equal: {
  35.           color: '#888888'
  36.         }
  37.       }
  38.     }
  39.   }]
  40. };
复制代码

3. 避免标签重叠

当数据点较多时,避免标签重叠影响可读性:
  1. option = {
  2.   xAxis: {
  3.     type: 'category',
  4.     data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
  5.   },
  6.   yAxis: {
  7.     type: 'value'
  8.   },
  9.   series: [{
  10.     data: [120, 200, 150, 80, 70, 110, 130, 90, 160, 100, 140, 180],
  11.     type: 'line',
  12.     label: {
  13.       show: true,
  14.       position: 'top',
  15.       // 使用rotate避免标签重叠
  16.       rotate: 45,
  17.       // 或者使用formatter选择性显示标签
  18.       formatter: function(params) {
  19.         // 只显示最高点和最低点的标签
  20.         const data = [120, 200, 150, 80, 70, 110, 130, 90, 160, 100, 140, 180];
  21.         const max = Math.max(...data);
  22.         const min = Math.min(...data);
  23.         if (params.value === max || params.value === min) {
  24.           return params.value;
  25.         }
  26.         return '';
  27.       }
  28.     }
  29.   }]
  30. };
复制代码

4. 提供上下文信息

为文字标注提供必要的上下文信息,帮助用户理解数据:
  1. option = {
  2.   title: {
  3.     text: '2023年月度销售额',
  4.     subtext: '单位:万元'
  5.   },
  6.   xAxis: {
  7.     type: 'category',
  8.     data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
  9.   },
  10.   yAxis: {
  11.     type: 'value',
  12.     name: '销售额(万元)'
  13.   },
  14.   series: [{
  15.     data: [120, 200, 150, 80, 70, 110, 130, 90, 160, 100, 140, 180],
  16.     type: 'bar',
  17.     label: {
  18.       show: true,
  19.       position: 'top',
  20.       formatter: function(params) {
  21.         // 添加同比变化信息
  22.         const lastYearData = [100, 180, 130, 90, 60, 100, 120, 80, 140, 90, 120, 150];
  23.         const change = params.value - lastYearData[params.dataIndex];
  24.         const changePercent = (change / lastYearData[params.dataIndex] * 100).toFixed(1);
  25.         
  26.         if (change > 0) {
  27.           return params.value + '\n{up|↑ ' + changePercent + '%}';
  28.         } else if (change < 0) {
  29.           return params.value + '\n{down|↓ ' + Math.abs(changePercent) + '%}';
  30.         } else {
  31.           return params.value + '\n{equal|— 0%}';
  32.         }
  33.       },
  34.       rich: {
  35.         up: {
  36.           color: '#ff0000',
  37.           fontSize: 10
  38.         },
  39.         down: {
  40.           color: '#00ff00',
  41.           fontSize: 10
  42.         },
  43.         equal: {
  44.           color: '#888888',
  45.           fontSize: 10
  46.         }
  47.       }
  48.     }
  49.   }]
  50. };
复制代码

5. 考虑可访问性

确保文字标注对所有人都是可访问的,包括视力障碍用户:
  1. option = {
  2.   xAxis: {
  3.     type: 'category',
  4.     data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  5.   },
  6.   yAxis: {
  7.     type: 'value'
  8.   },
  9.   series: [{
  10.     data: [120, 200, 150, 80, 70, 110, 130],
  11.     type: 'bar',
  12.     label: {
  13.       show: true,
  14.       position: 'top',
  15.       // 使用较大的字体和足够的对比度
  16.       textStyle: {
  17.         color: '#000000', // 深色文字
  18.         fontSize: 14, // 较大的字体
  19.         fontWeight: 'bold' // 加粗文字
  20.       },
  21.       // 提供完整的上下文信息
  22.       formatter: function(params) {
  23.         return params.name + ': ' + params.value + '万元';
  24.       }
  25.     },
  26.     // 为色盲用户提供额外的视觉区分
  27.     itemStyle: {
  28.       color: function(params) {
  29.         // 使用色盲友好的颜色方案
  30.         const colorList = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2'];
  31.         return colorList[params.dataIndex % colorList.length];
  32.       }
  33.     }
  34.   }]
  35. };
复制代码

案例分析:实际项目中的应用

为了更好地理解文字标注在实际项目中的应用,让我们分析一个综合案例:一个销售数据仪表板。

案例背景

假设我们需要创建一个销售数据仪表板,展示不同产品类别在不同地区的销售情况,包括销售额、同比增长率、市场份额等关键指标。

完整实现
  1. // 初始化图表
  2. const myChart = echarts.init(document.getElementById('dashboard'));
  3. // 模拟数据
  4. const salesData = {
  5.   categories: ['电子产品', '服装', '食品', '家居', '图书'],
  6.   regions: ['华东', '华南', '华北', '西南', '东北'],
  7.   currentYear: [
  8.     [1200, 900, 800, 600, 400], // 电子产品
  9.     [800, 700, 600, 500, 300],  // 服装
  10.     [600, 500, 400, 300, 200],  // 食品
  11.     [500, 400, 300, 200, 100],  // 家居
  12.     [300, 200, 100, 50, 30]     // 图书
  13.   ],
  14.   lastYear: [
  15.     [1000, 800, 700, 500, 300], // 电子产品
  16.     [700, 600, 500, 400, 200],  // 服装
  17.     [500, 400, 300, 200, 100],  // 食品
  18.     [400, 300, 200, 100, 50],   // 家居
  19.     [200, 100, 50, 30, 20]      // 图书
  20.   ]
  21. };
  22. // 计算同比增长率
  23. const growthRates = salesData.currentYear.map((category, i) => {
  24.   return category.map((value, j) => {
  25.     return ((value - salesData.lastYear[i][j]) / salesData.lastYear[i][j] * 100).toFixed(1);
  26.   });
  27. });
  28. // 计算每个地区的总销售额
  29. const regionTotals = salesData.regions.map((_, j) => {
  30.   return salesData.currentYear.reduce((sum, category) => sum + category[j], 0);
  31. });
  32. // 计算每个产品类别的市场份额
  33. const marketShares = salesData.currentYear.map((category, i) => {
  34.   const categoryTotal = category.reduce((sum, value) => sum + value, 0);
  35.   const grandTotal = regionTotals.reduce((sum, value) => sum + value, 0);
  36.   return (categoryTotal / grandTotal * 100).toFixed(1);
  37. });
  38. // 图表配置
  39. const option = {
  40.   title: {
  41.     text: '2023年销售数据仪表板',
  42.     subtext: '单位:万元',
  43.     left: 'center'
  44.   },
  45.   tooltip: {
  46.     trigger: 'axis',
  47.     axisPointer: {
  48.       type: 'shadow'
  49.     },
  50.     formatter: function(params) {
  51.       let result = params[0].axisValue + '<br/>';
  52.       params.forEach(item => {
  53.         const categoryIndex = item.seriesIndex;
  54.         const regionIndex = item.dataIndex;
  55.         const growthRate = growthRates[categoryIndex][regionIndex];
  56.         result += item.marker + item.seriesName + ': ' + item.value + '万元 (';
  57.         result += growthRate > 0 ? '+' : '';
  58.         result += growthRate + '%)<br/>';
  59.       });
  60.       return result;
  61.     }
  62.   },
  63.   legend: {
  64.     data: salesData.categories,
  65.     top: '8%'
  66.   },
  67.   grid: {
  68.     left: '3%',
  69.     right: '4%',
  70.     bottom: '15%',
  71.     top: '15%',
  72.     containLabel: true
  73.   },
  74.   xAxis: {
  75.     type: 'category',
  76.     data: salesData.regions,
  77.     axisLabel: {
  78.       interval: 0,
  79.       rotate: 30
  80.     }
  81.   },
  82.   yAxis: {
  83.     type: 'value',
  84.     name: '销售额(万元)'
  85.   },
  86.   series: salesData.categories.map((category, i) => {
  87.     return {
  88.       name: category,
  89.       type: 'bar',
  90.       stack: 'total',
  91.       data: salesData.currentYear[i],
  92.       label: {
  93.         show: true,
  94.         position: 'inside',
  95.         formatter: function(params) {
  96.           // 只显示大于500的值,避免标签重叠
  97.           return params.value > 500 ? params.value : '';
  98.         }
  99.       },
  100.       emphasis: {
  101.         focus: 'series'
  102.       },
  103.       // 根据市场份额设置颜色深浅
  104.       itemStyle: {
  105.         color: function() {
  106.           const colors = ['#5470C6', '#91CC75', '#FAC858', '#EE6666', '#73C0DE'];
  107.           const baseColor = colors[i % colors.length];
  108.           // 市场份额越大,颜色越深
  109.           const share = parseFloat(marketShares[i]);
  110.           const opacity = 0.3 + (share / 50) * 0.7; // 0.3到1之间的透明度
  111.           return baseColor.replace(')', `, ${opacity})`).replace('rgb', 'rgba');
  112.         }
  113.       }
  114.     };
  115.   }),
  116.   // 添加市场份额标注
  117.   graphic: salesData.categories.map((category, i) => {
  118.     return {
  119.       type: 'text',
  120.       left: (i * 20 + 10) + '%',
  121.       top: '92%',
  122.       style: {
  123.         text: category + ': ' + marketShares[i] + '%',
  124.         font: '12px sans-serif',
  125.         fill: '#666'
  126.       }
  127.     };
  128.   }),
  129.   // 添加同比增长率标注
  130.   markPoint: {
  131.     symbol: 'pin',
  132.     symbolSize: 50,
  133.     data: salesData.categories.flatMap((category, i) => {
  134.       return salesData.regions.map((region, j) => {
  135.         const growthRate = parseFloat(growthRates[i][j]);
  136.         // 只标注增长率超过20%或低于-10%的数据点
  137.         if (growthRate > 20 || growthRate < -10) {
  138.           return {
  139.             name: category + ' ' + region,
  140.             coord: [j, salesData.currentYear[i][j]],
  141.             value: growthRate > 0 ? '+' + growthRate + '%' : growthRate + '%',
  142.             itemStyle: {
  143.               color: growthRate > 0 ? '#ff0000' : '#0000ff'
  144.             }
  145.           };
  146.         }
  147.         return null;
  148.       }).filter(item => item !== null);
  149.     })
  150.   }
  151. };
  152. // 应用配置
  153. myChart.setOption(option);
  154. // 添加交互事件
  155. myChart.on('click', function(params) {
  156.   const categoryIndex = params.seriesIndex;
  157.   const regionIndex = params.dataIndex;
  158.   
  159.   // 显示详细信息
  160.   const detail = document.getElementById('detail');
  161.   detail.innerHTML = `
  162.     <h3>${params.seriesName} - ${params.name}</h3>
  163.     <p>当前年销售额: ${params.value}万元</p>
  164.     <p>去年销售额: ${salesData.lastYear[categoryIndex][regionIndex]}万元</p>
  165.     <p>同比增长: ${growthRates[categoryIndex][regionIndex]}%</p>
  166.     <p>市场份额: ${marketShares[categoryIndex]}%</p>
  167.   `;
  168. });
  169. // 响应式调整
  170. window.addEventListener('resize', function() {
  171.   myChart.resize();
  172. });
复制代码

案例分析

这个综合案例展示了如何在实际项目中应用各种文字标注技巧:

1. 多层次信息展示:基础数据标签显示销售额markPoint标注异常增长率graphic元素展示市场份额tooltip提供详细交互信息
2. 基础数据标签显示销售额
3. markPoint标注异常增长率
4. graphic元素展示市场份额
5. tooltip提供详细交互信息
6. 视觉层次:使用颜色深浅表示市场份额大小使用不同颜色区分正负增长率使用标签位置和大小创建视觉层次
7. 使用颜色深浅表示市场份额大小
8. 使用不同颜色区分正负增长率
9. 使用标签位置和大小创建视觉层次
10. 交互设计:点击事件显示详细信息tooltip提供上下文信息响应式设计适应不同屏幕
11. 点击事件显示详细信息
12. tooltip提供上下文信息
13. 响应式设计适应不同屏幕
14. 数据关系展示:通过堆叠柱状图展示部分与整体关系通过增长率标注展示时间趋势通过市场份额标注展示竞争格局
15. 通过堆叠柱状图展示部分与整体关系
16. 通过增长率标注展示时间趋势
17. 通过市场份额标注展示竞争格局

多层次信息展示:

• 基础数据标签显示销售额
• markPoint标注异常增长率
• graphic元素展示市场份额
• tooltip提供详细交互信息

视觉层次:

• 使用颜色深浅表示市场份额大小
• 使用不同颜色区分正负增长率
• 使用标签位置和大小创建视觉层次

交互设计:

• 点击事件显示详细信息
• tooltip提供上下文信息
• 响应式设计适应不同屏幕

数据关系展示:

• 通过堆叠柱状图展示部分与整体关系
• 通过增长率标注展示时间趋势
• 通过市场份额标注展示竞争格局

总结

在ECharts中,文字标注是提升数据可视化效果和用户体验的关键元素。通过本文的详细介绍,我们了解了如何在各种图表类型中添加标签注释和数据说明,包括:

1. 基础文字标注技术:包括标签位置控制、内容格式化和样式设置。
2. 不同图表类型的文字标注技巧:针对柱状图、折线图、饼图、散点图和地图等不同图表类型的特点,提供了相应的文字标注方法。
3. 高级文字标注技巧:包括动态标注、交互式标注和自定义样式等高级应用。
4. 文字标注的最佳实践:强调了简洁明了、合理使用颜色、避免重叠、提供上下文信息和考虑可访问性等原则。
5. 实际案例分析:通过一个综合的销售数据仪表板案例,展示了如何在实际项目中应用各种文字标注技巧。

合理运用这些技巧,可以显著提升数据可视化的效果,使数据故事更加完整、准确和有说服力。在实际应用中,我们需要根据具体的数据特点和用户需求,灵活选择和组合不同的文字标注方法,以达到最佳的视觉效果和用户体验。

最后,随着数据可视化技术的不断发展,ECharts也在不断更新和完善其文字标注功能。作为开发者,我们应该保持学习和探索的态度,不断尝试新的技术和方法,以创建更加优秀的数据可视化作品。
「七転び八起き(ななころびやおき)」
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则