DMN & BPMN Diagram Paint Issue

The BPMN & DMN diagrams don’t show on the UI initally (everything loaded without any issues on the web console)
(Image 1)

Scrolling Up/Down shows the images (after wating for few seconds)
(Image 2)

If I scroll the mouse too quckly (after initial load), re-paint of the diagram re-paint is messed up
(Image 3)
(Images are in the reverse order 3,2 and 1)

DMN_AfterMouseMove1_Diagram_Image_3 DMN_AfterMouseMove_Diagram_Image_2 DMN_Init_Diagram_Image_1

I’m using Chrome on windows-10
Browser Version 80.0.3987.106 (Official Build) (64-bit)

It’s hard to help you if we don’t know your project setup. Are you able to share it, e.g. via http://codesandbox.io/?

Let me guess. You’re trying to interact with the modeler before the diagram has been imported? Share you’re code and we might be able to help you.

1 Like
import {
  OnInit,
  Component,
  OnDestroy,
  ViewChild,
  ViewChildren,
  ElementRef,
  AfterContentInit,
  SimpleChanges,
  EventEmitter,
  OnChanges
} from '@angular/core';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { FlowChartService } from '../flow-chart/flow-chart.service';
import { IFlowChart } from 'app/shared/model/bizzrlCore/flow-chart.model';
import { Subscription } from 'rxjs';
import { map } from 'rxjs/operators';

import * as _ from 'lodash';

import * as customElementsData from './custom-elements.json';
import { JhiAlertService, JhiDataUtils } from 'ng-jhipster';
import * as BpmnJS from 'bpmn-js/dist/bpmn-modeler.development.js';
import BpmnModeler from 'bpmn-js/dist/bpmn-modeler.development.js';
import InjectionNames from 'bpmn-js/dist/bpmn-modeler.development.js';
import OriginalPaletteProvider from 'bpmn-js/dist/bpmn-modeler.development.js';
import BpmnPalletteModule from 'bpmn-js/lib/features/palette';
import gridModule from 'diagram-js/lib/features/grid-snapping';
import propertiesPanelModule from 'bpmn-js-properties-panel';
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda';
import * as camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda.json';

@Component({
  selector: 'jhi-view-diagram-component',
  templateUrl: './view-diagram-component.html',
  styleUrls: ['./view-diagram-component.scss']
})
export class ViewDiagramComponent implements OnInit, OnDestroy, AfterContentInit, OnChanges {
  flowChartFindSubscription: Subscription;
  flowChard: IFlowChart;
  error: Error;
  isChartLoading = false;
  private bpmnDiagramViewer: BpmnJS;
  private diagramModeler: BpmnModeler;
  private diagramElemRegistry;
  private diagramElemRegistryString;
  private isElementRegistryDisp = false;
  private isShowChangesOn = false;
  private isEnableEvents = false;
  private eventEnableStatus = 'Events Turned OFF';
  private eventBus;
  private importDone: EventEmitter<any> = new EventEmitter();
  previousRoute: string;

  @ViewChild('ref', { static: false }) private el: ElementRef;
  @ViewChild('refProps', { static: false }) private elProps: ElementRef;

  constructor(
    protected activatedRoute: ActivatedRoute,
    private router: Router,
    private flowChartService: FlowChartService,
    protected alertService: JhiAlertService
  ) {
    console.log('json :', customElementsData);
    this.bpmnDiagramViewer = new BpmnJS();

    this.diagramModeler = new BpmnModeler({
      keyboard: { bindTo: document },
      BpmnPalletteModule,
      propertiesPanel: {
        parent: this.elProps
      },
      additionalModules: [
        gridModule,
        propertiesPanelModule,
        propertiesProviderModule,
        { [InjectionNames.originalPaletteProvider]: ['type', OriginalPaletteProvider] }
      ],
      moddleExtensions: { camunda: camundaModdleDescriptor }
    });
    /**
     * propertiesPanel: { parent: this.elProps },
     */

    console.log('diagramModeler is initalized properly..', this.diagramModeler);
    this.diagramModeler.on('import.done', ({ error, warnings }) => {
      console.log('Import Done event successfully emitted');
      if (!error) {
        console.log('Canvas Fit-viewport fired', warnings);
        this.diagramModeler.get('canvas').zoom('fit-viewport');
        this.diagramModeler.attachTo(this.el.nativeElement);
        console.log('this.el.nativeElement::', this.el.nativeElement);
        const propsPanel = this.diagramModeler.get('propertiesPanel');
        console.log('propsPanel ', propsPanel);
        propsPanel.attachTo(this.elProps.nativeElement);
        // later attach events here as well as button click
        this.onEnableEvents();
      }
    });
  }

