СоХабр закрыт.

С 13.05.2019 изменения постов больше не отслеживаются, и новые посты не сохраняются.

| сохранено

H Версия для печати — делаем красиво с помощью canvas и javascript в черновиках Из песочницы

Рано или поздно перед каждым разработчиком встает вопрос о печати страницы в красивом формате, будь то pdf или просто красивая печатная версия вашего сайта. Для этого вы можете использовать html2pdf, например. Но эта бибилиотека поддерживает только вебкит. Что же делать с FF и IE? Нужен более универсальный способ печати, кроме того, есть ряд задач:

  • Печать всей страницы целиком;
  • Печать части страницы (без футера и шапки, например);
  • Максимально кроссбраузерно и просто.


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

Нам понадобятся:


Начать стоит с генерации canvas, все просто:

function renderPrintVersion() {
    html2canvas(document.body, { // рендеим body по умолчанию
      onrendered: function(canvas) {
        document.body.appendChild(canvas); // вставляем перед </body>
      }
    });
  }

  setTimeout(function() {
    window.print(); // таймаут для отрисовки канваса
  }, 2000);
};
});


Далее отправляем все это на печать:

// для windows все просто, достаточно отловить нужное сочетание клавиш
jQuery(document).bind("keyup", function(e){
  if(e.ctrlKey && e.keyCode == 80) {
     // console.log('print ctrl + 80');
      renderPrintVersion();
  }
});

// для маков все сложно, дело в том, что command не имеет свой keyCode, 
// ну или не откликается на 91/93 keyCode
$(window).keydown(function(e) {
  if (e.keyCode >= 65 && e.keyCode == 80) {
    renderPrintVersion();
    return false; // отменяем вызов окна печати по умолчанию
  }
})


На этом этапе у вас уже будет рабочая версия формы печати, но она будет выводится вместе с вашей текущей html версией, нехорошо. Добавляем css для печатной версии:

@media print {
  canvas {
   /* в веб версии мы скрываем canvas и он присутствует в DOM. */
    display: block; 
  }
  .wrapper, footer, header {
    display: none;
  }

  body {
    background-color: #fff;
  }
}


Но задача стоит другая — напечатать только часть страницы. Для этого (вы уже наверное все знаете) достаточно передать вместо document.body нужный вам id, например:

html2canvas(document.getElementById('print-table-only'), { // печатаем только таблицу тарифов
  onrendered: function(canvas) {
    document.body.appendChild(canvas);
  }
});


В результате работы вы получите красивую печатную версию вашего сайта, в которой нет места экономии чернил, но, тем не менее, она будет отлично смотреться на листке бумаги и будет иметь узнаваемый дизайн вашего продукта.
+13
9024

комментарии (26)

+11
Makaveli ,  
Было бы неплохо демо приложить
+7
Xlab ,   * (был изменён)
Или скриншоты хотя бы, может наши понятия о красоте отличны от авторских.
–8
mrTyler ,  
Простите, проект NDA и он довольно таки авральный.
+4
artishok ,  
Можно демо-страничку обычную для демонстрации
0
spmbt ,  
На самом деле, всё это довольно легко просмотреть на странице автора скрипта: html2canvas.hertzen.com/screenshots.html

Меня, например, в первую очередь заинтересовал вопрос отображения кириллицы. Ввёл www.yandex.ru. 2 раза не дождался обработки (какой-то янд.счётчик в запросе висел), на 3-й раз выдался чистый и корректный скриншот Яндекса.

В общем — да, интересный способ обойти искажения страниц браузеным рендерером печати (когда прямо пытаешься напечатать по Ctrl-P или хотя бы посмотреть превью печати. Было очень браузерозависимо в своё время и с кучей стилевых особенностей (если не сказать отклонений)). Спасибо.
0
spmbt ,   * (был изменён)

Да, совсем забыл скриншот показать, чтобы не заставлять желающих ):
habrastorage.org/files/a76/1b1/d7a/a761b1d7aa3147bf9b003281bd862b3d.png — скриншот Яндекса через Canvas, 70К

0
mrTyler ,  
несмотря на то, что мне страшно уже тут что-либо говорить, я все же скажу вам больше спасибо за ваш скриншот и проверку моего маленького лайфхака.
+2
AndersonDunai ,  
Я понимаю — скриншоты делать с-под сайта через канвас, но печатать… Зачем?
–1
mrTyler ,  
Заказчик желает видеть распечатанную версию расчета некоего калькулятора в очень красивом виде.
+5
werdender ,  
Но можно же просто распечатать html, применив нужные стили. Или я чего-то не понял?
0
progit ,   * (был изменён)
Еще можно сделать красивый PDF.
При печати html все-таки есть один недочет: по-умолчанию печатаются колонтитулы, что может немного подпортить внешний вид распечатанного документа.
–2
mrTyler ,  
при выборе печати «без полей» все смотрится просто отлично
0
Alexgks ,  
Через стили нельзя задать печать фона по умолчанию, и соответственно разнообразные иконки печататься не будут.
+5
jonic ,  
Удобно конечно, но с другой стороны я обычно просто стили ставил другие для печати.
+2
VolyaPers ,  
Всё таки может выложите демку?)
+4
david_mz ,  
Разве отпечаток не получится размытым? Скриншот же делается в разрешении экрана, у принтера оно выше.
0
progit ,  
В этом случае можно применить хак и «нарисовать» в увеличенном масштабе, но все равно получится не так четко, как при печати текста.
–3
mrTyler ,  
Да, все верно, данная проблема есть, но она не столь важна в этом случае. Текст остается читаемым при генерации, он не такой четкий как хотелось бы, но прочесть его можно без труда.
+1
david_mz ,  
Вот тут описаны некоторые техники, возможно, помогут: www.html5rocks.com/en/tutorials/canvas/hidpi/
0
+1 –1
mrTyler ,  
спасибо большое
0
LeX_KaR ,  
И все таки данный способ не лучше, а местами и печати через обычный print с кастомным стилем. Другое дело html2pdf
–2
mrTyler ,  
html2pdf не может быть использован в FF и IE, в то время как мой пример протестирован на Chrome, Opera (webkit), Safari, Firefox и IE10 и работает там корректно, за исключением резкости изображения, о который писали выше
+2
Holden ,  
Интересное решение.
Почему не воспользовались projects.erikzaadi.com/jQueryPlugins/jQuery.printElement?
–3
+3 –6
mrTyler ,  
просто не знал о таком решении и времени ресерчить особо не было. Нужно было делать. Иногда время слишком дорого, чтобы тратить его на плагины, которые возможно не подойдут. Пошел по понятному для себя пути решения задачи.
0
barkalov ,  
Растрировать вектор в 72dpi, чтобы печатать? Идея странная по определению.
0
cybermerlin ,  
а как насчет PDFjs?
на выходе получаем чистейший pdf и поддерживается вроде всеми браузерами (не самыми старыми, конечно, но вроде пользующиеся спросом.