0

I have inline SVG with patterns. I need two different page layouts - one for "media print" another one for browsers. I am creating everything in #svgCanvas dynamically and I need it to appear at the bottom of my print layout.

My first idea was to clone whole svg, but then I ended up with things having same ID's and Firefox and Edge got really upset about it. What are the alternatives to achieve this?

I had a look at doing svg to html5 canvas conversion but for some reason that did not really work out for me so I though maybe there is another easier way like the one below? I know it is possible to do something like this:

<img src="external.svg">

so thought I should be able to do the same with inline svg.

<span class="media-print-only">
  some stuff
  <img src="#svgCanvas">
</span>

<span class="no-media-print">
  some more stuff
  <svg id="svgCanvas">
    <defs> some <patterns> </defs>
    some lines and rectangles that are using patterns in defs
  </svg>
  again more stuff
</span>
M. Paulikas
  • 840
  • 10
  • 14
  • Maybe check out this [answer to "set img.src to dynamic svg element"](http://stackoverflow.com/a/11765731/4824627), it might help – Matheus Avellar Feb 25 '17 at 19:53
  • That worked well for objects, but not completely for patterns. I am making patterns for my rectangles from other patterns that have xlink:href="someImages.png" dynamically using JS. I did get parts of patterns which do not rely on other patterns. – M. Paulikas Feb 25 '17 at 20:13

2 Answers2

1

You can use use element for this purpose. When you create SVG graphic with id, you can refer it in any place by using use element, like this.

<span class="media-print-only">
  <div class="svg-container">
    <svg width="200px" height="200px">
      <use xlink:href="#svgCanvas"/>
    </svg>   
  </div>
</span>

<span class="media-no-print">
  <div class="svgRealPlace">
    <svg width="200px" height="200px">
      <use xlink:href="#svgCanvas"/>
    </svg>
  </div>
</span>

<!--defining base SVG graphic-->
<svg width="0" height="0">
  <svg id="svgCanvas" width="200px" height="200px">
    <defs>
      <pattern id="pattern" width="10" height="10" patternUnits="userSpaceOnUse">
        <circle cx="5" cy="5" r="5" fill="blue"/>
      </pattern>
    </defs>
    <circle cx="100" cy="100" r="100" fill="url(#pattern)"/>
  </svg>   
</svg>

Note:
Base svg element or its ancestor elements must not have display:none style or hidden property, because they break reference to base svg. So I set size of container svg element to 0 to hide from screen.

defghi1977
  • 5,081
  • 1
  • 30
  • 29
  • I have already tried this method and that did not help and your "Note:" was exactly the bit that I was missing and it earned you accepted answer. Well Done! Only a small addition - for some reason I needed to not only set the svg copies width and height, but also "use" elements width and height in order to make it work. – M. Paulikas Feb 26 '17 at 16:17
0

I found a workaround to this problem - use jquery to move svg to printable place just before window.print() method and put the svg back to its original place straight after the method:

HTML

<span class="media-print-only">
  some-stuff
  <div class="svg-container"></div>
</span>

<span class="media-no-print">
  some more stuff
  <div class="svgRealPlace">
    <svg id="svgCanvas">
      <defs> some patterns </defs>
      some lines and rectangles that are using patterns in defs
    </svg>
  </div>
  again more stuff
</span>

JS

function printButtonClicked(){
    $(".svg-container").append($('#svgCanvas'));
    window.print();
    $(".svgRealPlace").append($('#svgCanvas'));
}

Tested on Chrome, Firefox and Edge. I really hope there exists a better solution since DOM modifications are almost never a good idea.

M. Paulikas
  • 840
  • 10
  • 14