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

发布于 2024-11-05 07:52:12 字数 101 浏览 0 评论 0原文

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

I have drawn two path lines using SVG and I've saved these elements into two variables in my javascript code: 'Line1', and 'Line2', and I need to merge the two lines into one single path element. Is there a way to do so?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

胡大本事 2024-11-12 07:52:12

您的路径是相对定义的(小写字母)还是绝对定义的(大写字母)?如果是绝对路径,则连接两个路径很简单,只需附加 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;"/>

Here's a jsFiddle< /a>,它适用于 Firefox 4(需要 HTML5 解析器,以便您可以拥有内联 SVG)。

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

Are your paths defined relatively (small letters) or absolutely (capitals)? If absolute, joining two paths is trivial, just append the values of the d attribute. If you have two paths like this:

<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;"/>

Then this JavaScript code:

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

Will lead to you having a single path like this:

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

Here's a jsFiddle, it works in Firefox 4 (needs an HTML5 parser so you can have inline SVG).

If your paths are relative then you're going to have to add something between the appended paths so that the second one starts in the correct place.

千鲤 2024-11-12 07:52:12

连接 d 属性

通常,您可以简单地连接多个 元素的 pathdata d 属性来获得复合路径 - 无论是否这些命令使用相对、绝对、速记(STVH)或高度精简的命令。

不幸的是,您可能会遇到一些使用 Mm 作为可互换的启动命令的»不好的做法<

事实上,每个第一个mM命令(在路径数据d属性中)描述绝对< /strong> 坐标 – 因为没有前面的点。因此,大多数情况下,您可以将前 m 命令更改为大写并连接。

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

摘要:

  • 所有路径数据d属性以大写M命令开头 - 您可以安全地连接它们。除非路径有不同的转换。在这种情况下,您可能需要事先展平转换
  • 第一个路径命令是小写 m,但只有两个值(x 和 y) - 将第一个 m 命令更改为大写 M< /code> 和连接
  • 第一个路径命令是小写的 m 但有两个以上的后续值(x 和 y) - 它隐式地引入了相对 linetos:更改第一个 M 命令转为大写M,在第三个值之前添加相对 linto 命令 l 并连接

示例 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:相邻 linetos 的 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/[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 有一些强大的路径操作,如联合、减去等
此处解释:“合并两个基于贝塞尔曲线的形状合二为一以创建新的轮廓”

Concatenate d attributes

Usually, you can simply concatenate the pathdata d attribute of several <path> elements to get a compound path – no matter if these are using relative, absolute, shorthand (S, T, V, H) or highly minified commands.

Unfortunately, you may encounter some »bad practices« using M or m as interchangeable starting commands.

In fact, every first m or M command (in a pathdata d attribute) describes absolute coordinates – since there are no preceding points. So most often you can change the first m commands to uppercase and concatenate.

Exception: the lowercase m command introduces a row of implicit relative l lineto commands. (For instance for polygons/polylines).

Summary:

  • all your path data d attributes start with a uppercase M command – you can safely concatenate them. Unless paths have different transformations. In this case you may need to flatten transformation beforehand.
  • first path command is lowercase m but has only two values (x and y) – change the first m command to uppercase M and concatenate
  • first path command is lowercase m but has more than two subsequent values (x and y) – it's implicitely introducing relative linetos: change the first M command to uppercase M, prepend a relative linto command l before the third value and concatenate

Example 1: paths starting with (unnecessary) 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>

Fix: just replace each starting m with an absolute M

Example 2: m command for adjacent linetos

The exception are m commands followed by coordinates – used as a shorthand for succeeding l (relative linetos). (See also w3c specs.)

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>

Fix: insert l commands

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

equals

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

or

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

Example 3: fix pseudo relative m commands via getPathData()

Currently still a draft and not natively supported by major browser.
However you can use Jarek Foksa's polyfill..

getPathData() will return an array of command objects and normalize
repeated commands like this:

[
  {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>

Since the implicit linetos are converted to explicit l commands we can change the first moveto to M

 pathData[0].type='M';

Recommendation: only use relative m commands if they are actually relative:

  • if you need a shorthand for following l commands (like m 20 0 10 0 0 10 -10 0z)
  • for relative (subpath) starting points in compound paths – like the letter "o"

Actually merging shapes: removing overlapping shapes

If you need to merge shapes - paper.js has some powerful path operations like unite, subtract etc.
Explained here: "Merging two bezier-based shapes into one to create a new outline"

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文