如何在ECharts散点图中独立分组展示两组标签
在Angular中实现ECharts分组标签独立避重的散点图
问题描述
在Angular项目中使用ECharts创建包含大量数据的交互式散点图,需在同一张图内展示两组数据点:一组标签固定在图表顶部区域,另一组固定在数据点下方区域。使用labelLayout的moveOverlap: 'shiftX'配置解决标签重叠时,发现该配置会全局检测X轴方向的所有标签重叠,导致上下区域的标签互相干扰,出现不合理的水平偏移,显示效果怪异且性能低下。尝试过拆分网格、坐标轴、系列等方式,仍无法实现对两组标签分别应用shiftX避重规则。
可行解决方案
核心思路是利用ECharts的labelLayout自定义能力,手动划分标签分组区域,仅对同一区域内的标签进行重叠检测和偏移处理,不同区域标签互不干扰。
步骤1:标记标签分组
通过系列索引(seriesIndex)为两组标签划分独立分组,分别存储每组标签的位置和宽度信息。
步骤2:实现分组内的自定义避重逻辑
放弃全局moveOverlap配置,在labelLayout函数中手动计算同组标签的位置,仅调整同组内重叠标签的X坐标:
- 收集同组内所有标签的初始位置与宽度
- 按X轴坐标排序后,依次调整标签位置,避免与同组前一个标签重叠
- 返回调整后的最终位置
修改后的完整代码
const data = [ [[28604,77,17096869,'Australia',1990],[31163,77.4,27662440,'Canada',1990],[1516,68,1154605773,'China',1990],[13670,74.7,10582082,'Cuba',1990],[28599,75,4986705,'Finland',1990],[29476,77.1,56943299,'France',1990],[31476,75.4,78958237,'Germany',1990],[28666,78.1,254830,'Iceland',1990],[1777,57.7,870601776,'India',1990],[29550,79.1,122249285,'Japan',1990],[2076,67.9,20194354,'North Korea',1990],[12087,72,42972254,'South Korea',1990],[24021,75.4,3397534,'New Zealand',1990],[43296,76.8,4240375,'Norway',1990],[10088,70.8,38195258,'Poland',1990],[19349,69.6,147568552,'Russia',1990],[10670,67.3,53994605,'Turkey',1990],[26424,75.7,57110117,'United Kingdom',1990],[37062,75.4,252847810,'United States',1990]], [[44056,81.8,23968973,'Australia',2015],[43294,81.7,35939927,'Canada',2015],[13334,76.9,1376048943,'China',2015],[21291,78.5,11389562,'Cuba',2015],[38923,80.8,5503457,'Finland',2015],[37599,81.9,64395345,'France',2015],[44053,81.1,80688545,'Germany',2015],[42182,82.8,329425,'Iceland',2015],[5903,66.8,1311050527,'India',2015],[36162,83.5,126573481,'Japan',2015],[1390,71.4,25155317,'North Korea',2015],[34644,80.7,50293439,'South Korea',2015],[34186,80.6,4528526,'New Zealand',2015],[64304,81.6,5210967,'Norway',2015],[24787,77.3,38611794,'Poland',2015],[23038,73.13,143456918,'Russia',2015],[19360,76.5,78665830,'Turkey',2015],[38225,81.4,64715810,'United Kingdom',2015],[53354,79.1,321773631,'United States',2015]] ]; // 存储两组标签的位置与宽度,实现分组隔离 const groupLabelInfo = { 0: [], // 顶部区域标签组 1: [] // 底部区域标签组 }; option = { xAxis: [ { splitLine: { show: false } }, { splitLine: { show: false } } ], yAxis: [ { splitLine: { show: false }, scale: true }, { splitLine: { show: false }, scale: true } ], grid: { left: 40, right: 130 }, series: [ { name: '1990', data: data[0], xAxisIndex: 0, yAxisIndex: 0, type: 'scatter', symbolSize: (data: any) => Math.sqrt(data[2]) / 5e2, emphasis: { focus: 'self' }, labelLayout: (param: any) => { const groupIndex = 0; const labelWidth = param.labelRect.width; const targetY = param.chart.getHeight() - 750; let targetX = param.x; // 同组内标签避重 const sameGroupLabels = groupLabelInfo[groupIndex]; if (sameGroupLabels.length > 0) { const lastLabel = sameGroupLabels[sameGroupLabels.length - 1]; const minGap = 5; // 标签间最小间距 const overlapOffset = lastLabel.x + lastLabel.width + minGap - targetX; if (overlapOffset > 0) { targetX += overlapOffset; } } sameGroupLabels.push({ x: targetX, width: labelWidth }); return { x: targetX, y: targetY }; }, labelLine: { show: true, lineStyle: { color: '#bbb' } }, label: { show: true, formatter: (param: any) => param.data[3], position: 'right', minMargin: 2 } }, { name: '2015', data: data[1], xAxisIndex: 1, yAxisIndex: 1, type: 'scatter', symbolSize: (data: any) => Math.sqrt(data[2]) / 5e2, emphasis: { focus: 'self' }, labelLayout: (param: any) => { const groupIndex = 1; const labelWidth = param.labelRect.width; const targetY = param.chart.getHeight() - 30; let targetX = param.x; // 同组内标签避重 const sameGroupLabels = groupLabelInfo[groupIndex]; if (sameGroupLabels.length > 0) { const lastLabel = sameGroupLabels[sameGroupLabels.length - 1]; const minGap = 5; const overlapOffset = lastLabel.x + lastLabel.width + minGap - targetX; if (overlapOffset > 0) { targetX += overlapOffset; } } sameGroupLabels.push({ x: targetX, width: labelWidth }); return { x: targetX, y: targetY }; }, labelLine: { show: true, lineStyle: { color: '#bbb' } }, label: { show: true, formatter: (param: any) => param.data[3], position: 'right', minMargin: 2 } } ] };
方案说明
- 通过
groupLabelInfo对象隔离两组标签的位置数据,避免跨区域干扰 - 自定义
minGap参数可调整标签间的最小间距,保证可读性 - 仅对同组标签进行重叠检测,相比全局配置提升了性能
- 保留了原需求中标签固定在顶部/底部区域的布局逻辑
内容的提问来源于stack exchange,提问作者bleujaiz
相关产品推荐
相关产品推荐

