Skip to content
Merged
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
6 changes: 3 additions & 3 deletions docs/bpmn-support.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,9 @@ The default rendering uses `white` as fill color and `black` as stroke color.

|Exclusive
|icon:check-circle-o[]
|
|Icon may be subject to change +

|Parallel
|
|
|icon:check-circle-o[]
|Icon may be subject to change +
|===
3 changes: 2 additions & 1 deletion src/component/mxgraph/ShapeConfigurator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { MxGraphFactoryService } from '../../service/MxGraphFactoryService';
import { mxgraph } from 'ts-mxgraph';
import { ShapeBpmnElementKind } from '../../model/bpmn/shape/ShapeBpmnElementKind';
import { EndEventShape, StartEventShape, ThrowIntermediateEventShape } from './shape/event-shapes';
import { ExclusiveGatewayShape } from './shape/gateway-shapes';
import { ExclusiveGatewayShape, ParallelGatewayShape } from './shape/gateway-shapes';
import { ServiceTaskShape, TaskShape, UserTaskShape } from './shape/task-shapes';

export default class ShapeConfigurator {
Expand All @@ -35,6 +35,7 @@ export default class ShapeConfigurator {
this.mxCellRenderer.registerShape(ShapeBpmnElementKind.EVENT_START, StartEventShape);
this.mxCellRenderer.registerShape(ShapeBpmnElementKind.EVENT_INTERMEDIATE_THROW, ThrowIntermediateEventShape);
this.mxCellRenderer.registerShape(ShapeBpmnElementKind.GATEWAY_EXCLUSIVE, ExclusiveGatewayShape);
this.mxCellRenderer.registerShape(ShapeBpmnElementKind.GATEWAY_PARALLEL, ParallelGatewayShape);
this.mxCellRenderer.registerShape(ShapeBpmnElementKind.TASK, TaskShape);
this.mxCellRenderer.registerShape(ShapeBpmnElementKind.TASK_SERVICE, ServiceTaskShape);
this.mxCellRenderer.registerShape(ShapeBpmnElementKind.TASK_USER, UserTaskShape);
Expand Down
17 changes: 0 additions & 17 deletions src/component/mxgraph/StyleConfigurator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export default class StyleConfigurator {
this.configureTasksStyle();
// gateways
this.configureGatewaysStyle();
this.configureParallelGatewayStyle();
}

private getStylesheet(): any {
Expand Down Expand Up @@ -117,22 +116,6 @@ export default class StyleConfigurator {
});
}

// TODO: to be removed as it will be configured in configureGatewaysStyle
// left just to not break current rendering
private configureParallelGatewayStyle(): void {
const style = this.cloneDefaultVertexStyle();
style[this.mxConstants.STYLE_SHAPE] = this.mxConstants.SHAPE_RHOMBUS;
style[this.mxConstants.STYLE_PERIMETER] = this.mxPerimeter.RhombusPerimeter;
style[this.mxConstants.STYLE_VERTICAL_ALIGN] = 'top';
style[this.mxConstants.STYLE_STROKECOLOR] = '#96A826';
style[this.mxConstants.STYLE_STROKEWIDTH] = 1.7;

style[this.mxConstants.STYLE_SPACING_TOP] = 55;
style[this.mxConstants.STYLE_SPACING_RIGHT] = 110;
style[this.mxConstants.STYLE_GRADIENTCOLOR] = '#E9ECB1';
this.putCellStyle(ShapeBpmnElementKind.GATEWAY_PARALLEL, style);
}

private configureGatewaysStyle(): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aibcmars Can you remove unnecessary line style[this.mxConstants.STYLE_PERIMETER] = this.mxPerimeter.RhombusPerimeter; ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we please stop noticing this? we have to understand why this is put in all mxGraph examples
This seems to be ok without for our rendering but we do not know what is the purpose of this.
I suggest we manage this later and track this with a dedicated issue

What I have understood so far is that the perimeter provides the list of points that can be used to attach edges to the current shape. This could be usefull for automatic rendering.
I know we are supposed to have the waypoints in the BPMN files that should define the point on the shape where the edge must be attached, but without exactly knowing what is going on, it is to early to remove the perimeters from the style IMHO

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Thomas, as yesterday stated: we have found it occurs in all mxgraph examples concerning RHOMBUS.

ShapeUtil.gatewayKinds().forEach(kind => {
const style = this.cloneDefaultVertexStyle();
Expand Down
103 changes: 81 additions & 22 deletions src/component/mxgraph/shape/gateway-shapes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import { MxGraphFactoryService } from '../../../service/MxGraphFactoryService';
import { mxgraph } from 'ts-mxgraph';
import { StyleConstant } from '../StyleConfigurator';
import MxScaleFactorCanvas from '../extension/MxScaleFactorCanvas';

const mxRhombus: typeof mxgraph.mxRhombus = MxGraphFactoryService.getMxGraphProperty('mxRhombus');
const mxUtils: typeof mxgraph.mxUtils = MxGraphFactoryService.getMxGraphProperty('mxUtils');
Expand All @@ -27,18 +28,50 @@ abstract class GatewayShape extends mxRhombus {
super(bounds, fill, stroke, strokewidth);
}

protected abstract paintInnerShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void;

public paintVertexShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void {
this.paintOuterShape(c, x, y, w, h);
c.setFillColor(this.stroke);
c.setStrokeWidth(0);
this.paintInnerShape(c, x, y, w, h);
}

protected paintOuterShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void {
super.paintVertexShape(c, x, y, w, h);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
protected paintInnerShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void {
// do nothing by default
// TODO: will be removed when exclusive gateway will use MXScaleFactorCanvas
protected getScaledGeometry(x: number, y: number, w: number, h: number): { xS: number; yS: number; wS: number; hS: number } {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ good to share code! 😄
I have noticed that we didn't communicate well about the icon scaling and position of elements in the task (what I did) and gateway (what you did) shapes and we now have 2 ways of doing things 😯

I have introduced a MxScaleFactorCanvas class in charge of hidding the scaling

// vanilla canvas calls when a scale factor must be applied to positions
const scaleFactor = 0.26;
c.moveTo(8 * scaleFactor, 39 * scaleFactor);
c.lineTo(12 * scaleFactor, 25 * scaleFactor);

// MxScaleFactorCanvas
const canvas = new MxScaleFactorCanvas(c, 0.26);
canvas.moveTo(8, 39);
canvas.lineTo(12, 25);

This makes the code clearer than in the current gateway implementation. However, it only scales the x and y direction with the same value.

In the gateway side, you introduce a way to manage the translation required to position the icon. In the task shape, this is done globally by a translation of the current cursor which has a side effect: after icon drawing, the orgin coordinates have changed, so subsequent drawing won't be done at the right place, except if we remember to reset the origin coordinates at the end of the task icon drawing! For sure, this will create issue in the future when we will draw the task markers.

So to me, we have to merge the good part of the 2 implementations in a new single one, especially if we want to benefits of it for event icons.

I suggest that we keep the gateway icon implementation as it is now in this PR but we manage a refactoring very soon (let's say next week) with @csouchet as well. If you agree, I can create an issue to track this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as discussed with @aibcmars, this will be managed in #226

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, done in 226 so resolving this conversation

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not fully implemented in #226, so unresolving

const symbolScale = this.getInnerSymbolScale(w, h);
return {
xS: x + symbolScale,
yS: y + symbolScale,
wS: w - 2 * symbolScale,
hS: h - 2 * symbolScale,
};
}

// TODO: will be removed when exclusive gateway will use MXScaleFactorCanvas
private getInnerSymbolScale(w: number, h: number): number {
return 3 * mxUtils.getValue(this.style, mxConstants.STYLE_MARGIN, Math.min(3 + this.strokewidth, Math.min(w / 5, h / 5)));
}

protected configureCanvasForIcon(c: mxgraph.mxXmlCanvas2D, parentWidth: number, parentHeight: number, iconOriginalSize: number): MxScaleFactorCanvas {
// ensure we are not impacted by the configured shape stroke width
c.setStrokeWidth(1);

const parentSize = Math.min(parentWidth, parentHeight);
const ratioFromParent = 0.25;
const scaleFactor = iconOriginalSize !== 0 ? (parentSize / iconOriginalSize) * ratioFromParent : 0.5;

return new MxScaleFactorCanvas(c, scaleFactor);
}

protected translateToStartingIconPosition(c: mxgraph.mxXmlCanvas2D, parentX: number, parentY: number, parentWidth: number, parentHeight: number): void {
const xTranslation = parentX + parentWidth / 4;
const yTranslation = parentY + parentHeight / 4;
c.translate(xTranslation, yTranslation);
}
}

Expand All @@ -52,29 +85,55 @@ export class ExclusiveGatewayShape extends GatewayShape {
}

private addExclusiveGatewaySymbol(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void {
const symbolScale = 3 * mxUtils.getValue(this.style, mxConstants.STYLE_MARGIN, Math.min(3 + this.strokewidth, Math.min(w / 5, h / 5)));
x += symbolScale;
y += symbolScale;
w -= 2 * symbolScale;
h -= 2 * symbolScale;
c.setFillColor(this.stroke);
c.setStrokeWidth(0);
const { xS, yS, wS, hS } = this.getScaledGeometry(x, y, w, h);

c.begin();
c.moveTo(x + w * 0.105, y);
c.lineTo(x + w * 0.5, y + h * 0.38);
c.lineTo(x + w * 0.895, y);
c.lineTo(x + w, y + h * 0.11);
c.lineTo(x + w * 0.6172, y + h * 0.5);
c.lineTo(x + w, y + h * 0.89);
c.lineTo(x + w * 0.895, y + h);
c.lineTo(x + w * 0.5, y + h * 0.62);
c.lineTo(x + w * 0.105, y + h);
c.lineTo(x, y + h * 0.89);
c.lineTo(x + w * 0.3808, y + h * 0.5);
c.lineTo(x, y + h * 0.11);
c.moveTo(xS + wS * 0.105, yS);
c.lineTo(xS + wS * 0.5, yS + hS * 0.38);
c.lineTo(xS + wS * 0.895, yS);
c.lineTo(xS + wS, yS + hS * 0.11);
c.lineTo(xS + wS * 0.6172, yS + hS * 0.5);
c.lineTo(xS + wS, yS + hS * 0.89);
c.lineTo(xS + wS * 0.895, yS + hS);
c.lineTo(xS + wS * 0.5, yS + hS * 0.62);
c.lineTo(xS + wS * 0.105, yS + hS);
c.lineTo(xS, yS + hS * 0.89);
c.lineTo(xS + wS * 0.3808, yS + hS * 0.5);
c.lineTo(xS, yS + hS * 0.11);
c.close();

c.fillAndStroke();
}
}

export class ParallelGatewayShape extends GatewayShape {
public constructor(bounds: mxgraph.mxRectangle, fill: string, stroke: string, strokewidth: number = StyleConstant.STROKE_WIDTH_THIN) {
super(bounds, fill, stroke, strokewidth);
}

protected paintInnerShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void {
this.addParallelGatewaySymbol(c, x, y, w, h);
}

private addParallelGatewaySymbol(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void {
const canvas = this.configureCanvasForIcon(c, w, h, 0);
this.translateToStartingIconPosition(c, x, y, w, h);

canvas.begin();
canvas.moveTo(w * 0.38, 0);
canvas.lineTo(w * 0.62, 0);
canvas.lineTo(w * 0.62, h * 0.38);
canvas.lineTo(w, h * 0.38);
canvas.lineTo(w, h * 0.62);
canvas.lineTo(w * 0.62, h * 0.62);
canvas.lineTo(w * 0.62, h);
canvas.lineTo(w * 0.38, h);
canvas.lineTo(w * 0.38, h * 0.62);
canvas.lineTo(0, h * 0.62);
canvas.lineTo(0, h * 0.38);
canvas.lineTo(w * 0.38, h * 0.38);
canvas.close();

canvas.fillAndStroke();
}
}