  ngOnInit() {
    this.isChartLoading = true;
    let flowChardId = 0;
    this.activatedRoute.params.subscribe((routerParams: Params) => {
      flowChardId = +routerParams['id'];
      console.log('RouterParams Params...', routerParams);
    });
    if (flowChardId != null) {
      this.flowChartFindSubscription = this.flowChartService
        .find(flowChardId)
        .pipe(
          map(httpResponse => {
            let responseFlowChart: IFlowChart = null;
            responseFlowChart = httpResponse.body;
            console.log('Raw BPMN Diagram (transformation began...) ::', responseFlowChart.xmlPayload);
            responseFlowChart.xmlPayload = _.unescape(atob(responseFlowChart.xmlPayload));

            return responseFlowChart;
          })
        )
        .subscribe(
          responseIFlowChart => {
            console.log(responseIFlowChart);
            this.flowChard = responseIFlowChart;
            console.log('BPMN Diagram (transformed) ::', this.flowChard.xmlPayload);
            // attach BpmnJS instance to DOM element
            if (this.flowChard.xmlPayload != null && this.flowChard.xmlPayload.length > 0) {
              // this.bpmnDiagramViewer.importXML(this.flowChard.xmlPayload, function(err, warnings) {
              this.diagramModeler.importXML(
                this.flowChard.xmlPayload,
                err => {
                  console.log('diagramModeler loading error :' + err);
                  this.importDone.emit({
                    type: 'error',
                    error: err
                  });
                },
                warnings => {
                  console.log('diagramModeler loaded with warning :', warnings);
                  this.importDone.emit({
                    type: 'success',
                    warning: warnings
                  });
                }
              );
            }
          },
          Error => {
            this.error = Error;
            this.isChartLoading = false;
          }
        );
    }

    this.isChartLoading = false;
  } // end of ngInit

  ngOnDestroy() {
    if (this.flowChartFindSubscription != null) {
      this.flowChartFindSubscription.unsubscribe();
    }
    // destroy BpmnJS instance
    if (this.bpmnDiagramViewer != null) {
      this.bpmnDiagramViewer.destroy();
    }
    if (null != this.diagramModeler) {
      this.diagramModeler.destroy();
    }
  }

  ngAfterContentInit() {
    // attach BpmnJS instance to DOM element
    console.log('ngAfterContentInit Fired..');
    if (this.diagramModeler != null && null != this.el) {
      console.log('attaching diagramModeler to element ', this.diagramModeler);
      this.diagramModeler.attachTo(this.el.nativeElement);
    }
  }

  ngOnChanges(changes: SimpleChanges) {
    // re-import whenever the diagram changes. not working thats different issue to fix
    console.log('Simple Changes fired onChanges chjages=', changes);
    this.refreshDiagram();
  }

  refreshDiagram() {
    if (null != this.flowChard && this.flowChard.xmlPayload != null && this.flowChard.xmlPayload.length > 0) {
      this.diagramModeler.destroy();
      // this.bpmnDiagramViewer.importXML(this.flowChard.xmlPayload, function(err, warnings) {
      this.diagramModeler.importXML(
        this.flowChard.xmlPayload,
        err => {
          console.log('diagramModeler loading error :' + err);
          this.importDone.emit({
            type: 'error',
            error: err
          });
        },
        warnings => {
          console.log('diagramModeler loaded with warning :', warnings);
          this.importDone.emit({
            type: 'success',
            warning: warnings
          });
        }
      );
    }
  }

