根据 clipPath 元素更改要裁剪的 SVG 路径

Change SVG paths to be clipped according to clipPath element

我有一个如下所示的 SVG:

<svg id="Layer_1" data-name="Layer 1"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 576 576">
  <defs>
    <style>...</style>
    <clipPath id="clip-path">
      <rect class="cls-1" x="0.02" width="575.04" height="576"/>
    </clipPath>
  </defs>
  <g class="cls-2">
    <path class="cls-3" d="M137.91-147.28c-4-1.67-8.25-3.46-12.37-3.86-5.43-.53-9.26,1.73-12.55,5a18.75,18.75,0,0,0-4.69-9.42,19.23,19.23,0,0,0-6.45-...
    <path class="cls-4" d="M.08,502.59c-.79-5.67-6.22-4.3-5.81-.22a17.15,17.15,0,0,1,0,2.95c-.22,2.82-1.46,7.6-5,7.61-1.35,0-2.61-1-3.12...
    ...

我想将其更改为:

我试过这个:

inkscape --actions \
 "select-all:groups; SelectionUnGroup; ObjectUnSetClipPath; export-filename: output.svg; export-plain-svg; export-do;" \
 Decorations.svg

这会删除分组,但不会剪裁 path 元素。 clipPath 仍然存在。

ObjectUnSetClipPath 将删除裁剪属性 clip-path="url(#clip-path)" – 而不是 <def> 裁剪路径本身。

但是,如果您的 clipPath 定义被剥离,您将无法剪辑任何元素。

function stripClip(el){
  let clipPaths = document.querySelector(el).querySelectorAll('clipPath');
  if(clipPaths.length){
    clipPaths.forEach(function(item, i){
      item.remove();
    }
    )
  }
}
svg{
width: 20vw;
}

.clipped{
clip-path: url(#clip-path2);
}
  <p><button onclick="stripClip('#svg1')" >remove ClipPath</button></p>
  
<svg id="svg1" data-name="Layer 1"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 36 36">
  <defs>
    <style>...</style>
    <clipPath id="clip-path">
      <rect class="cls-1" x="10" width="36" height="18"/>
    </clipPath>
  </defs>
  <g class="cls-2">
   <path clip-path="url(#clip-path)" d="M18 2.0845
  a 15.9155 15.916 0 0 1 0 31.83
  a 15.916 15.916 0 0 1 0 -31.83z" fill="red" />
  <rect  clip-path="url(#clip-path)" x="0" y="0" width="10" height="25" />
  </g>
  </svg>
  
  
  <svg id="svg2" data-name="Layer 1"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 36 36">
  <defs>
    <style>...</style>
    <clipPath id="clip-path2">
      <rect class="cls-1" x="10" width="36" height="18"/>
    </clipPath>
  </defs>
  <g class="cls-2">
   <path class="clipped" d="M18 2.0845
  a 15.9155 15.916 0 0 1 0 31.83
  a 15.916 15.916 0 0 1 0 -31.83z" fill="red" />
  <rect class="clipped" x="0" y="0" width="10" height="25" />
  </g>
  </svg>
  

**编辑:** 使用 paper.js

获取 svg 相交路径

不可否认,这不是最方便的方法,但它是可能的:
除了 paper.js,我们还需要一些 script/helper 来将 svg 形状(圆形、矩形等)转换为 <path> 元素(我是使用 'pathThatSvg' ,因为 paper.js 只能根据 2 个路径元素计算新的交叉路径,如下所示:

var intersectionPath = path1.intersect(clipPath);

基于

var svg = document.querySelector("#svgIntersect");

// set auto ids for processing
function setAutoIDs(svg) {
  var svgtEls = svg.querySelectorAll(
    "path, polygon, rect, circle, line, text, g"
  );
  svgtEls.forEach(function (el, i) {
    if (!el.getAttribute("id")) {
      el.id = el.nodeName + "-" + i;
    }
  });
}
setAutoIDs(svg);

// convert shapes to paths
function shapesToPath(svg) {  
        pathThatSvg(svg.outerHTML).then((converted) => {
          var tmp = document.createElement("div");
          tmp.innerHTML = converted;
          svg.innerHTML = tmp.querySelector("svg").innerHTML;
        });
}
shapesToPath(svg);


function intersectPath(svg, decimals=2) {
  // init paper.js and add canvas
  canvas = document.createElement('canvas');
  canvas.id = "canvasPaper";
  canvas.setAttribute('style','display:none')
  document.body.appendChild(canvas);
  paper.setup("canvasPaper");

  // process clipped elements
  var all = paper.project.importSVG(svg, function (item, i) {
    item.position = new paper.Point(
      item.bounds.width / 2,
      item.bounds.height / 2
    );
    //item.scale(0.5, new Point(0, 0) )
    var items = item.getItems();
    var ids = item._namedChildren;

    var groups = item.children;
    groups.forEach(function (gr, i) {
      var group = gr["_namedChildren"];
      if (group) {
        for (key in group) {
          //get clip path
          var clip = group["clipPath"][0];
          if (key !== "clipPath") {
            var el = group[key][0];
             //get intersection path and generate d commands
            var elClipped = el.intersect(clip);
            var elClippedD = elClipped
              .exportSVG({ precision: decimals })
              .getAttribute("d");
            // select path by id and overwrite d attribute
            var newEl = svg.querySelector("#" + key);
            newEl.setAttribute("d", elClippedD);
          }
        }
      }
    });

    // remove clip defs and attributes
    var clippedEls = svg.querySelectorAll("[clip-path]");
    clippedEls.forEach(function (clippedEl, e) {
      clippedEl.removeAttribute("clip-path");
    });
    svg.querySelector("defs").remove();
    svg.classList.add("svg-intersect");
    console.log(svg.outerHTML)
  });
}
svg{
  border: 1px solid #ccc;
  display:inline-block;
  width:200px;
}

.svg-intersect path{
  stroke:red;
  stroke-width: 0.25;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.0/paper-full.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/path-that-svg@1.2.4/dist/pathThatSvg.umd.min.js"></script>
<p>
  <button type="button" onclick="intersectPath(svg)">get Path Intersect</button>
</p>

<svg id="svgIntersect" viewBox="0 0 100 100">
  <defs>
    <clipPath id="clipPath">
      <circle cx="25" cy="25" r="25"/>
    </clipPath>
  </defs>
  <g id="clipGroup" clip-path="url(#clipPath)">
    <circle fill="#999" data-id="circle" cx="25" cy="25" r="25" />
    <rect fill="#555" id="rect" x="25" y="25" width="50" height="50" />
  </g>
  
  <g  clip-path="url(#clipPath)">
    <circle fill="#444" id="circle2" cx="66" cy="25" r="25" />
    <rect fill="#22" id="rect2" x="15" y="12.5" width="20" height="75" />
  </g>
</svg>