是否有一种方法可以使用Javascript合并两个路径元素(svg)

Is there a way to merge two path elements (svg) using Javascript?

本文关键字:合并 两个 路径 svg 元素 Javascript 可以使 一种 是否 方法      更新时间:2023-09-26

我使用SVG绘制了两条路径线,并将这些元素保存到javascript代码中的两个变量中:'Line1'和'Line2',我需要将这两条线合并为一个路径元素。有办法吗?

路径是相对定义的(小写字母)还是绝对定义的(大写字母)?如果是绝对的,则连接两个路径是微不足道的,只需附加d属性的值即可。如果你有两个这样的路径:

<path id="Line1" d="M50,50
         A30,30 0 0,1 35,20
         L100,100"
      style="stroke:#660000; fill:none;"/>
<path id="Line2" d="M110,110
         L100,0"
      style="stroke:#660000; fill:none;"/>

然后这个JavaScript代码:

var Line1 = document.getElementById("Line1");
var Line2 = document.getElementById("Line2");
//Add paths together
Line1.setAttribute('d', Line1.getAttribute('d') + ' ' + Line2.getAttribute('d'));
//Remove unnecessary second path
Line2.parentNode.removeChild(Line2);

将导致您拥有像这样的单个路径:

<path id="Line1" d="M50,50
         A30,30 0 0,1 35,20
         L100,100 M110,110
         L100,0"
      style="stroke:#660000; fill:none;"/>

这是一个jsFiddle,它在Firefox 4中工作(需要一个HTML5解析器,所以你可以有内联SVG)。

如果你的路径是相对的,那么你必须在附加的路径之间添加一些东西,以便第二个路径在正确的位置开始

连接d属性

通常,您可以将多个<path>元素的pathdata d属性连接起来,得到一个组合路径。

不幸的是,您可能会遇到一些»不良做法«使用Mm作为可互换的命令。

关于Mm的常见误解:

  • M (moveto)可以是绝对的或相对的。
    不像z (closepath)命令(小写/大写-不重要)。
    相对m命令可用于复合路径,例如内部"hole"字母"o";参考前一个命令的结束坐标。
  • 事实上,每个第一个 mM命令都使用绝对坐标-因为没有前面的点
  • 但是,M的第一个命令可以是大写或小写——这无关紧要
    (怪规格)
  • 例外:小写的m命令引入了一行隐式的相对l lineto命令。(但你也可以/应该避免这种情况)

示例1:以(不必要的)relative m command

开头的路径

svg{
  border:1px solid #ccc;
  width:25%;
}
path{
  fill:#555;
}
<p>Seperate paths</p>
<svg viewBox="0 0 50 10">
  <path id="path1" d="m 20 0 l 10 0 l 0 10 l -10 0z" />
  <path id="path2" d="m 40 0 l 10 0 l 0 10 l -10 0z" />
  <path id="path3" d="m 0 0 l 10 0 l 0 10 l -10 0z" />
</svg>
<p>Merged paths</p>
<svg viewBox="0 0 50 10">
  <path id="pathConcat" 
  d="
 m 20 0 l 10 0 l 0 10 l -10 0z 
 m 40 0 l 10 0 l 0 10 l -10 0z
 m 0 0 l 10 0 l 0 10 l -10 0z
 " />
</svg>
<p>Merged paths - fixed</p>
<svg viewBox="0 0 50 10">
  <path id="pathConcat" 
  d="
 M 20 0 l 10 0 l 0 10 l -10 0z 
 M 40 0 l 10 0 l 0 10 l -10 0z
 M 0 0 l 10 0 l 0 10 l -10 0z
 " />
</svg>

修复:只需将每个开始的m替换为绝对的M

示例2:相邻行

m命令

例外是m命令后面跟着坐标——用作l(相对行符)之后的简写。(参见w3c规范)

svg{
  border:1px solid #ccc;
  width:25%;
}
path{
  fill:#555;
}
<p>Seperate paths</p>
<svg viewBox="0 0 50 10">
  <path id="path1" d="m 20 0  10 0  0 10  -10 0z" />
  <path id="path2" d="m 40 0  10 0  0 10  -10 0z" />
  <path id="path3" d="m 0 0  10 0  0 10  -10 0z" />
</svg>
<p>Merged paths</p>
<svg viewBox="0 0 50 10">
  <path id="pathConcat" 
  d="
 m 20 0  10 0  0 10  -10 0z 
 m 40 0  10 0  0 10  -10 0z
 m 0 0  10 0  0 10  -10 0z
 " />
</svg>
<p>Merged paths - fixed</p>
<svg viewBox="0 0 50 10">
  <path id="pathConcat" 
  d="
 m 20 0  10 0  0 10  -10 0z 
 M 40 0  l 10 0  0 10  -10 0z
 M 0 0  l 10 0  0 10  -10 0z
 " />
</svg>

修复:插入l命令
<path d="m 20 0  10 0  0 10  -10 0z" />

=

<path d="M 20 0 l 10 0 l 0 10 l -10 0z" />  

<path d="M 20 0 l 10 0  0 10 -10 0z" />

示例3:通过getPathData()修复伪相对m命令

目前仍然是一个草案,不支持原生的主要浏览器。
但是你可以使用Jarek Foksa的polyfill.

getPathData()将返回一个命令对象数组并进行规范化像这样重复命令:

[
  {type: 'm', values:[20, 0] },
  {type: 'l', values:[10, 0]},
  {type: 'l', values:[0, 10]},
  {type: 'l', values:[-10, 0]}
]

function concatSimple(){
  let d1= path1.getAttribute('d')
  let d2= path2.getAttribute('d')
  let d3= path3.getAttribute('d')
  pathConcat.setAttribute('d', d1+d2)
}
function concatPathData(){
  let pathData1= fixFirstM(path1.getPathData());
  let pathData2= fixFirstM(path2.getPathData());
  let pathData3= fixFirstM(path3.getPathData());
  
  let pathDataConcat = pathData1.concat(pathData2).concat(pathData3);
  pathConcat.setPathData(pathDataConcat);
  
}
// change first m to absolute M
function fixFirstM(pathData){
  pathData[0].type='M';
  return pathData;
}
svg{
  border:1px solid #ccc;
  width:25%;
}
path{
  fill:#555;
}
<p><button onclick="concatSimple()">concat d simple</button>
  <button onclick="concatPathData()">concat d pathData</button>
</p>

<svg viewBox="0 0 50 10">
  <path id="path1" d="m 20 0  10 0  0 10  -10 0z" />
  <path id="path2" d="m 40 0  10 0  0 10  -10 0z" />
  <path id="path3" d="m 0 0  10 0  0 10  -10 0z" />
</svg>
<svg viewBox="0 0 50 10">
  <path id="pathConcat" d="" />
</svg>

<script src="https://cdn.jsdelivr.net/npm/path-data-polyfill@1.0.4/path-data-polyfill.min.js"></script>

要修复第一个相对m,我们可以通过更改第一个命令类型进行转换

 pathData[0].type='M';

建议:只使用相对的m命令,如果它们实际上是相对的:

  • 如果您需要以下l命令的简写(如m 20 0 10 0 0 10 -10 0z)
  • 复合路径中的相对(子路径)起始点
  • -如字母"o"

实际合并形状:删除重叠的形状

如果你需要合并形状- paper.js有一些强大的路径操作,如统一,减去等

将两个基于bezier的形状合并为一个以创建新的轮廓线