Get the svg of the main process and its subprocesses related to it

Hi,

I have an angular app and I am using bpmn as a library. I have processes that have sub processes. What I am doing is creating a pdf document, and in that document attach the svg of the process which I already am able to do with this function:

  /**
   * Save diagram as a SVG
   * @returns
   */
  async saveDiagram() {
    const { svg } = await this.bpmnJS.saveSVG({ format: true });
    return svg;
  }

Some processes have sub processes and what I need to do is when I click the extract pdf along side all the info I get I need to get the svg of the main process and all the sub processes that are part of this process. One process can have many sub processes. I have seen similar topics and have taken this example from the forum:

getSubProcesses() {
    let canvas = this.bpmnJS.get('canvas');
    let subprocesses = this.bpmnJS
    .get("elementRegistry")
    .filter(
      (el) => el.type === ProcessObjectEnum.BPMN_SUB_PROCESS && el.hasOwnProperty("layer")
    );
    for (let i = 0; i < subprocesses.length; i++) {
      // console.log(subprocesses[i]);
      canvas.setRootElement(subprocesses[i]);
      // console.log(JSON.stringify(canvas));
    }
  }

The problem is that when I click the print pdf, the printed document shows me one sub process the last one it iterates and skips the other sub processes and also the main process. Am I doing something wrong ? Is the thing I want to achieve possible. Appreciate the help.

I found the solution. Here it is for anyone who wants the same output as I do:

/**
  * Gets main process and its subprocesses and converts
  * them to svg files. Adds also the names and process id of the
  * subprocesses
  */
async getSubProcesses() {
   const svgCollection: { subProcessId: string; svg: string }[] = [];

   // Save the SVG of the main process
   const { svg: mainSvg } = await this.bpmnJS.saveSVG({ format: true });
   const mainSvgObj = {
     subProcessId: "",
     svg: mainSvg
   }

   svgCollection.push(mainSvgObj);

   // Get the XML of the main process
   const { xml } = await this.bpmnJS.saveXML({ format: true });

   // Create a hidden BPMN Modeler instance
   const hiddenBpmnJS = new BpmnJS({
     container: '#hiddenCanvasContainer',
   });

   // Import the XML into the hidden modeler
   await hiddenBpmnJS.importXML(xml);

   // Get the subprocesses
   const hiddenCanvas = hiddenBpmnJS.get('canvas');
   const subprocesses = hiddenBpmnJS.get('elementRegistry').filter(
     (el) => el.type === 'bpmn:SubProcess' && el.hasOwnProperty('layer')
   );

   // Save the SVG of each subprocess
   for (let i = 0; i < subprocesses.length; i++) {
     hiddenCanvas.setRootElement(subprocesses[i]);
     const { svg: subSvg } = await hiddenBpmnJS.saveSVG({ format: true });
     const svgWithId = {
       subProcessId: subprocesses[i].id,
       svg: subSvg
     }
     svgCollection.push(svgWithId);
   }

   // Destroy the hidden BPMN modeler instance to free up resources
   hiddenBpmnJS.destroy();
   return svgCollection;
 }

Great to read you found a solution to your problem.

BpmnViewer#saveSVG will save the currently available viewport. So indeed, it will not render the contents of embedded sub-process.

The library represents different sub-processes as root elements, and you’d be able to iterate through all available root elements, show them, and their graphical representation individually:

const bpmnJS = ...;

const canvas = bpmnJS.get('canvas');

const rootElements = canvas.getRootElements();

for (const rootElement of rootElements) {
  canvas.setRootElement(rootElement);

  const { svg: elementSVG } = await bpmnJS.saveSVG(...);
  
  ...
}

You can do so in a hidden bpmn-js instance, or your main editor :slight_smile:.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.