Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 13 additions & 24 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,9 @@
"utils:test:model": "node ./scripts/utils/dist/utils.mjs test/fixtures/bpmn/simple-start-task-end.bpmn --output model"
},
"dependencies": {
"@typed-mxgraph/typed-mxgraph": "~1.0.8",
"@maxgraph/core": "^0.20.0",
"es-toolkit": "~1.39.10",
"fast-xml-parser": "5.2.5",
"mxgraph": "4.2.2"
"fast-xml-parser": "5.2.5"
},
"devDependencies": {
"@asciidoctor/core": "~3.0.4",
Expand Down
42 changes: 34 additions & 8 deletions src/bpmn-visualization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@
limitations under the License.
*/

// Use mxgraph types
// The `preserve="true"` directive is required to retain types in the output starting from TypeScript 5.5.
// See https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html#preservetrue for details.
// It is sufficient to add the `preserve` attribute once across all triple-slash directives, as the API Extractor will merge them when generating the final single definition file.
/// <reference types="@typed-mxgraph/typed-mxgraph" preserve="true"/>

// Public API
export * from './component/options';
export { BpmnVisualization } from './component/BpmnVisualization';
Expand All @@ -33,5 +27,37 @@
export * from './component/mxgraph/style';
export * from './component/mxgraph/shape/render';

// the mxGraph context
export { mxgraph } from './component/mxgraph/initializer';
// the mxGraph context - for backward compatibility
// @deprecated Use direct imports from '@maxgraph/core' instead
import {

Check failure on line 32 in src/bpmn-visualization.ts

View workflow job for this annotation

GitHub Actions / build (macos-14)

Import in body of module; reorder to top

Check failure on line 32 in src/bpmn-visualization.ts

View workflow job for this annotation

GitHub Actions / build (ubuntu-24.04, -- --coverage)

Import in body of module; reorder to top

Check failure on line 32 in src/bpmn-visualization.ts

View workflow job for this annotation

GitHub Actions / build (ubuntu-24.04, -- --coverage)

Import in body of module; reorder to top

Check failure on line 32 in src/bpmn-visualization.ts

View workflow job for this annotation

GitHub Actions / build (windows-2022)

Import in body of module; reorder to top

Check failure on line 32 in src/bpmn-visualization.ts

View workflow job for this annotation

GitHub Actions / build (windows-2022)

Import in body of module; reorder to top

Check failure on line 32 in src/bpmn-visualization.ts

View workflow job for this annotation

GitHub Actions / build (macos-14)

Import in body of module; reorder to top
CellRenderer,
Client,
constants,
Dictionary,
EdgeStyle,
ImageShape,
InternalEvent,
Perimeter,
Point,
Rectangle,
RectangleShape,
SvgCanvas2D,
styleUtils,
} from '@maxgraph/core';

export const mxgraph = {
CellRenderer: CellRenderer,
mxCellRenderer: CellRenderer,
mxClient: Client,
mxConstants: constants,
mxDictionary: Dictionary,
mxEvent: InternalEvent,
mxPerimeter: Perimeter,
mxPoint: Point,
mxRectangle: Rectangle,
mxRectangleShape: RectangleShape,
mxSvgCanvas2D: SvgCanvas2D,
mxUtils: styleUtils,
ImageShape,
EdgeStyle,
};
26 changes: 13 additions & 13 deletions src/component/mxgraph/BpmnCellRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,49 +15,49 @@
*/

import type { IconPainter } from './shape/render';
import type { mxCellState, mxImageShape, mxShape } from 'mxgraph';
import type { CellState, ImageShape, Shape } from '@maxgraph/core';

import { mxgraph, mxRectangle } from './initializer';
import { CellRenderer, Dictionary, Rectangle } from '@maxgraph/core';

Check failure on line 20 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build (macos-14)

There should be at least one empty line between import groups

Check failure on line 20 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build (ubuntu-24.04, -- --coverage)

There should be at least one empty line between import groups

Check failure on line 20 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build (ubuntu-24.04, -- --coverage)

There should be at least one empty line between import groups

Check failure on line 20 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build (windows-2022)

There should be at least one empty line between import groups

Check failure on line 20 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build (windows-2022)

There should be at least one empty line between import groups

Check failure on line 20 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build (macos-14)

There should be at least one empty line between import groups
import { CustomCellOverlay } from './overlay/custom-overlay';
import { OverlayBadgeShape } from './overlay/shapes';
import { overrideCreateSvgCanvas } from './shape/utils';

export class BpmnCellRenderer extends mxgraph.mxCellRenderer {
export class BpmnCellRenderer extends CellRenderer {
constructor(private readonly iconPainter: IconPainter) {
super();
}

override createCellOverlays(state: mxCellState): void {
override createCellOverlays(state: CellState): void {
const graph = state.view.graph;
const overlays = graph.getCellOverlays(state.cell);
let dict = null;

if (overlays != null) {
dict = new mxgraph.mxDictionary<mxShape>();
dict = new Dictionary<Shape>();

Check failure on line 36 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build_and_test_npm_package

Expected 2 type arguments, but got 1.

Check failure on line 36 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build_and_test_npm_package

Expected 2 type arguments, but got 1.

for (const currentOverlay of overlays) {
const shape = state.overlays == null ? null : state.overlays.remove(currentOverlay);
if (shape != null) {
dict.put(currentOverlay, shape);

Check failure on line 41 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build_and_test_npm_package

Argument of type 'CellOverlay' is not assignable to parameter of type 'Shape'.

Check failure on line 41 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build_and_test_npm_package

Argument of type 'CellOverlay' is not assignable to parameter of type 'Shape'.
continue;
}

let overlayShape: mxShape;
let overlayShape: Shape;

// START bpmn-visualization CUSTOMIZATION
if (currentOverlay instanceof CustomCellOverlay) {
overlayShape = new OverlayBadgeShape(currentOverlay.label, new mxRectangle(0, 0, 0, 0), currentOverlay.style);
overlayShape = new OverlayBadgeShape(currentOverlay.label, new Rectangle(0, 0, 0, 0), currentOverlay.style);
} else {
overlayShape = new mxgraph.mxImageShape(new mxRectangle(0, 0, 0, 0), currentOverlay.image.src);
(overlayShape as mxImageShape).preserveImageAspect = false;
overlayShape = new ImageShape(new Rectangle(0, 0, 0, 0), currentOverlay.image.src);

Check failure on line 51 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build_and_test_npm_package

'ImageShape' cannot be used as a value because it was imported using 'import type'.

Check failure on line 51 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build_and_test_npm_package

'ImageShape' cannot be used as a value because it was imported using 'import type'.
(overlayShape as ImageShape).preserveImageAspect = false;
}
// END bpmn-visualization CUSTOMIZATION

overlayShape.dialect = state.view.graph.dialect;
overlayShape.overlay = currentOverlay;

// The 'initializeOverlay' signature forces us to hardly cast the overlayShape
this.initializeOverlay(state, overlayShape as mxImageShape);
this.initializeOverlay(state, overlayShape as ImageShape);
this.installCellOverlayListeners(state, currentOverlay, overlayShape);

if (currentOverlay.cursor != null) {
Expand All @@ -71,22 +71,22 @@
}
// END bpmn-visualization CUSTOMIZATION

dict.put(currentOverlay, overlayShape);

Check failure on line 74 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build_and_test_npm_package

Argument of type 'CellOverlay' is not assignable to parameter of type 'Shape'.

Check failure on line 74 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build_and_test_npm_package

Argument of type 'CellOverlay' is not assignable to parameter of type 'Shape'.
}
}

// Removes unused
if (state.overlays != null) {
// prefix parameter name - common practice to acknowledge the fact that some parameter is unused (e.g. in TypeScript compiler)
state.overlays.visit(function (_id: string, shape: mxShape) {
state.overlays.visit(function (_id: string, shape: Shape) {
shape.destroy();
});
}

state.overlays = dict;

Check failure on line 86 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build_and_test_npm_package

Type 'Dictionary<Shape, unknown>' is not assignable to type 'Dictionary<CellOverlay, Shape>'.

Check failure on line 86 in src/component/mxgraph/BpmnCellRenderer.ts

View workflow job for this annotation

GitHub Actions / build_and_test_npm_package

Type 'Dictionary<Shape, unknown>' is not assignable to type 'Dictionary<CellOverlay, Shape>'.
}

override createShape(state: mxCellState): mxShape {
override createShape(state: CellState): Shape {
const shape = super.createShape(state);
if ('iconPainter' in shape) {
shape.iconPainter = this.iconPainter;
Expand All @@ -95,7 +95,7 @@
return shape;
}

override createLabel(state: mxCellState, value: string): void {
override createLabel(state: CellState, value: string): void {
super.createLabel(state, value);
overrideCreateSvgCanvas(state.text);
}
Expand Down
17 changes: 9 additions & 8 deletions src/component/mxgraph/BpmnGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@
limitations under the License.
*/

import type { mxCellRenderer, mxCellState, mxGraphView, mxPoint } from 'mxgraph';
import type { CellRenderer, CellState, Point } from '@maxgraph/core';

import { Graph, GraphView } from '@maxgraph/core';

import { BpmnCellRenderer } from './BpmnCellRenderer';
import { mxgraph } from './initializer';
import { IconPainterProvider } from './shape/render';

export class BpmnGraph extends mxgraph.mxGraph {
export class BpmnGraph extends Graph {
/**
* @internal
*/
Expand All @@ -35,11 +36,11 @@
/**
* @internal
*/
override createGraphView(): mxGraphView {
override createGraphView(): GraphView {
return new BpmnGraphView(this);
}

override createCellRenderer(): mxCellRenderer {
override createCellRenderer(): CellRenderer {
// in the future, the IconPainter could be configured at library initialization and the provider could be removed
return new BpmnCellRenderer(IconPainterProvider.get());
}
Expand All @@ -51,10 +52,10 @@
*
* @param callbackFunction the update to be made in the transaction.
*
* @experimental subject to change, may move to a subclass of {@link mxGraphModel}
* @experimental subject to change, may move to a subclass of {@link GraphDataModel}
* @alpha
*/
batchUpdate(callbackFunction: () => void): void {

Check failure on line 58 in src/component/mxgraph/BpmnGraph.ts

View workflow job for this annotation

GitHub Actions / build_and_test_npm_package

This member must have an 'override' modifier because it overrides a member in the base class 'Graph'.

Check failure on line 58 in src/component/mxgraph/BpmnGraph.ts

View workflow job for this annotation

GitHub Actions / build_and_test_npm_package

This member must have an 'override' modifier because it overrides a member in the base class 'Graph'.
this.model.beginUpdate();
try {
callbackFunction();
Expand All @@ -64,8 +65,8 @@
}
}

class BpmnGraphView extends mxgraph.mxGraphView {
override getFloatingTerminalPoint(edge: mxCellState, start: mxCellState, end: mxCellState, source: boolean): mxPoint {
class BpmnGraphView extends GraphView {
override getFloatingTerminalPoint(edge: CellState, start: CellState, end: CellState, source: boolean): Point {
// some values may be null: the first and the last values are null prior computing floating terminal points
const edgePoints = edge.absolutePoints.filter(Boolean);
// when there is no BPMN waypoint, all values are null
Expand Down
33 changes: 18 additions & 15 deletions src/component/mxgraph/BpmnRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
import type ShapeBpmnElement from '../../model/bpmn/internal/shape/ShapeBpmnElement';
import type { RendererOptions } from '../options';
import type { RenderedModel } from '../registry/bpmn-model-registry';
import type { mxCell } from 'mxgraph';
import type { Cell } from '@maxgraph/core';

import { MessageVisibleKind, ShapeUtil } from '../../model/bpmn/internal';
import { MessageFlow } from '../../model/bpmn/internal/edge/flows';

import { mxPoint } from './initializer';
import { Point } from '@maxgraph/core';

Check failure on line 29 in src/component/mxgraph/BpmnRenderer.ts

View workflow job for this annotation

GitHub Actions / build (macos-14)

`@maxgraph/core` import should occur before import of `../../model/bpmn/internal`

Check failure on line 29 in src/component/mxgraph/BpmnRenderer.ts

View workflow job for this annotation

GitHub Actions / build (macos-14)

There should be at least one empty line between import groups

Check failure on line 29 in src/component/mxgraph/BpmnRenderer.ts

View workflow job for this annotation

GitHub Actions / build (ubuntu-24.04, -- --coverage)

`@maxgraph/core` import should occur before import of `../../model/bpmn/internal`

Check failure on line 29 in src/component/mxgraph/BpmnRenderer.ts

View workflow job for this annotation

GitHub Actions / build (ubuntu-24.04, -- --coverage)

There should be at least one empty line between import groups

Check failure on line 29 in src/component/mxgraph/BpmnRenderer.ts

View workflow job for this annotation

GitHub Actions / build (ubuntu-24.04, -- --coverage)

`@maxgraph/core` import should occur before import of `../../model/bpmn/internal`

Check failure on line 29 in src/component/mxgraph/BpmnRenderer.ts

View workflow job for this annotation

GitHub Actions / build (ubuntu-24.04, -- --coverage)

There should be at least one empty line between import groups

Check failure on line 29 in src/component/mxgraph/BpmnRenderer.ts

View workflow job for this annotation

GitHub Actions / build (windows-2022)

`@maxgraph/core` import should occur before import of `../../model/bpmn/internal`

Check failure on line 29 in src/component/mxgraph/BpmnRenderer.ts

View workflow job for this annotation

GitHub Actions / build (windows-2022)

There should be at least one empty line between import groups

Check failure on line 29 in src/component/mxgraph/BpmnRenderer.ts

View workflow job for this annotation

GitHub Actions / build (windows-2022)

`@maxgraph/core` import should occur before import of `../../model/bpmn/internal`

Check failure on line 29 in src/component/mxgraph/BpmnRenderer.ts

View workflow job for this annotation

GitHub Actions / build (windows-2022)

There should be at least one empty line between import groups

Check failure on line 29 in src/component/mxgraph/BpmnRenderer.ts

View workflow job for this annotation

GitHub Actions / build (macos-14)

`@maxgraph/core` import should occur before import of `../../model/bpmn/internal`

Check failure on line 29 in src/component/mxgraph/BpmnRenderer.ts

View workflow job for this annotation

GitHub Actions / build (macos-14)

There should be at least one empty line between import groups
import CoordinatesTranslator from './renderer/CoordinatesTranslator';
import StyleComputer from './renderer/StyleComputer';

Expand All @@ -46,7 +46,7 @@

private insertShapesAndEdges({ pools, lanes, subprocesses, otherFlowNodes, boundaryEvents, edges }: RenderedModel): void {
this.graph.batchUpdate(() => {
this.graph.getModel().clear(); // ensure to remove manual changes or already loaded graphs
this.graph.getDataModel().clear(); // ensure to remove manual changes or already loaded graphs
this.insertShapes(pools);
this.insertShapes(lanes);
this.insertShapes(subprocesses);
Expand All @@ -62,7 +62,7 @@
for (const shape of shapes) this.insertShape(shape);
}

private getParent(bpmnElement: ShapeBpmnElement): mxCell {
private getParent(bpmnElement: ShapeBpmnElement): Cell {
const bpmnElementParent = this.getCell(bpmnElement.parentId);
return bpmnElementParent ?? this.graph.getDefaultParent();
}
Expand All @@ -87,6 +87,7 @@
const target = this.getCell(bpmnElement.targetReferenceId);
const labelBounds = internalEdge.label?.bounds;
const style = this.styleComputer.computeStyle(internalEdge, labelBounds);
// @ts-expect-error - TODO maxgraph: style is string but maxGraph expects CellStyle object
const edge = this.graph.insertEdge(parent, bpmnElement.id, bpmnElement.name, source, target, style);
this.insertWaypoints(internalEdge.waypoints, edge);

Expand All @@ -97,43 +98,45 @@
const edgeCenterCoordinate = this.coordinatesTranslator.computeEdgeCenter(edge);
edge.geometry.relative = false;

const labelBoundsRelativeCoordinateFromParent = this.coordinatesTranslator.computeRelativeCoordinates(edge.parent, new mxPoint(labelBounds.x, labelBounds.y));
const labelBoundsRelativeCoordinateFromParent = this.coordinatesTranslator.computeRelativeCoordinates(edge.parent, new Point(labelBounds.x, labelBounds.y));
const relativeLabelX = labelBoundsRelativeCoordinateFromParent.x + labelBounds.width / 2 - edgeCenterCoordinate.x;
const relativeLabelY = labelBoundsRelativeCoordinateFromParent.y - edgeCenterCoordinate.y;
edge.geometry.offset = new mxPoint(relativeLabelX, relativeLabelY);
edge.geometry.offset = new Point(relativeLabelX, relativeLabelY);
}

this.insertMessageFlowIconIfNeeded(internalEdge, edge);
}
}

private insertMessageFlowIconIfNeeded(internalEdge: Edge, edge: mxCell): void {
private insertMessageFlowIconIfNeeded(internalEdge: Edge, edge: Cell): void {
if (internalEdge.bpmnElement instanceof MessageFlow && internalEdge.messageVisibleKind !== MessageVisibleKind.NONE) {
// @ts-expect-error - TODO maxgraph: style is string but maxGraph expects CellStyle object
const cell = this.graph.insertVertex(edge, messageFlowIconId(edge.id), undefined, 0, 0, 20, 14, this.styleComputer.computeMessageFlowIconStyle(internalEdge));
cell.geometry.relative = true;
cell.geometry.offset = new mxPoint(-10, -7);
cell.geometry.offset = new Point(-10, -7);
}
}

private insertWaypoints(waypoints: Waypoint[], edge: mxCell): void {
private insertWaypoints(waypoints: Waypoint[], edge: Cell): void {
if (waypoints) {
edge.geometry.points = waypoints.map(waypoint => this.coordinatesTranslator.computeRelativeCoordinates(edge.parent, new mxPoint(waypoint.x, waypoint.y)));
edge.geometry.points = waypoints.map(waypoint => this.coordinatesTranslator.computeRelativeCoordinates(edge.parent, new Point(waypoint.x, waypoint.y)));
}
}

private getCell(id: string): mxCell {
return this.graph.getModel().getCell(id);
private getCell(id: string): Cell {
return this.graph.getDataModel().getCell(id);
}

private insertVertex(parent: mxCell, id: string | null, value: string, bounds: Bounds, labelBounds: Bounds, style?: string): mxCell {
const vertexCoordinates = this.coordinatesTranslator.computeRelativeCoordinates(parent, new mxPoint(bounds.x, bounds.y));
private insertVertex(parent: Cell, id: string | null, value: string, bounds: Bounds, labelBounds: Bounds, style?: string): Cell {
const vertexCoordinates = this.coordinatesTranslator.computeRelativeCoordinates(parent, new Point(bounds.x, bounds.y));
// @ts-expect-error - TODO maxgraph: style is string but maxGraph expects CellStyle object
const cell = this.graph.insertVertex(parent, id, value, vertexCoordinates.x, vertexCoordinates.y, bounds.width, bounds.height, style);

if (labelBounds) {
// label coordinates are relative in the cell referential coordinates
const relativeLabelX = labelBounds.x - bounds.x;
const relativeLabelY = labelBounds.y - bounds.y;
cell.geometry.offset = new mxPoint(relativeLabelX, relativeLabelY);
cell.geometry.offset = new Point(relativeLabelX, relativeLabelY);
}
return cell;
}
Expand Down
2 changes: 1 addition & 1 deletion src/component/mxgraph/GraphConfigurator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
this.graph.setCellsSelectable(false);
this.graph.setEdgeLabelsMovable(false);

this.graph.setHtmlLabels(true); // required for wrapping
this.graph.htmlLabels = true; // required for wrapping

// To have the boundary event on the border of a task
this.graph.setConstrainChildren(false);
Expand All @@ -54,6 +54,6 @@

// Disable folding for container cells (pool, lane, sub process, call activity) because we don't need it.
// This also prevents requesting unavailable images (see #185) as we don't override BpmnGraph folding default images.
this.graph.foldingEnabled = false;

Check failure on line 57 in src/component/mxgraph/GraphConfigurator.ts

View workflow job for this annotation

GitHub Actions / build_and_test_npm_package

Property 'foldingEnabled' does not exist on type 'BpmnGraph'. Did you mean 'isFoldingEnabled'?

Check failure on line 57 in src/component/mxgraph/GraphConfigurator.ts

View workflow job for this annotation

GitHub Actions / build_and_test_npm_package

Property 'foldingEnabled' does not exist on type 'BpmnGraph'. Did you mean 'isFoldingEnabled'?
}
}
Loading
Loading