Search code examples
javascriptautodesk-forgeautodesk-viewer

Autodesk forge viewer custom markup is not restored on viewer


I created a custom markup following the example: https://forge.autodesk.com/blog/implementing-custom-markups

The markup is created, highlighted and edited. We save and send information about the markup on the document to the server. When you open a document, the native markup is perfectly restored - edited, highlighted. But there is a problem with custom markup - they are displayed on the document, but they cannot be edited. They are not markups for viewer. It seems to me that this is due to the fact that viewer does not know about the type of custom markup (in the example this.type = 'smiley';)

How can this be fixed? Thanks!

We restore the markup in this way:

forgeRef.viewer.loadExtension('Autodesk.Viewing.MarkupsCore').then((m: any) => {
  setMarkup(m)
  const currentMarkup = allMarkupElements.find(item => item.page === activePage)
  if (currentMarkup) {
    m.show()
    m.loadMarkups(currentMarkup.data, 'Layer1')
    m.viewer.restoreState(currentMarkup.viewerState, undefined, true)
    if (!m.enterEditMode('Layer1')) {
      console.error('enter edit mode returns false') // eslint-disable-line
    }
  } else if (!m.enterEditMode()) {
    console.error('enter edit mode returns false') // eslint-disable-line
  }
  m.allowNavigation(true)
})

Solution

  • It turned out to solve the problem by re-initializing the custom markup. currentMarkup.data is an SVG string that contains information about the custom markup. From this string, you need to pull the custom markup using a parser and load the markup without it. Then you need to re-create your custom markup.

    After that, the custom markup will appear on the viewer and can be edited.

      import { parse, stringify } from 'svgson'
       
      const splitLocationMarkup = async (svgData: string) => {
        const parsedSvg = await parse(svgData)
        const children = parsedSvg.children.filter(({ name }) => name !== 'metadata')
        const location = children.find(
          child => child.children[0].children[0].attributes.type === 'location'
        )
    
        const childrenWithoutLocation = parsedSvg.children.filter(
          child => child.children[0].children[0]?.attributes.type !== 'location'
        )
        const svgWithoutLocation = stringify({
          ...parsedSvg,
          children: childrenWithoutLocation,
        })
        return { location, svgWithoutLocation }
      }
    
      const initializingLocationMarkup = async (
        location: any,
        id: number | string,
        markupInstance: any
      ) => {
        if (location) {
          const locationAttributes = location.children[0].children[0].attributes
          const [positionX, positionY] = locationAttributes.position.split(' ').map(Number)
          const position = { x: positionX, y: positionY }
          const [sizeX, sizeY] = locationAttributes.size.split(' ').map(Number)
          const style = {
            'fill-color': locationAttributes['fill-color'],
            'fill-opacity': locationAttributes['fill-opacity'],
            'stroke-color': locationAttributes['stroke-color'],
            'stroke-opacity': locationAttributes['stroke-opacity'],
            'stroke-width': locationAttributes['stroke-width'],
          }
          // @ts-ignore
          const { MarkupLocation } = await import(
            '../../Viewer/CustomMarkups/LocationMarkup/location-markup'
            )
          const customLocationMarkup = new MarkupLocation(id, markupInstance.editFrame.editor)
          // @ts-ignore
          customLocationMarkup.setSize(position, sizeX, sizeY)
          // @ts-ignore
          customLocationMarkup.setStyle(style)
          markupInstance.editFrame.editor.addMarkup(customLocationMarkup)
        }
      }
    
      const handleDocumentLoaded = (doc: any, pages: number) => {
        setPagesCount(pages)
        if (forgeRef?.viewer) {
          forgeRef.viewer.loadExtension('Autodesk.Viewing.MarkupsCore').then(async (m: any) => {
            setMarkup(m)
            const currentMarkup = allMarkupElements.find(item => item.page === activePage)
            if (currentMarkup) {
              m.show()
              const { location, svgWithoutLocation } = await splitLocationMarkup(currentMarkup.data)
              //Loading the markups without custom markup
              m.loadMarkups(svgWithoutLocation, 'Layer1')
              //Initializing custom markup
              initializingLocationMarkup(location, 'location', m)
    
              m.viewer.restoreState(currentMarkup.viewerState, undefined, true)
              if (!m.enterEditMode('Layer1')) {
                console.error('enter edit mode returns false') // eslint-disable-line
              }
            } else if (!m.enterEditMode()) {
              console.error('enter edit mode returns false') // eslint-disable-line
            }
            m.allowNavigation(true)
          })
        }
      }