#在51CTO的第一篇博文#
这是一篇新人文章
自我介绍
hello 大家好!很高兴来到51CTO博客。目前从事前端开发五年有余,以前主要在酒店文旅行业工作,主要做一些酒店管理系统和酒店预订小程序、APP等;受疫情影响公司裁员,目前主要深耕web可视化、大屏数据展示,使用到的技术主要Vue3, canvas,SVG多一点,框架方面Ecahrts,G2, G6, D3等都使用,个人喜欢用antV系列多一点。但图表性能方面,感觉还是echarts要强一点。以上纯属个人喜好,如有异议,以你的为准。 希望在这里能学到更多的知识,并且能够写出优秀的博客。
技术分享
1.echarts 折柱线混合label互相遮挡
这种折柱混合图形,当label经常容易重叠。
Echarts 解决方案>>>
series-bar.labelLayout.moveOverlap
在标签重叠的时候是否挪动标签位置以防止重叠。
目前支持配置为:
'shiftX' 水平方向依次位移,在水平方向对齐时使用
'shiftY' 垂直方向依次位移,在垂直方向对齐时使用
个人亲测尝试了一下,目前这个API主要主要针对同一个series系列有一定的优化作用,不同系列间的label无法解决。
G2 解决方案>>>
overlapDodgeY 位置碰撞的标签在 y 方向上进行调整,防止标签重叠。
chart
.line()
.encode('x', 'letter')
.encode('y', 'frequency')
.encode('color', 'type')
/* ... */
.label({
text: 'frequency',
transform: [
{
type: 'overlapDodgeY',
},
],
});
个人也写了一个demo测试了一下,没有深入的了解。G2可以解决同类型的label重叠问题, 比如说多条折线图之间label重叠,但是它也还是不能优化折柱混合label之间的重合问题。当然G2还有一些其它针对优化可做选择,比如:
overflowHide 对于标签在图形上放置不下的时候,隐藏标签。
overlapHide 对位置碰撞的标签进行隐藏。算法逻辑是碰撞的两个标签,保留前一个,隐藏后一个。
还可以自定义碰撞优化方法。
me
受echarts和G2处理这种label碰撞优化方案启发,只考虑折柱混合这种情况。
series-bar.labelLayout 属性
标签的统一布局配置。
该配置项是在每个系列默认的标签布局基础上,统一调整标签的(x, y)位置,标签对齐等属性以实现想要的标签布局效果。
该配置项也可以是一个有如下参数的回调函数
/ 标签对应数据的 dataIndex
dataIndex: number
// 标签对应的数据类型,只在关系图中会有 node 和 edge 数据类型的区分
dataType?: string
// 标签对应的系列的 index
seriesIndex: number
// 标签显示的文本
text: string
// 默认的标签的包围盒,由系列默认的标签布局决定
labelRect: {x: number, y: number, width: number, height: number}
// 默认的标签水平对齐
align: 'left' | 'center' | 'right'
// 默认的标签垂直对齐
verticalAlign: 'top' | 'middle' | 'bottom'
// 标签所对应的数据图形的包围盒,可用于定位标签位置
rect: {x: number, y: number, width: number, height: number}
// 默认引导线的位置,目前只有饼图(pie)和漏斗图(funnel)有默认标签位置
// 如果没有该值则为 null
labelLinePoints?: number[][]
Echarts提供的labelLayout回调,可以取到当前label的位置(x,y)和宽高(w,h),并返回新的坐标(x,y)。 当series=[bar, line],
第一步
echarts根据series顺序先渲染bar-x1、bar-x2、bar-x3..., 此时将[bar-x1,bar-x2,bar-x3...]label的坐标位置存储起来。
第二步
echarts 渲染完bar组件,开始渲染line-x1, line-x2, line-x3..., 此时判断 line-x1的label是否和bar-x1的label是否碰撞,
第三步
若bar-x1与line-x1碰撞,则修改line-x1坐标位置并返回
demo代码
/**
* 处理多series系列, 不同系列之间label重叠
* @param barSeries
*/
export function lineLabelLayout(barSeries) {
const _labelList = { 0: {} }
barSeries.forEach(item => {
item.labelLayout = param => {
const xy = layout(param)
return {
x: xy?.x || param.labelRect.x,
y: xy?.y || param.labelRect.y
}
}
})
function layout(params) {
// labelRect: {x: number, y: number, width: number, height: number} 默认的标签的包围盒,由系列默认的标签布局决定 从左上角开始算起
const { dataIndex, seriesIndex, labelRect, rect } = params
if (dataIndex === undefined) {
return
}
const labelSeriesIndex = _labelList[seriesIndex] || {}
if (seriesIndex === 0) {
// 第一系列,直接添加并返回
labelSeriesIndex[dataIndex] = { ...params }
_labelList[0][dataIndex] = { ...params }
return { x: labelRect.x, y: labelRect.y }
} else if (seriesIndex === 1) {
// 非第一系列,
const preSeries = _labelList[0][dataIndex]
const preY = preSeries.labelRect.y
const y = labelRect.y
const diff = y - preY
const maxDiff = Math.max(preSeries.labelRect.height, labelRect.height)
let newY = labelRect.y
// 判断 两个系列的label Y轴上是否存重叠
// todo 只处理了,两个系列 Y轴上的重叠; 多系列参考 left/right, top/bottom设置修改
if (Math.abs(diff) <= maxDiff) {
if (diff < 0) {
newY = y - (maxDiff + diff) - 2
} else {
newY = y + (maxDiff - diff) + 2
}
}
return { x: labelRect.x, y: newY }
}
}
return barSeries
}
flag!
明天更好!