0%

图表元素拾取扩大热区范围方案

背景

针对在如何在图表编辑器场景下快速索引图元所对应的方案,我们得到了ECharts图元拾取方案。但图表场景通常具有很多【线条】类型的图元,这些图元宽度普遍不高,通常为【1-2】个像素宽度。这就给通过交互的方式来拾取图元造成了一定的困扰,不容易选取、很容易移出热区。本文探究一种图表元素拾取扩大热区范围方案。

image-20230704102535628

核心思路

核心思路其实很简单一句话概括的话就是:通过后期在图元上插入一个透明的图层,并绑定与图元相同的事件,来达到扩大图元拾取热曲的效果。

具体方案

SVG后处理-插入透明图层

具体方案并不复杂,大致步骤为:

  1. 遍历图表的SVG元素,识别其中path元素
  2. 克隆path节点
  3. 修改克隆节点的【线宽】、【透明度】等属性
  4. 将克隆节点插入原节点上方

其中关于svgVisitor相关可以参阅:SVG后处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
* 创建 隐藏透明图层 用于单像素的图元筛选
*
* @param {*} chartContextDom 图表的外层Dom
*/
export const createShadowSvg = function (chartContextDom) {
const chartSVGs = chartContextDom.querySelectorAll("svg");
for (let i = 0; i < chartSVGs.length; i++) {
svgVisitor(chartSVGs[i], {
// 遍历图表的 path 元素
pathVisitor: function (pathDom) {
const elTargets = pathDom.getAttribute("elTarget");
const strokeWidth = pathDom.getAttribute("stroke-width");
// 识别echart图元,未识别的到的图元不处理。
if (!elTargets) return;
// 线宽大于 SHADOW_STROKE_WIDTH 的不处理
if (strokeWidth && parseInt(strokeWidth) >= DEFAULT_SHADOW_STROKE_WIDTH)
return;
// 线宽为0的不处理
if (parseInt(strokeWidth) === 0) return;
// symbol类型的不处理
const elTargetObject = JSON.parse(elTargets);
if (elTargetObject.element === "symbol") return;

// 拷贝节点
const cloneNode = pathDom.cloneNode();
// 设置私有属性 isShadow 为 true 以便区分 热区与真是的图元Dom
cloneNode.setAttribute("isShadow", true);
// 线条颜色为透明
cloneNode.setAttribute("stroke", "transparent");
// 填充颜色为透明
cloneNode.setAttribute("fill-opacity", "0");

// 这里针对不同的场景 设置了不同的热区宽度
if (elTargetObject.component === "series") {
cloneNode.setAttribute("stroke-width", SERIES_SHADOW_STROKE_WIDTH);
} else {
cloneNode.setAttribute("stroke-width", DEFAULT_SHADOW_STROKE_WIDTH);
}
// 设置鼠标指示器样式
cloneNode.setAttribute("style", "cursor: pointer");
const dasharray = cloneNode.getAttribute("stroke-dasharray");
if (dasharray) {
cloneNode.removeAttribute("stroke-dasharray");
}
// 将用于拾取的热区Dom插入原节点上层
pathDom.parentNode.insertBefore(cloneNode, pathDom);
},
});
}
};

参考 & 引用

ECharts图元拾取方案 | SZ 博客 (sz-p.cn)

SVG后处理 | SZ 博客 (sz-p.cn)