  onEnableEvents() {
    this.isEnableEvents = !this.isEnableEvents;

    if (null != this.diagramModeler) {
      if (this.isEnableEvents) {
        this.eventEnableStatus = 'Events Turned ON';
        if (null == this.eventBus) {
          this.eventBus = this.diagramModeler.get('eventBus');
          console.log('Event Bus ::', this.eventBus);
        }
        const events = ['element.dblclick'];
        /**, 'element.click', 'element.changed'];  */
        events.forEach(event => {
          console.log('Event Bus inside forEach ::', this.eventBus);
          this.eventBus.on(event, function(elem) {
            console.log(event + ' on ' + elem.element.type);
            if (elem.element.type === 'bpmn:BusinessRuleTask') {
              alert('Would like to Author Rules ?');
            }
          });
        });
      } else {
        this.eventEnableStatus = 'Events Turned OFF';
      }
    }
  }
  onSaveDiagram() {
    if (null != this.bpmnDiagramViewer) {
      this.isChartLoading = true;
      this.diagramModeler.saveXML({ format: true }, (err, updatedXML) => {
        this.callSaveService(updatedXML);
      });
      this.isChartLoading = false;
    }
  }

  callSaveService(updatedXML) {
    const togoXml = btoa(
      _.escape(updatedXML).replace(
        // TODO - Figure out y without this its not working
        /[\u00a0-\u2666]/g,
        c => {
          return '&#' + c.charCodeAt(0) + ';';
        }
      )
    );
    this.flowChartService
      .update({
        id: this.flowChard.id,
        name: this.flowChard.name,
        xmlPayloadContentType: this.flowChard.xmlPayloadContentType,
        xmlPayloadId: this.flowChard.xmlPayloadId,
        xmlPayload: togoXml
      })
      .subscribe(value => this.saveSuccess(value), error => this.saveError(error));
  }

  saveSuccess(value) {
    // Do after success stuff
    if (null != value) {
      if (value.statusText === 'OK') {
        this.alertService.success('Diagram Successfully Saved', null, null);
      } else {
        this.alertService.warning('Something seems wnt wrong!!', null, null);
      }
    }
    console.log('Save Success ::', value);
  }

  saveError(error) {
    // Do after error stuff
    this.alertService.error('Something seems wnt wrong!!', null, null);
    console.log('Save Error ::', error);
  }

  onElementRegistry() {
    if (this.diagramModeler != null) {
      this.diagramElemRegistry = this.diagramModeler.get('elementRegistry');
      this.diagramElemRegistryString = JSON.stringify(this.diagramElemRegistry);
      console.log('Element Registry :: ', this.diagramElemRegistry);
      this.isElementRegistryDisp = !this.isElementRegistryDisp;
    }
  }

  onShowChanges() {
    this.isShowChangesOn = !this.isShowChangesOn;
    let changes = { stroke: 'green', fill: 'yellow' };
    if (this.isShowChangesOn) {
      changes = { stroke: 'green', fill: 'yellow' };
    } else {
      changes = { stroke: 'black', fill: 'white' };
    }

    if (null == this.diagramElemRegistry) {
      this.diagramElemRegistry = this.diagramModeler.get('elementRegistry');
    }
    const modeling = this.diagramModeler.get('modeling');
    const selectPizzaTask = this.diagramElemRegistry.get('_6-74');
    const orderPizzaTask = this.diagramElemRegistry.get('_6-127');
    console.log('selectPizzaTas ::', selectPizzaTask);
    console.log('orderPizzaTask ::', orderPizzaTask);
    console.log('modeling ', modeling);
    const changElements = [selectPizzaTask, orderPizzaTask];
    modeling.setColor(changElements, changes);
  }

  onCancelDiagram() {
    console.log('moving back to parent component');
    const params = { id: null };
    this.router.navigate([], { queryParams: params });
  }
}

Same behaviour even if i wait for 5 to 10 minutes.

So now doesn’t work after waiting for minutes either?

Yes, it doesn’t work without scrolling the page.