From e975cdb59f82f5952c0c7b012fc512af6d8b2565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9line=20Souchet?= Date: Wed, 29 Apr 2020 16:50:08 +0200 Subject: [PATCH 1/4] Add final render of Throw Message intermediate event --- src/component/mxgraph/shape/event-shapes.ts | 28 ++++++++------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/component/mxgraph/shape/event-shapes.ts b/src/component/mxgraph/shape/event-shapes.ts index 262cc6b29f..90e28081c6 100644 --- a/src/component/mxgraph/shape/event-shapes.ts +++ b/src/component/mxgraph/shape/event-shapes.ts @@ -59,9 +59,16 @@ abstract class EventShape extends mxEllipse { c.setFillAlpha(0.3); } + protected paintEventIcon(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number, isInverse = false): void { + const eventKind = this.getBpmnEventKind(); + if (eventKind == ShapeBpmnEventKind.MESSAGE) { + this.paintMessageEventIcon(c, x, y, w, h, isInverse); + } + } + // this implementation is adapted from the draw.io BPMN 'message' symbol // https://github.com/jgraph/drawio/blob/0e19be6b42755790a749af30450c78c0d83be765/src/main/webapp/shapes/bpmn/mxBpmnShape2.js#L465 - private paintMessageIcon(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number, isInverse = false): void { + private paintMessageEventIcon(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number, isInverse = false): void { // Change the coordinate referential c.translate(x + w * 0.24, y + h * 0.34); w = w * 0.52; @@ -110,10 +117,6 @@ abstract class EventShape extends mxEllipse { c.stroke(); } - - protected paintThrowMessageIcon(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { - this.paintMessageIcon(c, x, y, w, h, true); - } } export class StartEventShape extends EventShape { @@ -194,14 +197,8 @@ export class CatchIntermediateEventShape extends IntermediateEventShape { super(bounds, fill, stroke, strokewidth); } - // TODO: will be removed when managing the message rendering - protected paintOuterShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { - const eventKind = this.getBpmnEventKind(); - if (eventKind == ShapeBpmnEventKind.MESSAGE) { - this.paintOuterMessageShape(c); - } - - super.paintOuterShape(c, x, y, w, h); + protected paintInnerShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { + this.paintEventIcon(c, x, y, w, h); } } export class ThrowIntermediateEventShape extends IntermediateEventShape { @@ -210,9 +207,6 @@ export class ThrowIntermediateEventShape extends IntermediateEventShape { } protected paintInnerShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { - const eventKind = this.getBpmnEventKind(); - if (eventKind == ShapeBpmnEventKind.MESSAGE) { - this.paintThrowMessageIcon(c, x, y, w, h); - } + this.paintEventIcon(c, x, y, w, h, true); } } From 43ad04f66f7f26266b91c0d18d4a03db3b7c94dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9line=20Souchet?= Date: Wed, 6 May 2020 10:51:48 +0200 Subject: [PATCH 2/4] Add the render of Catch Message Intermediate Event --- docs/bpmn-support.adoc | 4 ++-- src/component/mxgraph/shape/event-shapes.ts | 10 +++++----- test/e2e/View.test.ts | 7 +++++++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/bpmn-support.adoc b/docs/bpmn-support.adoc index 7ba837c3cd..c51eb3e6dd 100644 --- a/docs/bpmn-support.adoc +++ b/docs/bpmn-support.adoc @@ -103,8 +103,8 @@ The default rendering uses `white` as fill color and `black` as stroke color. |Stroke fits the BPMN specification but no icon |Message Intermediate Catch Event -| -|Stroke fits the BPMN specification but no icon +|icon:check-circle-o[] +|The stroke & icon width may be adjusted |=== [cols="1,1,4", options="header"] diff --git a/src/component/mxgraph/shape/event-shapes.ts b/src/component/mxgraph/shape/event-shapes.ts index 90e28081c6..d71f936333 100644 --- a/src/component/mxgraph/shape/event-shapes.ts +++ b/src/component/mxgraph/shape/event-shapes.ts @@ -59,16 +59,16 @@ abstract class EventShape extends mxEllipse { c.setFillAlpha(0.3); } - protected paintEventIcon(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number, isInverse = false): void { + protected paintIcon(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number, isInverse = false): void { const eventKind = this.getBpmnEventKind(); if (eventKind == ShapeBpmnEventKind.MESSAGE) { - this.paintMessageEventIcon(c, x, y, w, h, isInverse); + this.paintMessageIcon(c, x, y, w, h, isInverse); } } // this implementation is adapted from the draw.io BPMN 'message' symbol // https://github.com/jgraph/drawio/blob/0e19be6b42755790a749af30450c78c0d83be765/src/main/webapp/shapes/bpmn/mxBpmnShape2.js#L465 - private paintMessageEventIcon(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number, isInverse = false): void { + private paintMessageIcon(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number, isInverse = false): void { // Change the coordinate referential c.translate(x + w * 0.24, y + h * 0.34); w = w * 0.52; @@ -198,7 +198,7 @@ export class CatchIntermediateEventShape extends IntermediateEventShape { } protected paintInnerShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { - this.paintEventIcon(c, x, y, w, h); + this.paintIcon(c, x, y, w, h); } } export class ThrowIntermediateEventShape extends IntermediateEventShape { @@ -207,6 +207,6 @@ export class ThrowIntermediateEventShape extends IntermediateEventShape { } protected paintInnerShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { - this.paintEventIcon(c, x, y, w, h, true); + this.paintIcon(c, x, y, w, h, true); } } diff --git a/test/e2e/View.test.ts b/test/e2e/View.test.ts index 61cec3881e..0c4358a6a7 100644 --- a/test/e2e/View.test.ts +++ b/test/e2e/View.test.ts @@ -60,6 +60,9 @@ describe('BPMN Visualization JS', () => { + + + Flow_028jkgv @@ -114,6 +117,9 @@ describe('BPMN Visualization JS', () => { + + + @@ -202,6 +208,7 @@ describe('BPMN Visualization JS', () => { expectModelContainsBpmnEvent('endEvent_1', ShapeBpmnElementKind.EVENT_END, ShapeBpmnEventKind.TERMINATE); expectModelContainsBpmnEvent('noneIntermediateThrowEvent', ShapeBpmnElementKind.EVENT_INTERMEDIATE_THROW, ShapeBpmnEventKind.NONE); expectModelContainsBpmnEvent('messageIntermediateThrowEvent', ShapeBpmnElementKind.EVENT_INTERMEDIATE_THROW, ShapeBpmnEventKind.MESSAGE); + expectModelContainsBpmnEvent('messageIntermediateCatchEvent', ShapeBpmnElementKind.EVENT_INTERMEDIATE_CATCH, ShapeBpmnEventKind.MESSAGE); expectModelContainsBpmnEvent('IntermediateCatchEvent_Timer_01', ShapeBpmnElementKind.EVENT_INTERMEDIATE_CATCH, ShapeBpmnEventKind.TIMER); expectModelContainsCell('task_1', ShapeBpmnElementKind.TASK); expectModelContainsCell('serviceTask_2', ShapeBpmnElementKind.TASK_SERVICE); From a30ba36d1878323251aebe0b6cfa9a3a96c3ca1e Mon Sep 17 00:00:00 2001 From: Thomas Bouffard <27200110+tbouffard@users.noreply.github.com> Date: Thu, 7 May 2020 00:37:01 +0200 Subject: [PATCH 3/4] [REFACTOR] generalize icons management Introduce a declarative way for the bpmn event render icon method selection This uses a more functional way of doing things instead of having several if/else or switch which brings more clarity and will simplify extensions. Simplify how we handle catch/throw icon render This is now hold by the Shape class itself allowing icon render method to easily know if a Throw or Catch icon has to be painted. Prior this change, we had to pass argument to several methods which made the code hard to follow. Introduce a single place to manage events currently displayed with a arbitrary fill color prior we implement their final icon. This was prior done at several places which make the code hard to follow and was error prone: we have broken the render of such BPMN events several times in the past. --- src/component/mxgraph/shape/event-shapes.ts | 107 ++++++++------------ 1 file changed, 43 insertions(+), 64 deletions(-) diff --git a/src/component/mxgraph/shape/event-shapes.ts b/src/component/mxgraph/shape/event-shapes.ts index d71f936333..edac84201a 100644 --- a/src/component/mxgraph/shape/event-shapes.ts +++ b/src/component/mxgraph/shape/event-shapes.ts @@ -24,51 +24,63 @@ const mxUtils: typeof mxgraph.mxUtils = MxGraphFactoryService.getMxGraphProperty const mxConstants: typeof mxgraph.mxConstants = MxGraphFactoryService.getMxGraphProperty('mxConstants'); abstract class EventShape extends mxEllipse { + // when all/more event types will be supported, we could move to a Record/MappedType + private iconPainters: Map void> = new Map([ + [ShapeBpmnEventKind.MESSAGE, (c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number) => this.paintMessageIcon(c, x, y, w, h)], + [ShapeBpmnEventKind.TERMINATE, (c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number) => this.paintTerminateIcon(c, x, y, w, h)], + ]); + protected isUsingThrowIcons = false; + protected constructor(bounds: mxgraph.mxRectangle, fill: string, stroke: string, strokewidth: number) { super(bounds, fill, stroke, strokewidth); } public paintVertexShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { + this.markNonFullyRenderedEvents(c); + this.paintOuterShape(c, x, y, w, h); + this.paintInnerShape(c, x, y, w, h); + } + + // This will be removed when managing the render of all events + private markNonFullyRenderedEvents(c: mxgraph.mxXmlCanvas2D): void { const eventKind = this.getBpmnEventKind(); - // will be removed when managing the timer rendering if (eventKind == ShapeBpmnEventKind.TIMER) { c.setFillColor('green'); c.setFillAlpha(0.3); + } // eslint-disable-next-line @typescript-eslint/no-use-before-define + else if (eventKind == ShapeBpmnEventKind.MESSAGE && (this instanceof StartEventShape || this instanceof EndEventShape)) { + c.setFillColor('yellow'); + c.setFillAlpha(0.3); } - - this.paintOuterShape(c, x, y, w, h); - 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 + const iconPainter = + this.iconPainters.get(this.getBpmnEventKind()) || ((c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number) => this.paintEmptyIcon(c, x, y, w, h)); + iconPainter(c, x, y, w, h); } - protected getBpmnEventKind(): ShapeBpmnEventKind { + private getBpmnEventKind(): ShapeBpmnEventKind { return mxUtils.getValue(this.style, StyleConstant.BPMN_STYLE_EVENT_KIND, ShapeBpmnEventKind.NONE); } - // TODO: will be removed when managing the message rendering - protected paintOuterMessageShape(c: mxgraph.mxXmlCanvas2D): void { - c.setFillColor('yellow'); - c.setFillAlpha(0.3); - } - - protected paintIcon(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number, isInverse = false): void { - const eventKind = this.getBpmnEventKind(); - if (eventKind == ShapeBpmnEventKind.MESSAGE) { - this.paintMessageIcon(c, x, y, w, h, isInverse); - } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private paintEmptyIcon(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { + // empty by nature } // this implementation is adapted from the draw.io BPMN 'message' symbol // https://github.com/jgraph/drawio/blob/0e19be6b42755790a749af30450c78c0d83be765/src/main/webapp/shapes/bpmn/mxBpmnShape2.js#L465 - private paintMessageIcon(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number, isInverse = false): void { + private paintMessageIcon(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { + // eslint-disable-next-line @typescript-eslint/no-use-before-define + if (!(this instanceof IntermediateEventShape)) { + return; + } + const isInverse = this.isUsingThrowIcons; // Change the coordinate referential c.translate(x + w * 0.24, y + h * 0.34); w = w * 0.52; @@ -117,38 +129,9 @@ abstract class EventShape extends mxEllipse { c.stroke(); } -} - -export class StartEventShape extends EventShape { - public constructor(bounds: mxgraph.mxRectangle, fill: string, stroke: string, strokewidth: number = StyleConstant.STROKE_WIDTH_THIN) { - super(bounds, fill, stroke, strokewidth); - } - - // TODO: will be removed when managing the message rendering - protected paintOuterShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { - const eventKind = this.getBpmnEventKind(); - if (eventKind == ShapeBpmnEventKind.MESSAGE) { - this.paintOuterMessageShape(c); - } - - super.paintOuterShape(c, x, y, w, h); - } -} - -export class EndEventShape extends EventShape { - public constructor(bounds: mxgraph.mxRectangle, fill: string, stroke: string, strokewidth: number = StyleConstant.STROKE_WIDTH_THICK) { - super(bounds, fill, stroke, strokewidth); - } - - protected paintInnerShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { - const eventKind = this.getBpmnEventKind(); - if (eventKind == ShapeBpmnEventKind.TERMINATE) { - this.paintTerminateEventIcon(c, x, y, w, h); - } - } // highly inspired from mxDoubleEllipse - private paintTerminateEventIcon(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { + private paintTerminateIcon(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { c.setFillColor(this.stroke); c.setStrokeWidth(0); const inset = mxUtils.getValue(this.style, mxConstants.STYLE_MARGIN, Math.min(3 + this.strokewidth, Math.min(w / 5, h / 5))); @@ -163,15 +146,17 @@ export class EndEventShape extends EventShape { c.fillAndStroke(); } +} - // TODO: will be removed when managing the message rendering - protected paintOuterShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { - const eventKind = this.getBpmnEventKind(); - if (eventKind == ShapeBpmnEventKind.MESSAGE) { - this.paintOuterMessageShape(c); - } +export class StartEventShape extends EventShape { + public constructor(bounds: mxgraph.mxRectangle, fill: string, stroke: string, strokewidth: number = StyleConstant.STROKE_WIDTH_THIN) { + super(bounds, fill, stroke, strokewidth); + } +} - super.paintOuterShape(c, x, y, w, h); +export class EndEventShape extends EventShape { + public constructor(bounds: mxgraph.mxRectangle, fill: string, stroke: string, strokewidth: number = StyleConstant.STROKE_WIDTH_THICK) { + super(bounds, fill, stroke, strokewidth); } } @@ -196,17 +181,11 @@ export class CatchIntermediateEventShape extends IntermediateEventShape { public constructor(bounds: mxgraph.mxRectangle, fill: string, stroke: string, strokewidth?: number) { super(bounds, fill, stroke, strokewidth); } - - protected paintInnerShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { - this.paintIcon(c, x, y, w, h); - } } + export class ThrowIntermediateEventShape extends IntermediateEventShape { public constructor(bounds: mxgraph.mxRectangle, fill: string, stroke: string, strokewidth?: number) { super(bounds, fill, stroke, strokewidth); - } - - protected paintInnerShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { - this.paintIcon(c, x, y, w, h, true); + this.isUsingThrowIcons = true; } } From 4b736f61cc4f395ee07994c42064d69d00f70abd Mon Sep 17 00:00:00 2001 From: Thomas Bouffard <27200110+tbouffard@users.noreply.github.com> Date: Tue, 12 May 2020 17:08:43 +0200 Subject: [PATCH 4/4] rename the constant that stores the function that paints the icon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Souchet Céline <4921914+csouchet@users.noreply.github.com> --- src/component/mxgraph/shape/event-shapes.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/component/mxgraph/shape/event-shapes.ts b/src/component/mxgraph/shape/event-shapes.ts index edac84201a..0f599082ba 100644 --- a/src/component/mxgraph/shape/event-shapes.ts +++ b/src/component/mxgraph/shape/event-shapes.ts @@ -59,9 +59,9 @@ abstract class EventShape extends mxEllipse { } protected paintInnerShape(c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number): void { - const iconPainter = + const paintIcon = this.iconPainters.get(this.getBpmnEventKind()) || ((c: mxgraph.mxXmlCanvas2D, x: number, y: number, w: number, h: number) => this.paintEmptyIcon(c, x, y, w, h)); - iconPainter(c, x, y, w, h); + paintIcon(c, x, y, w, h); } private getBpmnEventKind(): ShapeBpmnEventKind {