SVG线重合部分被覆盖问题
一、场景介绍
后台有接口提供类似以下的xml数据(部分数据省略):
<graph>
<root>
<node id="nodeA" property="value">
<name>Node A</name>
</node>
<node id="nodeB" property="value">
<name>Node B</name>
</node>
<node id="nodeC" property="value">
<name>Node C</name>
</node>
<link id="linkAC" source="nodeA" target="nodeC"/>
<link id="linkBC" source="nodeB" target="nodeC"/>
</root>
</graph>
发送到前端后,在前端渲染为svg格式的图形(已流转的线被设置为红色),如下:
<svg width="400" height="240" viewBox="0 0 400 240">
<rect id="nodeA" x="40" y="25" width="80" height="50" rx="5" ry="5" style="fill:none;stroke:#4da4fb;stroke-width:2;"/>
<text x="50" y="55" fill="black">Node A</text>
<rect id="nodeB" x="280" y="25" width="80" height="50" rx="5" ry="5" style="fill:none;stroke:#4da4fb;stroke-width:2;"/>
<text x="292" y="55" fill="black">Node B</text>
<rect id="nodeC" x="160" y="180" width="80" height="50" rx="5" ry="5" style="fill:none;stroke:#4da4fb;stroke-width:2;"/>
<text x="173" y="212" fill="black">Node C</text>
<polyline id="linkAC" points="120,50 200,50 200,180" style="fill:none;stroke:red;stroke-width:2;"/>
<polyline id="linkBC" points="280,50 200,50 200,180" style="fill:none;stroke:black;stroke-width:2;"/>
</svg>
二、问题
如上图所示,由于此图形是先画了A与C之间的连线,然后才画的B与C之间的连线,因此在图形中看到的是连线BC与连线AC重合的一段是显示连线BC的颜色,但实际是需要显示完整的当前流转的线(例如:AC之间的线应该全为红色)。
三、解决方法
为了解决上述问题,特意看了下前端的解析过程:是按xml节点的顺序解析,只要保证解析线时它的source和target已被解析就行。 因此对于此问题可以在后端通过接口拿到数据后,找到已流转的连线,将它移动到最后;此时需要使用XPath查询。
1、需要的jar
-
Dom4J
-
Jaxen
2、使用
- 模拟接口
public static Node getGraphNode() throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read(XmlTest.class.getResourceAsStream("../../graph.xml"));
return document;
}
如上所示,该接口返回一个Node。
- 使用
selectSingleNode
查询
Node selectSingleNode(java.lang.String xpathExpression)
Node node = getGraphNode();
//<graph>
Element graph = node.getDocument().getRootElement();
//<root>
Element root = (Element) graph.selectSingleNode("root");
selectSingleNode
中直接用nodename查询表示:选取此节点的所有子节点。但如果此节点有多个(例如从root中查找node节点),此方法返回第一个满足条件的节点。
对于使用XPath查找linkAC这条线有多种方式,举例两种:
-
第一种:
Node linkAC = graph.selectSingleNode("//link[@id=\"linkAC\"]");
-
//
从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
-
[@id="xxx"]
过滤出id为xxx的节点
-
-
第二种:
Node linkAC = graph.selectSingleNode("/graph/root/link[@id=\"linkAC\"]");
-
/
从根节点选取。
-
-
移动节点
我没有找到能移动节点的方法,因此先将找到的节点remove
,然后再使用add
添加。
root.remove(linkAC);
root.add(linkAC);
注意:此处调用移除和添加方法的是查找到节点的父节点。
再调用root.asXML()
,可以看到linkAC
已被移动到了最后:
<link id="linkAB" source="nodeA" target="nodeB"/>
<link id="linkAC" source="nodeA" target="nodeC"/>
在前端渲染后也就得到了想要的效果: