将 SVG 拆分成多个部分 - Javascript

Split SVG into pieces - Javascript

我有一个很大的 svg 标签,里面有很多 svg 多边形、线条、文本,形成一个 2D 地图,需要溢出才能在屏幕上看到全尺寸,类似这样的东西:

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

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

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

没有办法用纯 CSS.

做你想做的事

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

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

该示例使用复选框来模拟 "print mode",但您可以 运行 自动拆分和取消拆分功能,在打印时,通过收听 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>