July 13, 2020

Markups with LeafletLoader vs PDFLoader

We already have an article on the new way of loading PDF's in the Forge Viewer using the PDFLoader component: https://forge.autodesk.com/blog/fast-pdf-viewingmarkup-inside-forge-viewer

Previously only the LeafletLoader component was available for viewing PDF's. That is based on loading various images created from the original PDF depending on where the user is zooming into the content 

Which loader will be used depends on the resolution of the PDF being loaded, i.e. based on the totalRasterPixels value for the PDF in the manifest. You can also affect which one is used by the LMV_RASTER_PDF and LMV_VECTOR_PDF properties.

You can easily check in the browser's Developer Console which loader is being used currently by checking this property: 

NOP_VIEWER.model.loader
// it will be either a
// LeafletLoader with an 'isLeafletLoader = true' property or a 
// PDFLoader with an 'isPdfLoader = true' property

One problem you might run into is if the user created markups when the LeafletLoader was used, and now wants to load the same markups but using the PDFLoader for viewing the PDF. When viewing a PDF document using Leaflet, it uses a normalized coordinate system. However, when viewing the same document as Vector-PDF, the model uses page-coordinates (according to the real model scale). Because of this, if you have markups generated when using the LeafletLoader and you load it when the PDFLoader is used to view the PDF, then the scale and position of the markups will be incorrect - see picture on top 

Fortunately, there is a function called Autodesk.Viewing.PDFUtils.leafletToPdfWorld() that can be used to figure out the position and scale transformation you need in order to show your markups correctly. Once you know those values, the easiest solution seems to be to edit the SVG directly by adding a "transform" attribute to it - see below

As a test you could follow these steps - you could use your own web app with the Forge Viewer in it (version 7+) or e.g. https://oss-manager.autodesk.io/:

1) Set this in the Developer Console of the browser before loading the PDF

window.LMV_RASTER_PDF = true

2) After loading the PDF, double check that the LeafletLoader is being used by running this: 

NOP_VIEWER.model.loader

3) Let's switch to markup editing:

let markupExtension = await NOP_VIEWER.loadExtension('Autodesk.Viewing.MarkupsCore')
markupExtension.enterEditMode();
var arrow = new Autodesk.Viewing.Extensions.Markups.Core.EditModeArrow(markupExtension)
markupExtension.changeEditMode(arrow)

4) Draw a couple of arrows and try to remember their positions

5) Let's save the markups into an SVG

var markupGeneratedForLeaflet = markupExtension.generateData()

6) Now let's switch to using the PDFLoader:  

window.LMV_RASTER_PDF = false

7) Now load the same PDF again

8) Run this code to load the saved markups

let markupExtension = await NOP_VIEWER.loadExtension('Autodesk.Viewing.MarkupsCore')
markupExtension.show()
markupExtension.loadMarkups(markupGeneratedForLeaflet, "layerName")
if (NOP_VIEWER.model.loader.isPdfLoader) {
  let origin = Autodesk.Viewing.PDFUtils.leafletToPdfWorld(NOP_VIEWER, new THREE.Vector3(0,0,0))
  let one = Autodesk.Viewing.PDFUtils.leafletToPdfWorld(NOP_VIEWER, new THREE.Vector3(1,1,1))
  let svg = markupExtension.svg
  svg.firstChild.setAttribute("transform", `translate(${origin.x}, ${origin.y}) scale(${one.x - origin.x}, ${one.y - origin.y})`)
}

9) They all should be at the correct location 🤞

If you happen to find yourself in the opposite scenario, i.e. you have an SVG of a markup that was generated while using the PDFLoader, but now want to load it while using the LeafletLoader, you could use this code instead in step 8)

let markupExtension = await NOP_VIEWER.loadExtension('Autodesk.Viewing.MarkupsCore')
markupExtension.show()
markupExtension.loadMarkups(markupGeneratedForPdf, "layerName")
if (NOP_VIEWER.model.loader.isLeafletLoader) {
  let origin = Autodesk.Viewing.PDFUtils.leafletToPdfWorld(NOP_VIEWER, new THREE.Vector3(0,0,0))
  let one = Autodesk.Viewing.PDFUtils.leafletToPdfWorld(NOP_VIEWER, new THREE.Vector3(1,1,1))
  let svg = markupExtension.svg
  svg.firstChild.setAttribute("transform", `scale(${1 / (one.x - origin.x)}, ${1 / (one.y - origin.y)}) translate(${-origin.x}, ${-origin.y})`)
}

 

Related Posts