Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to print a large canvas across multiple page widths in browser?

My application needs to print out an arbitrarily large canvas that can span multiple page width and height widths.

There was a similar question some time back where it was claimed the browser won't print to multiple page widths.

Since this was a while back I am wondering if it is still true. Also, what strategies are available to print out a large canvas without splitting it up?

var canvas = document.getElementById("canvas1");

function draw_a() {
  var context = canvas.getContext("2d");
  //   //  LEVER

  //plane
  context.fillStyle = '#aaa';
  context.fillRect(25, 90, 2500, 400);


}

$(document).ready(function() {
  draw_a();

});
canvas {
  border: 1px dotted;
}

.printOnly {
  display: none;
}

@media print {
  html,
  body {
    height: 100%;
    background-color: yellow;
  }
  .myDivToPrint {
    background-color: yellow;
    /*
        height: 100%;
    
        width: 100%;
        position: fixed;*/
    top: 0;
    left: 0;
    margin: 0;
  }
  .no-print,
  .no-print * {
    display: none !important;
  }
  .printOnly {
    display: block;
  }
}

@media print and (-ms-high-contrast: active),
(-ms-high-contrast: none) {
  html,
  body {
    height: 100%;
    background-color: yellow;
  }
  .myDivToPrint {
    background-color: yellow;
    /*
        height: 100%;
    
        width: 100%;
        position: fixed;*/
    top: 0;
    left: 0;
    margin: 0;
    padding: 15px;
    font-size: 14px;
    line-height: 18px;
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: center;
    -webkit-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
    transform: rotate(90deg);
  }
  .no-print,
  .no-print * {
    display: none !important;
  }
  .printOnly {
    display: block;
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="window.print();" class="no-print">Print Canvas</button>
<div class="myDivToPrint">
  <div class="Aligner-item">
    <canvas height="2500px" width="4000px" id="canvas1"></canvas>
    <div class="printOnly Aligner-item--bottom"> Print Only</div>
  </div>

</div>
like image 371
Matthew David Jankowski Avatar asked Sep 01 '17 20:09

Matthew David Jankowski


3 Answers

It does seem that browsers will split up a large canvas into multiple pages. I tested on MacOS Sierra using latest chrome and safari browsers.

A possible approach for printing a canvas is to first transform it to a data URI containing a representation of the image using canvas.toDataURL(). You can then manipulate the image dimensions prior to printing.

"<img src='" + canvas.toDataURL() + "' height='500px' width='500px' />'"

In the following example, the large 4500px by 4500px canvas is translated into an img and placed inside an iframe, used for printing. You can probably append the image to the original document and than print that specific element, but the iframe may be more flexible to handle print output. You can manipulate the img dimensions according to your requirements and print a scaled representation of the canvas. Note that I hardcoded the width and height of the image but this can be calculated and changed as needed for printing.

Due to iframe cross-origin restrictions, the code snippet below will not work here, but it does work on this jsfiddle.

The scaled 500px by 500px image representing the canvas fits on one page when printed.

var canvas = document.getElementById("canvas1");

function draw_a() {
  var context = canvas.getContext("2d");
  //   //  LEVER

  //plane
  context.fillStyle = '#aaa';
  context.fillRect(25, 90, 4500, 4500);
}

print = function() {
	window.frames["myFrame"].focus();
	window.frames["myFrame"].print();
}

function setupPrintFrame() {
	$('<iframe id="myFrame" name="myFrame">').appendTo("body").ready(function(){
    setTimeout(function(){
        $('#myFrame').contents().find('body').append("<img src='" + canvas.toDataURL() + "' height='500px' width='500px' />'");
    },50);
	});
}

$(document).ready(function() {
  draw_a();
	setupPrintFrame();
});
canvas {
  border: 1px dotted;
}

.printOnly, #myFrame {
  display: none;
}

@media print {
  html,
  body {
    height: 100%;
    background-color: yellow;
  }
  .myDivToPrint {
    background-color: yellow;
    /*
        height: 100%;
    
        width: 100%;
        position: fixed;*/
    top: 0;
    left: 0;
    margin: 0;
  }
  .no-print,
  .no-print * {
    display: none !important;
  }
  .printOnly {
    display: block;
  }
}

@media print and (-ms-high-contrast: active),
(-ms-high-contrast: none) {
  html,
  body {
    height: 100%;
    background-color: yellow;
  }
  .myDivToPrint {
    background-color: yellow;
    /*
        height: 100%;
    
        width: 100%;
        position: fixed;*/
    top: 0;
    left: 0;
    margin: 0;
    padding: 15px;
    font-size: 14px;
    line-height: 18px;
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: center;
    -webkit-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
    transform: rotate(90deg);
  }
  .no-print,
  .no-print * {
    display: none !important;
  }
  .printOnly {
    display: block;
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<button onclick="print()" class="no-print">Print Canvas</button>
<div class="myDivToPrint">
  <div class="Aligner-item">
    <canvas height="4500px" width="4500px" id="canvas1"></canvas>
    <div class="printOnly Aligner-item--bottom"> Print Only</div>
  </div>

</div>
like image 114
Julio Feferman Avatar answered Oct 15 '22 13:10

Julio Feferman


@media print {  
  @page {
    size: 297mm 210mm; /* landscape */
    /* you can also specify margins here: */
    margin: 25mm;
    margin-right: 45mm; /* for compatibility with both A4 and Letter */
  }
}

var canvas = document.getElementById("canvas1");
function draw_a() {
  var context = canvas.getContext("2d");
  //   //  LEVER
  //plane
  context.fillStyle = '#aaa';
  context.fillRect(25, 90, 2500, 400);
}
$(document).ready(function() {
  draw_a();
});
canvas {
  border: 1px dotted;
}
.printOnly {
  display: none;
}
@media print {
 @page {
    size: 297mm 210mm; /* landscape */
    /* you can also specify margins here: */
    margin: 25mm;
    margin-right: 45mm; /* for compatibility with both A4 and Letter */
  }
  html,
  body {
    height: 100%;
    background-color: yellow;
  }
  .myDivToPrint {
    background-color: yellow;
    /*
        height: 100%;
    
        width: 100%;
        position: fixed;*/
    top: 0;
    left: 0;
    margin: 0;
  }
  .no-print,
  .no-print * {
    display: none !important;
  }
  .printOnly {
    display: block;
  }
}

@media print and (-ms-high-contrast: active),
(-ms-high-contrast: none) {
  html,
  body {
    height: 100%;
    background-color: yellow;
  }
  .myDivToPrint {
    background-color: yellow;
    /*
        height: 100%;
    
        width: 100%;
        position: fixed;*/
    top: 0;
    left: 0;
    margin: 0;
    padding: 15px;
    font-size: 14px;
    line-height: 18px;
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: center;
    -webkit-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
    transform: rotate(90deg);
  }
  .no-print,
  .no-print * {
    display: none !important;
  }
  .printOnly {
    display: block;
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="window.print();" class="no-print">Print Canvas</button>
<div class="myDivToPrint">
  <div class="Aligner-item">
    <canvas height="2500px" width="4000px" id="canvas1"></canvas>
  <div class="printOnly Aligner-item--bottom"> Print Only</div>
  </div>
</div>
like image 43
Farhad Bagherlo Avatar answered Oct 15 '22 14:10

Farhad Bagherlo


Try this!

var canvas = document.getElementById("canvas1");
    function draw_a() {
      var context = canvas.getContext("2d");
    	context.fillStyle   = '#aaa';
    	context.fillRect  (25, 90, 2500, 400);
    } 
    
    $(document).ready(function(){
      draw_a();
    });
@page Section1 {
    size:8.27in 11.69in; 
    margin:0; 
    mso-header-margin:0; 
    mso-footer-margin:0; 
    mso-paper-source:0;
}
  <button onclick="window.print();" class="no-print">Print Canvas</button>
  <div class="myDivToPrint">
    <div class="Aligner-item">
      <canvas height="2500px" width="4000px" id="canvas1" style="border: solid 10px #000;"></canvas>
    </div>
  </div>
like image 26
grinmax Avatar answered Oct 15 '22 13:10

grinmax