跳到主要内容

后处理:动态修改markLine.label的位置

问题场景

​ 例如Demo所示,在某折线图中有一条x轴方向水平移动,从y起始点指向终点的标记线markLine,在markLine的起点处有一个附着在Line元素上的Text元素(label标签),标记线本身会随鼠标点击的位置,选取最近的x轴索引更新水平位置,但是在markLine水平移动的过程中,下方的label标签可能会超出图表,所以希望label标签能够根据markLine的水平位置动态设置文字的偏移量,在整体与markLine居中对齐的前提下让label标签保持在图表画布内。

解决方案

实现思路一

​ 通过扩展生命周期节点afterupdate,在echarts流程完成之后,手动计算label标签应有的偏移量,并在视图层修改label图形元素的位置属性,然后在修改后的下一帧刷新图形视图。

​ 这一思路的流程并不复杂,但在实现细节上可能会有部分困难。在计算label标签的偏移量时,我们需要同时拿到两个位置信息才能获取偏移量:markLine依赖的series依赖的坐标系(依赖链为:markLine依赖series, series依赖coordinateSystem)对应的绘制区域的包围盒信息(x, y, width, height);另一个是label标签元素在全局绘制区域下的包围盒信息。其中,坐标系的包围盒信息较容易获取,只需要如下即可:----ecIns表示图表实例对象, 部分API可查看相关文档----

// 通过seriesModel获取其依赖的坐标系对应的包围盒信息
// 1、遍历所有seriesModel或者查找特定seriesModel,找到seriesModel对应的坐标系对象
const ecModel = ecIns.getModel();
const lineModel = ecModel.getSeriesByType('line')[0];
const coordSys = seriesModel.coordinateSystem;
const gridRect = coordSys.getArea(); // 格式为:{x: 0, y: 0, width: 100, height: 100}

// gridArea对象本身还可以充当BoundingRect进行transform坐标变换操作
class BoundingRect {
x: number;
y: number;
width: number;
height: number;
/*以及各种矩阵计算相关的api*/
}

​ 其次,标签的包围盒信息需要在元素的树结构上获取,其中width,height信息获取相对容易,可以通过如下方法拿到:

/* 首先拿到对应标签的元素对象:
附属于某个系列seriesModel的标记线markLine的图形元素,存储在markLineView下的group.childAt(seriesIndex).childAt(0)中,
其中seriesIndex表示该系列的索引。
*/
const seriesIndex = 0;
const ecModel = ecIns.getModel();
const markLineModel = ecModel.getComponent('markLine', 0);
const markLineView = ecIns.getViewOfComponentModel(markLineModel);
const label = markLineView.group.childAt(seriesIndex).childAt(0);

// 通过label.getPaintRect()方法能够获取label元素准确的width和height信息,但是该方法提供的x和y具有滞后性,每次获取的xy坐标都是上次视图刷新前的坐标,因此该坐标不可用。
const paintRect = label.getPaintRect();
// 准确获取xy坐标的方法可参考如下方案
const { x, y } = label;


​ 最后,我们需要将计算出来的偏移量修改到视图元素上,并在下一帧刷新图形元素。修改label图形元素的位置属性上可能会出现问题:

原因

待整理/解决