将 SVG 中的组拆分为位于内容周围的子图像

Split groups in SVG into sub-images positioned around the contents

本文关键字:周围 于内容 图像 拆分 SVG      更新时间:2023-09-26

我在导入的 SVG 中遇到单个元素的问题,希望以某种方式提供建议。

我在 Illustrator 中创建了一个 SVG,其中包含多个图层,最终成为组元素。当我从服务器检索SVG时,我得到类似的东西。

<svg>
  <g>
  <g>
</svg>

我不想将图像作为一个整体放置,所以我按组将其分解,并用自己的 svg 标签包围每个图像,然后放置在页面上。

<svg>
  <g>
</svg>
<svg>
  <g>
</svg>

这很棒,就像我想要的那样工作。

我的问题是,这些项目中每个项目的路径都是在原始文件中绘制的。它们都是从 Illustrator 文件中绘制出来的 (0,0(,所以当我尝试放置它们时,它们在左侧都有大量的空白区域,其他元素曾经存在过。

我尝试使用 transform="translate(-50,-50(" 或其他什么,它确实移动了元素,但由于它们没有 x,y 属性,我不知道在哪里移动它们。

有谁知道抵消绘制路径的方法?或者,如果有一种方法可以读取 SVG 并将其分解为每个单独的元素并使用?

当使用Firebug或chrome时,它们以正确的大小向我显示单个元素,但由于Illustrator中绘制的路径的位置,它们被放置了很多空白。

我试过contentDocumentdocumentElement,这两个都显示为空。也许我用错了?

我是一个重度的Actionscript开发人员,现在使用Javascript和jQuery,所以我习惯了x,y坐标系统和放置元素,但这似乎不是它应该工作的方式:/

如果你真的想获取路径的XY部分,我写了一个函数来转换路径以使用全绝对命令。有了这个,您可以运行路径命令(使用 pathSegList DOM 接口,而不是原始字符串属性(并提取所有 X/Y 值并执行您想要的操作。

但是,更简单的是简单地计算路径的边界框,并在<svg>元素上设置viewBox以直接适应它:

// In case you want to leave the old SVG document unchanged
var newGroup = oldGroup.cloneNode(true);
var newSVG = document.createElementNS('http://www.w3.org/2000/svg','svg');
newSVG.appendChild(newGroup);
var bbox = newGroup.getBBox();
newSVG.setAttribute(
  'viewBox',
  [bbox.x,bbox.y,bbox.width,bbox.height].join(' ')
);

上述答案没有正确说明transform已应用于要移动的组的情况。(边界框在元素的未转换空间中返回。我创建了一个演示来解释这一点,为转换后的元素计算正确的边界框。

演示:http://phrogz.net/SVG/explode_svg_components.xhtml

// Find all the root groups in the original SVG file
var rootGroups = document.querySelectorAll('svg > g');
for (var i=rootGroups.length;i--;){
  var newSVG = elementToSVG(rootGroups[i]);
  document.body.appendChild(newSVG);
}
// Create a new SVG wrapping around a copy of the element
// with the viewBox set to encompass the element exactly
function elementToSVG(el){
  var old = el.ownerSVGElement,
      svg = document.createElementNS(old.namespaceURI,'svg'),
      css = old.querySelectorAll('style,defs');
  // Preserve elements likely needed for correct appearance
  [].forEach.call(css,copyToNewSVG);
  copyToNewSVG(el);
  var bb = globalBoundingBox(el);
  svg.setAttribute('viewBox',[bb.x,bb.y,bb.width,bb.height].join(' '));
  return svg;
  function copyToNewSVG(e){
    svg.appendChild(e.cloneNode(true));
  }
}
// Calculate the bounding box of an element in global SVG space
// accounting for transforms applied to the element
function globalBoundingBox(el){
  var bb  = el.getBBox(),
      svg = el.ownerSVGElement,
      m   = el.getTransformToElement(svg);
  var pts = [
    svg.createSVGPoint(), svg.createSVGPoint(),
    svg.createSVGPoint(), svg.createSVGPoint()
  ];
  pts[0].x=bb.x;          pts[0].y=bb.y;
  pts[1].x=bb.x+bb.width; pts[1].y=bb.y;
  pts[2].x=bb.x+bb.width; pts[2].y=bb.y+bb.height;
  pts[3].x=bb.x;          pts[3].y=bb.y+bb.height;
  var xMin=Infinity,xMax=-Infinity,yMin=Infinity,yMax=-Infinity;
  pts.forEach(function(pt){
    pt = pt.matrixTransform(m);
    xMin = Math.min(xMin,pt.x);
    xMax = Math.max(xMax,pt.x);
    yMin = Math.min(yMin,pt.y);
    yMax = Math.max(yMax,pt.y);
  });
  bb = {}; //IE9 disallows mutation of the original bbox
  bb.x = xMin; bb.width  = xMax-xMin;
  bb.y = yMin; bb.height = yMax-yMin;
  return bb;
}