ADN Open CIS
Сообщество программистов Autodesk в СНГ

30/04/2021

Forge Viewer: Печать листов

Сейчас Forge Viewer не предоставлят функицонала печати. BIM 360 фактически создает скриншот листа, показанного в Forge Viewer, размещает созданную картинку в HTML и вызывает функцию window.print().

В нашем блоге уже есть статья о создании скриншотов в Forge Viewer и создании скриншотов листов модели на сервере.

Вместо того, чтобы самим определять границы листа модели в Forge Viewer, мы можем воспользоваться функционалом, предоставляемым методом Autodesk.Viewing.ScreenShot.getScreenShotWithBounds(), передав в качестве параметра следующие настройки:

Код - JavaScript: [Выделить]
  1. { fullPage: true, margin: 0 }

В метод getScreenShowWithBounds мы передаем callback - функцию onDone, в которую будут переданы ширина, высота и blob URL созданной картинки. Полученные ширину и высоту мы будем использовать в шаблоне страницы, которую мы отправляем на печать при помощи функции window.print().

Мы также можем автоматически закрывать дополнительную вкладку или окно, когда пользователь закроет диалог печати, используя для этого событие onafterprint.

Пример возможной реализации, см. функцию printSheet():

Код - HTML: [Выделить]
  1.     <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=no" />
  2.     <meta charset="utf-8">
  3.  
  4.     <!-- Viewer CSS -->
  5.     <link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.min.css" type="text/css">
  6.  
  7.     <!-- CSS приложения -->
  8.     <style>
  9.         body {
  10.             margin: 0;
  11.             position: relative;
  12.         }
  13.        
  14.         #MyContainerDiv {
  15.             width: 100vw;
  16.             height: 100vh;
  17.             position: relative;
  18.         }
  19.     </style>
  20.    
  21.     <title>Print Sheet</title>
  22.  
  23. </head>
  24.  
  25.  
  26.     <!-- Forge Viewer будет размещен здесь -->
  27.     <div id="MyContainerDiv">
  28.         <div id="MyViewerDiv"></div>
  29.     </div>
  30.    
  31.     <!-- Forge Viewer JS -->
  32.     <script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.js"></script>
  33.  
  34.     <!-- jQuery -->
  35.     <script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
  36.  
  37.     <!-- JS приложения -->
  38.     <script>
  39.  
  40.         // iframe URL из A360, он показывается при нажатии кнопки Share
  41.         var embedURLfromA360 = 'https://autodesk3743.autodesk360.com/shares/public/SH919a0QTf3c32634dcf07b66797ba369695?mode=embed' // PDF-файл
  42.  
  43.         var viewer
  44.  
  45.         function getURN(onURNCallback) {
  46.             $.get({
  47.                 url: embedURLfromA360.replace('public', 'metadata').replace('mode=embed', ''),
  48.                 dataType: 'json',
  49.                 success: function (metadata) {
  50.                     if (onURNCallback) {
  51.                         let urn = btoa(metadata.success.body.urn).replace("/", "_").replace("=", "")
  52.                         onURNCallback(urn)
  53.                     }
  54.                 }
  55.             })
  56.         }
  57.  
  58.         function getForgeToken(onTokenCallback) {
  59.             $.post({
  60.                 url: embedURLfromA360.replace('public', 'sign').replace('mode=embed', 'oauth2=true'),
  61.                 data: '{}',
  62.                 success: function (oauth) {
  63.                     if (onTokenCallback)
  64.                         onTokenCallback(oauth.accessToken, oauth.validitySeconds)
  65.                 }
  66.             })
  67.         }
  68.  
  69.         getURN(function (urn) {
  70.             var options = {
  71.                 env: 'AutodeskProduction',
  72.                 getAccessToken: getForgeToken
  73.             }
  74.             var documentId = 'urn:' + urn
  75.             Autodesk.Viewing.Initializer(options, function onInitialized() {
  76.                 Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess)
  77.             })
  78.         })
  79.  
  80.         function onDocumentLoadSuccess(doc) {
  81.  
  82.             // Документ содержит 3D и 2D сцены.
  83.             var items = doc.getRoot().search({
  84.                 'type': 'geometry',
  85.                 'role': '2d'
  86.             }, true)
  87.             if (items.length === 0) {
  88.                 console.error('Document contains no viewables.')
  89.                 return
  90.             }
  91.  
  92.             var viewerDiv = document.getElementById('MyViewerDiv')
  93.             viewer = new Autodesk.Viewing.GuiViewer3D(viewerDiv)
  94.             viewer.start()
  95.            
  96.             viewer.loadDocumentNode(doc, items[1], {}).then(() => {
  97.                 let group = viewer.toolbar.getControl('printToolbar');
  98.                 if (!group) {
  99.                     group = new Autodesk.Viewing.UI.ControlGroup('printToolbar');
  100.                     viewer.toolbar.addControl(group);
  101.                 }
  102.  
  103.                 // Добавляем новую кнопку в группу кнопок toolbar-а
  104.                 button = new Autodesk.Viewing.UI.Button('printButton');
  105.                 button.setIcon('adsk-icon-layers');
  106.  
  107.                 button.onClick = () => {
  108.                     printSheet(viewer)
  109.                 }
  110.  
  111.                 button.setToolTip('Print Sheet');
  112.                 group.addControl(button);
  113.             })
  114.  
  115.         }
  116.  
  117.         function printSheet(viewer) {
  118.             let onDone = async (blob, imageWidth, imageHeight) => {
  119.                 let res = await fetch("printpage.html")
  120.                 let content = await res.text()
  121.                 // Высота картинки должна быть чётной, для того чтобы в диалоге печати не появлялось дополнительное пустое место
  122.                 imageHeight = imageHeight % 2 ? imageHeight + 1 : imageHeight
  123.                 content = content
  124.                     .replace(new RegExp("%IMG_WIDTH%", "g"), imageWidth)
  125.                     .replace(new RegExp("%IMG_HEIGHT%", "g"), imageHeight)
  126.                     .replace("%IMG_SRC%", blob)
  127.  
  128.                 let w = window.open('', '')
  129.                 if (w) {
  130.                     w.document.open()
  131.                     w.document.write(content)
  132.                     w.document.close()
  133.                 } else {
  134.                     console.info("Could not open a new window")
  135.                 }
  136.             }
  137.  
  138.             const canvasBounds = viewer.impl.getCanvasBoundingClientRect()
  139.             const originalWidth = canvasBounds.width
  140.             const originalHeight = canvasBounds.height
  141.             let widthInPixels
  142.             let pageWidth = viewer.model.getMetadata('page_dimensions', 'page_width')
  143.             const pageUnits = viewer.model.getMetadata('page_dimensions', 'page_units')
  144.  
  145.             // если page_units не указан, значит у нас растровое изображение и pageWidth уже в пикселях
  146.             if (pageUnits) {
  147.                 const widthInInch = Autodesk.Viewing.Private.convertUnits(pageUnits.toLowerCase(), 'in', 1, pageWidth)
  148.                 const DPI = 150
  149.  
  150.                 widthInPixels = Math.floor(widthInInch * DPI)
  151.             } else {
  152.                 widthInPixels = pageWidth
  153.             }
  154.  
  155.             const canvasRatio = originalHeight / originalWidth
  156.             const width = widthInPixels
  157.             const height = Math.floor(widthInPixels * canvasRatio)
  158.  
  159.             const screenshotOptions = {
  160.                 fullPage: true,
  161.                 margin: 0,
  162.             }
  163.  
  164.             Autodesk.Viewing.ScreenShot.getScreenShotWithBounds(viewer, width, height, onDone, screenshotOptions)
  165.         }
  166.     </script>
  167.  
  168. </body>
  169.  
  170. </html>

А вот шаблон страницы (printpage.html), используемой для печати:

Код - HTML: [Выделить]
  1.   <head>
  2.     <style>
  3.       @page {
  4.         size: %IMG_WIDTH%px %IMG_HEIGHT%px;
  5.         margin: 0;
  6.       }
  7.  
  8.       @media print {
  9.         html,
  10.         body {
  11.           margin: 0;
  12.         }
  13.       }
  14.     </style>
  15.     <script>
  16.       function onImageLoad() {
  17.         window.print();
  18.       }
  19.  
  20.       function onAfterPrint() {
  21.         window.close();
  22.       }
  23.     </script>
  24.   </head>
  25.   <body onafterprint="onAfterPrint()">
  26.     <img src="%IMG_SRC%" width="%IMG_WIDTH%px" height="%IMG_HEIGHT%px" onload="onImageLoad()" />
  27.   </body>
  28. </html>

 

Источник: https://forge.autodesk.com/blog/print-sheet-viewer

Автор перевода: Александр Игнатович
Опубликовано 30.04.2021