0

I'm trying to clone a page I need for printing. The print dialog should ONLY print out the selected element and its elements.

https://jsfiddle.net/ctqdhta7/

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.font = "30px Arial";
ctx.fillText("Hello World", 10, 50);



setTimeout(function() {
  var restorepage = $('body').html();
  var printcontent = $("#hello").clone();
  $('body').empty().html(printcontent);
  window.print();
  $('body').html(restorepage);
}, 1000);

This copies the entire body page, clones the content of the print I should print out, then it empties the body and replaces it with the content it should print. After that, it opens the print dialog with ONLY the printable elements. A workaround could be: Create the whole canvas after .html(printcontent) once again. Since clone() only clones the HTML, the canvas has not been initialized and has no content.

Since I am using an Angular directive, I am unable to simply do the whole "redraw the canvas". Is there an Angular way that makes it possible to "re-render the DOM again" or something like that?

MortenMoulder
  • 6,138
  • 11
  • 60
  • 116
  • If you have to revert to manual process for copying canvas see http://stackoverflow.com/questions/3318565/any-way-to-clone-html5-canvas-element-with-its-content – Vanquished Wombat Dec 20 '16 at 10:13
  • @VanquishedWombat Yes, but that is the absolute last resort. I really, really don't want to iterate through all my canvases (could be hundreds) right before I print the page. – MortenMoulder Dec 20 '16 at 10:20

1 Answers1

2

canvas "content" is not part of the DOM and can't be copied by DOM method. However, it's quite easy to call clonedCanvas.getContext('2d').drawImage(originalCanvas, 0,0) which will draw the original canvas on the cloned one.

You could then try something like

// This will override the HTMLCanvas 'cloneNode' prototype
(function(){
  var ori = HTMLCanvasElement.prototype.cloneNode;
  HTMLCanvasElement.prototype.cloneNode = function(){
    var copy = ori.apply(this, arguments);
    // don't do it for web-gl canvas
    if(this.getContext('2d')){
      copy.getContext('2d').drawImage(this, 0,0);
      }
    return copy;
    };
  })();

var original = document.querySelector('canvas');
original.getContext('2d').fillRect(20, 20, 20, 20);

for(var i = 0; i<20; i++){
  document.body.appendChild(original.cloneNode());
}
<canvas></canvas>

important note : The cloneNode method needs to be called on the canvas element directly (unfortunately, it won't work for canvas.parentNode.cloneNode(true)

Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • Funny, I just ended up doing something similar to this. However, it does not work in FireFox unfortunately. I ended up converting them all to images, changing the HTML of the canvas to an image, and then print the page. Since they're generated once and never touched again, I don't need to convert them back to a canvas. I also opted away from replacing the whole body, as that was rather slow and totally destroyed all my bindings. – MortenMoulder Dec 20 '16 at 12:43
  • @MortenMoulder, I wrote it on Firefox and it definitely works. And I don't see why it wouldn't for others. Also, cloneNode + drawImage is largely less memory consumptive than any export method. – Kaiido Dec 20 '16 at 12:45
  • That's odd! I just tried again and it works. It does take a few seconds for me though. Thanks :) – MortenMoulder Dec 20 '16 at 12:46
  • Ah also, it needs to be called on the canvas element directly (unfortunately, it won't work for `parentNode.cloneNode(true)`) – Kaiido Dec 20 '16 at 12:52