Моему приложению необходимо распечатать сколь угодно большой холст, который может охватывать несколько страниц по ширине и по высоте.

Некоторое время назад был похожий вопрос где было заявлено, что браузер не будет печатать на нескольких страницах ширины.

Так как это было некоторое время назад, мне интересно, если это все еще правда. Кроме того, какие стратегии доступны, чтобы распечатать большой холст, не разбивая его?

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>
9
Matthew David Jankowski 1 Сен 2017 в 23:08

5 ответов

Лучший ответ

Похоже, что браузеры разделят большой холст на несколько страниц. Я тестировал на MacOS Sierra, используя последние браузеры Chrome и Safari.

Возможный подход к печати холста - сначала преобразовать его в URI данных, содержащий представление изображения с использованием canvas.toDataURL(). Затем вы можете управлять размерами изображения перед печатью.

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

В следующем примере большой 4500px от 4500px canvas переводится в img и помещается в iframe, который используется для печати. Возможно, вы можете добавить изображение к исходному документу и распечатать этот конкретный элемент, но iframe может быть более гибким для обработки вывода на печать. Вы можете манипулировать размерами img в соответствии с вашими требованиями и печатать масштабированное представление холста. Обратите внимание, что я жестко закодировал width и height изображения, но это можно рассчитать и изменить по мере необходимости для печати.

Из-за ограничений между источниками iframe приведенный ниже фрагмент кода здесь работать не будет, но он работает на этой jsfiddle .

Масштабированное изображение 500px по 500px, представляющее холст, помещается на одной странице при печати.

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>
2
jfeferman 6 Сен 2017 в 02:50

Я только что протестировал эту скрипку в обоих браузерах Firefox и Chrome, используя среду localhost, и она работала в обоих. Вот оригинальная js fiddle

И вот HTML, который я тестировал

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();

});
div.sizePage {
  color: #333;
}

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>

Поэтому я думаю, что можно с уверенностью сказать, что он поддерживается в обоих браузерах.

Я использую самое последнее обновление в обоих браузерах.

1
Arun Vinoth 6 Сен 2017 в 13:23

Невозможно решить эту проблему, используя простые стили CSS. Я рекомендую клонировать элемент для печати несколько раз (в данном случае), размещать копии друг за другом и делать их «только для печати» с помощью CSS. Кроме того, холст нельзя просто клонировать - его нужно перерисовывать для каждой копии.

Количество копий зависит от элемента и ширины страницы. Ширина страницы по умолчанию составляет 210 мм, ее можно преобразовать в px (Пиксель в сантиметр?) и сравнить с ширина элемента.

Когда у нас есть ширина страницы в пикселях, мы можем установить отрицательное левое поле для каждой копии соответственно. При этом весь холст будет «разбит» на столбцы и напечатан сверху вниз.

Чтобы печатать каждую копию, начиная с новой страницы, просто используйте это правило CSS:

page-break-before: always;

Есть много жестко запрограммированных вещей, однако я думаю, что вы могли бы использовать это, чтобы создать общее решение для вашей проблемы.

var divide = function(selector, pageWidth) {
  var elementToDivide = document.querySelector(selector);
  var widthPx = elementToDivide.offsetWidth;
  var pageWidthPx = pageWidth * 3.7795;

  for (var i = 1; i <= parseInt(widthPx/pageWidthPx); i++) {
    var clone = elementToDivide.cloneNode(true);
    elementToDivide.parentNode.appendChild(clone);

    draw_a(document.getElementsByTagName("canvas"))
    clone.style.marginLeft = "-" + (pageWidthPx * i) + "px";
    clone.className += " printOnly";
  }
}

var standardPrint = window.print;

window.print = function() {
  if (!window.pagesDivided) {
    divide(".myDivToPrint", 210);
    window.pagesDivided = true;
  }
  standardPrint();
};

function draw(canvas) {
  var context = canvas.getContext("2d");
  var grd = context.createLinearGradient(0, 0, 4000, 2500);
  grd.addColorStop(0, "yellow");
  grd.addColorStop(1, "red");

  context.fillStyle = grd;
  context.fillRect(25, 25, 4000, 2500);
}

function draw_a(elem) {
  if (elem.length != null && elem.length > 1) {
    for (var i = 0; i < elem.length; i++) {
      draw(elem[i]);
    }
  } else {
    draw(elem);
  }
}
$(document).ready(function() {
  draw_a(document.getElementById("canvas1"));
});
canvas {
  border: 5px dashed;
}
.printOnly {
  display: none;
}
.myDivToPrint { 
  float: left;
}
@media print {
 @page {
    size: 297mm 210mm;
    margin: 0mm;
    margin-right: 0mm;
  }
  html,
  body {
    height: 100%;
    background-color: yellow;
  }
  .myDivToPrint {
    page-break-before: always;
    background-color: yellow;
    margin: 0;
  }
  .no-print,
  .no-print * {
    display: none !important;
  }
  .printOnly {
    display: block;
    page-break-before: always;
  }
}

@media print and (-ms-high-contrast: active),
(-ms-high-contrast: none) {
  html,
  body {
    height: 100%;
    background-color: yellow;
  }
  .myDivToPrint {
    background-color: yellow;
    top: 0;
    left: 0;
    margin: 0;
    padding: 15px;
    font-size: 14px;
    line-height: 18px;
    align-items: center;
    justify-content: center;
  }
  .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>
1
luke 11 Сен 2017 в 12:24

Попробуй это!

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>
1
grinmax 6 Сен 2017 в 13:09
@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>
3
Farhad Bagherlo 5 Сен 2017 в 19:11