【问题标题】:Split SVG into pieces - Javascript将 SVG 拆分为多个部分 - Javascript
【发布时间】:2019-10-08 12:51:48
【问题描述】:

我有一个很大的 svg 标签,里面有很多 svg 多边形、线条、文本,制作了一个 2D 地图,需要溢出才能在屏幕上看到它的全尺寸,就像这样:

当我单击“打印”或使用“ctrl + p”时,我需要一种从浏览器打印它的方法,但为此我需要将它分成几部分然后放在列布局上,这样它们就可以适合 A4 大小打印整个内容,类似这样:

当我尝试打印时,我得到了这个:

所以,我需要一种方法将这个 svg 字段分成几块以适应要打印的页面。 有没有办法做到这一点,使用js,css,什么?谢谢!

【问题讨论】:

  • 可能使用无头浏览器并截取屏幕截图?
  • 我们需要更多信息。您是说在网页上将其显示为三部分,以便您可以从浏览器打印?
  • 基于提供的有限信息:我会查看 print css @media print { 并将图像垂直放置 3 次。顶部图像是整个图像的左侧 1/3。中图为全图中间1/3,下图为全图右1/3。
  • Paul LeBeau,正是这样,我有这个 svg,它是我公司的 2D 地图,我需要从浏览器打印它,并且需要拆分它以便它可以适合 A4 纸跨度>
  • 我怀疑你会找到一种通用的方式来使用 JS 进行拆分。也许通过画布转换为图像并拆分可能会起作用,但可能不可靠,需要大型库等。我认为您最好准备 3 个 SVG 并使用 CSS 或 JS 中的媒体查询切换到它们

标签: javascript svg split cut


【解决方案1】:

没有办法用纯 CSS 做你想做的事。

您需要 Javascript 来创建 SVG 的分割部分。

这里有一些演示代码。我在代码中留下了 cmets 来解释它是如何工作的。

该示例使用复选框来模拟“打印模式”,但您可以在打印时通过监听beforeprintafterprint 事件自动运行拆分和取消拆分功能。

https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeprint

function  splitSVGs(splitWidth) {
  let splittables = document.querySelectorAll(".splittable");
  splittables.forEach(function(svgElem) {

    // Get starting size of the original SVG now
    const computed = getComputedStyle(svgElem);
    const width = parseInt(computed.width, 10);
    const height = parseInt(computed.height, 10);
    const vB = svgElem.viewBox.baseVal;
    // Get the viewBox of the SVG also
    const bbox = (svgElem.getAttribute("viewBox") !== null) ? {x:vB.x, y:vB.y, width:vB.width, height:vB.height}
                                                            : {x:0, y:0, width, height};
    // Hide the original SVG
    svgElem.classList.add("hide");
    
    // Create a temporary div element to hold our generated sections
    const div = document.createElement("div");
    div.classList.add("sections");
    svgElem.insertAdjacentElement('afterend', div);

    let remainingWidth = width;
    while (remainingWidth > 0) {
      const sectionWidth = Math.min(splitWidth, remainingWidth);
      // Convert sectionWidth relative to viewBox
      bbox.width = sectionWidth * bbox.height / height;

      // Create an SVG element to contain one section of the split
      const section = document.createElementNS("http://www.w3.org/2000/svg", "svg");
      section.setAttribute("width", sectionWidth);
      // Add a viewBox that shows the area of the original that we want to see in this section
      section.setAttribute("viewBox", [bbox.x, bbox.y, bbox.width, bbox.height].join(' '));
      
      // Add a <use> element to the section SVG that references the original
      const use = document.createElementNS("http://www.w3.org/2000/svg", "use");
      use.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", '#'+svgElem.id);
      use.setAttribute("width", vB.width);
      use.setAttribute("height", vB.height);
      section.appendChild(use);
      
      // Add this section SVG to the sections div
      div.appendChild(section);
      // How much of the original SVG width is left?
      remainingWidth -= splitWidth;
      // Update bbox so the next SVG will show the next section of the original
      bbox.x += bbox.width;
    }

  });
  
}


function unsplitSVGs() {
  // Get rid of the generated sections
  const sections = document.querySelectorAll(".sections");
  sections.forEach(function(div) {
    div.remove();
  });
  
  // Unhide all the original SVGs
  const splittables = document.querySelectorAll(".splittable");
  splittables.forEach(function(svgElem) {
    svgElem.classList.remove("hide");
  });
  
}


document.getElementById("print-mode").addEventListener("change", function(evt) {
  if (evt.target.checked) {
    splitSVGs(600);
  } else {
    unsplitSVGs();
  }
});
svg {
  background: linen;
}

svg#test {
  width: 2960px;
  height: 80px;
  border: solid 2px black;
}

/* Hide while still keeping the contents visible to our section SVGs */
.hide {
  position: absolute;
  top: -9999px;
}

.sections svg {
  border: solid 2px black;
}

.sections svg:not(:first-child) {
  border-left: dashed 2px black;
}

.sections svg:not(:last-child) {
  border-right: dashed 2px black;
}
<p>
<input type="checkbox" id="print-mode">
<label for="print-mode"> Simulate print mode (split the SVG)</label>
</p>

<svg viewBox="0 0 1480 40" id="test" class="splittable">
  <text x="10" y="30" font-size="30px">We choose to go to the Moon in this decade and do the other things, not because they are easy, but because they are hard.</text>
</svg>

【讨论】:

  • 这帮助很大!谢谢!
猜你喜欢
  • 1970-01-01
  • 2012-11-10
  • 2011-05-30
  • 1970-01-01
  • 1970-01-01
  • 2020-05-04
  • 2010-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多