有没有办法使用Javascript合并两个路径元素(svg)?

问题描述 投票:0回答:2

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

javascript svg
2个回答
17
投票

您的路径是相对定义的(小写字母)还是绝对定义的(大写字母)? 如果是绝对路径,则连接两条路径很简单,只需附加

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)。

如果您的路径是相对的,那么您将必须在附加路径之间添加一些内容,以便第二个路径从正确的位置开始。


3
投票

连接
d
属性

通常,您可以简单地连接多个

d
元素的 pathdata
<path>
属性来获得复合路径 - 无论这些路径是使用相对、绝对还是命令。

不幸的是,您可能会遇到一些»不好的做法«使用

M
m
作为可互换的启动命令。

事实上,每个 first

m
M
命令(在路径数据
d
属性中)都描述 absolute 坐标 - 因为没有没有前面的点。因此,大多数情况下,您可以将第一个
m
命令更改为大写并连接。

例外:小写的

m
命令引入了一行隐式相对的
l
lineto命令。 (例如多边形/折线)。

示例 1:以(不必要的)相对
m
命令开始的路径

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:通过
m
 修复伪相对 
getPathData()

命令

目前仍是草案,主要浏览器本身不支持。
不过你可以使用 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/[email protected]/path-data-polyfill.min.js"></script>

由于隐式 linetos 已转换为显式

l
命令,我们可以将第一个 moveto 更改为
M

 pathData[0].type='M';

建议:仅使用相对
m
命令(如果它们实际上是相对的):

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

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

如果您需要合并形状 - paper.js 有一些强大的路径操作,如合并、减去等。
此处解释:“将两个基于贝塞尔曲线的形状合并为一个以创建新的轮廓”

© www.soinside.com 2019 - 2024. All rights reserved.