diff --git a/docs/bpmn-support.adoc b/docs/bpmn-support.adoc index 03666a5f85..6c97ca02fb 100644 --- a/docs/bpmn-support.adoc +++ b/docs/bpmn-support.adoc @@ -122,7 +122,7 @@ The default rendering uses `white` as fill color and `black` as stroke color. |Comments |Exclusive -| +|icon:check-circle-o[] | |Parallel diff --git a/src/component/mxgraph/ShapeConfigurator.ts b/src/component/mxgraph/ShapeConfigurator.ts index 8e47ea2227..3628a30b1b 100644 --- a/src/component/mxgraph/ShapeConfigurator.ts +++ b/src/component/mxgraph/ShapeConfigurator.ts @@ -17,6 +17,7 @@ import { MxGraphFactoryService } from '../../service/MxGraphFactoryService'; import { mxgraph } from 'ts-mxgraph'; import { ShapeBpmnElementKind } from '../../model/bpmn/shape/ShapeBpmnElementKind'; import { EndEventShape, StartEventShape } from './shape/event-shapes'; +import { ExclusiveGatewayShape } from './shape/gateway-shapes'; import { TaskShape } from './shape/task-shapes'; export default class ShapeConfigurator { @@ -32,6 +33,7 @@ export default class ShapeConfigurator { private registerShapes(): void { this.mxCellRenderer.registerShape(ShapeBpmnElementKind.EVENT_END, EndEventShape); this.mxCellRenderer.registerShape(ShapeBpmnElementKind.EVENT_START, StartEventShape); + this.mxCellRenderer.registerShape(ShapeBpmnElementKind.GATEWAY_EXCLUSIVE, ExclusiveGatewayShape); this.mxCellRenderer.registerShape(ShapeBpmnElementKind.TASK, TaskShape); } diff --git a/src/component/mxgraph/StyleConfigurator.ts b/src/component/mxgraph/StyleConfigurator.ts index e6d8eb62f4..f3fff8e743 100644 --- a/src/component/mxgraph/StyleConfigurator.ts +++ b/src/component/mxgraph/StyleConfigurator.ts @@ -45,8 +45,8 @@ export default class StyleConfigurator { this.configureServiceTaskStyle(); this.configureTaskStyle(); // gateways + this.configureGatewaysStyle(); this.configureParallelGatewayStyle(); - this.configureExclusiveGatewayStyle(); } private getStylesheet(): any { @@ -133,6 +133,8 @@ export default class StyleConfigurator { this.putCellStyle(ShapeBpmnElementKind.TASK, style); } + // 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; @@ -147,9 +149,19 @@ export default class StyleConfigurator { this.putCellStyle(ShapeBpmnElementKind.GATEWAY_PARALLEL, style); } - private configureExclusiveGatewayStyle(): void { - const style = this.mxUtils.clone(this.getStylesheet().getCellStyle(ShapeBpmnElementKind.GATEWAY_PARALLEL), this.getDefaultVertexStyle()); - style[this.mxConstants.STYLE_GRADIENTCOLOR] = '#DDA0DD'; - this.putCellStyle(ShapeBpmnElementKind.GATEWAY_EXCLUSIVE, style); + private configureGatewaysStyle(): void { + ShapeUtil.gatewayKinds().forEach(kind => { + const style = this.cloneDefaultVertexStyle(); + style[this.mxConstants.STYLE_SHAPE] = kind; + style[this.mxConstants.STYLE_PERIMETER] = this.mxPerimeter.RhombusPerimeter; + style[this.mxConstants.STYLE_VERTICAL_ALIGN] = 'top'; + + // TODO to be removed when supporting label position + // left just to not break current rendering + style[this.mxConstants.STYLE_SPACING_TOP] = 55; + style[this.mxConstants.STYLE_SPACING_RIGHT] = 110; + + this.putCellStyle(kind, style); + }); } } diff --git a/src/component/mxgraph/shape/gateway-shapes.ts b/src/component/mxgraph/shape/gateway-shapes.ts new file mode 100644 index 0000000000..7fe4838cfd --- /dev/null +++ b/src/component/mxgraph/shape/gateway-shapes.ts @@ -0,0 +1,80 @@ +/** + * Copyright 2020 Bonitasoft S.A. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { MxGraphFactoryService } from '../../../service/MxGraphFactoryService'; +import { mxgraph } from 'ts-mxgraph'; +import { StyleConstant } from '../StyleConfigurator'; + +const mxRhombus: typeof mxgraph.mxRhombus = MxGraphFactoryService.getMxGraphProperty('mxRhombus'); +const mxUtils: typeof mxgraph.mxUtils = MxGraphFactoryService.getMxGraphProperty('mxUtils'); +const mxConstants: typeof mxgraph.mxConstants = MxGraphFactoryService.getMxGraphProperty('mxConstants'); + +abstract class GatewayShape extends mxRhombus { + 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.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 + } +} + +export class ExclusiveGatewayShape 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.addExclusiveGatewaySymbol(c, x, y, w, h); + } + + 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); + + 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.close(); + + c.fillAndStroke(); + } +} diff --git a/src/model/bpmn/shape/ShapeUtil.ts b/src/model/bpmn/shape/ShapeUtil.ts index f1f13abe21..b60192f279 100644 --- a/src/model/bpmn/shape/ShapeUtil.ts +++ b/src/model/bpmn/shape/ShapeUtil.ts @@ -18,9 +18,14 @@ import { ShapeBpmnElementKind } from './ShapeBpmnElementKind'; // TODO move to ShapeBpmnElementKind? and rename into ShapeBpmnElementKindUtil? // TODO bpmnEventKinds and flowNodeKinds currently hosted in ProcessConverter may be hosted here export default class ShapeUtil { - private static EVENTS_KIND = Object.values(ShapeBpmnElementKind).filter(kind => { - return kind.endsWith('Event'); - }); + private static readonly EVENTS_KIND = ShapeUtil.filterKind('Event'); + private static readonly GATEWAY_KINDS = ShapeUtil.filterKind('Gateway'); + + private static filterKind(suffix: string): ShapeBpmnElementKind[] { + return Object.values(ShapeBpmnElementKind).filter(kind => { + return kind.endsWith(suffix); + }); + } public static isEvent(kind: ShapeBpmnElementKind): boolean { return this.EVENTS_KIND.includes(kind); @@ -31,4 +36,7 @@ export default class ShapeUtil { public static topLevelBpmnEventKinds(): ShapeBpmnElementKind[] { return this.EVENTS_KIND; } + public static gatewayKinds(): ShapeBpmnElementKind[] { + return this.GATEWAY_KINDS; + } } diff --git a/src/service/MxGraphFactoryService.ts b/src/service/MxGraphFactoryService.ts index 0b3b76ad08..a6f524d3ac 100644 --- a/src/service/MxGraphFactoryService.ts +++ b/src/service/MxGraphFactoryService.ts @@ -20,6 +20,7 @@ type MxGraphProperty = | 'mxClient' | 'mxConstants' | 'mxEllipse' + | 'mxRhombus' | 'mxRectangleShape' | 'mxGeometry' | 'mxGraph'