UNPKG

bpmn-visualization

Version:

A TypeScript library for visualizing process execution data on BPMN diagrams

1,178 lines (1,129 loc) 273 kB
/* Copyright 2020-2023 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 factory from 'mxgraph'; import debounce from 'lodash.debounce'; import throttle from 'lodash.throttle'; import { XMLParser } from 'fast-xml-parser'; import { decodeXML } from 'entities'; /* 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. */ /** * @category Navigation */ var FitType; (function (FitType) { /** No fit, use dimensions and coordinates from the BPMN diagram. */ FitType["None"] = "None"; /** Fit the whole html container available to render the BPMN diagram. */ FitType["HorizontalVertical"] = "HorizontalVertical"; /** Fit only horizontally. */ FitType["Horizontal"] = "Horizontal"; /** Fit only vertically. */ FitType["Vertical"] = "Vertical"; /** Fit and center the BPMN Diagram. */ FitType["Center"] = "Center"; })(FitType || (FitType = {})); /** * @category Navigation * @since 0.24.0 */ var ZoomType; (function (ZoomType) { ZoomType["In"] = "in"; ZoomType["Out"] = "out"; })(ZoomType || (ZoomType = {})); /* Copyright 2021 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. */ /** * The real name of the field in the BPMN XSD. * @category BPMN */ var ShapeBpmnElementKind; (function (ShapeBpmnElementKind) { ShapeBpmnElementKind["LANE"] = "lane"; ShapeBpmnElementKind["POOL"] = "pool"; ShapeBpmnElementKind["CALL_ACTIVITY"] = "callActivity"; ShapeBpmnElementKind["SUB_PROCESS"] = "subProcess"; // When adding support, uncomment related content in tests // test/unit/component/mxgraph/renderer/StyleComputer.test.ts // test/unit/component/parser/json/BpmnJsonParser.marker.test.ts (adhoc requires special checks as an additional marker should be present) // Generalize test/unit/component/parser/json/BpmnJsonParser.sub.process.test.ts // See also, ShapeBpmnSubProcessKind // SUB_PROCESS_AD_HOC = 'adHocSubProcess', // SUB_PROCESS_TRANSACTION = 'transaction', ShapeBpmnElementKind["TASK"] = "task"; ShapeBpmnElementKind["TASK_USER"] = "userTask"; ShapeBpmnElementKind["TASK_SERVICE"] = "serviceTask"; ShapeBpmnElementKind["TASK_RECEIVE"] = "receiveTask"; ShapeBpmnElementKind["TASK_SEND"] = "sendTask"; ShapeBpmnElementKind["TASK_MANUAL"] = "manualTask"; ShapeBpmnElementKind["TASK_SCRIPT"] = "scriptTask"; ShapeBpmnElementKind["TASK_BUSINESS_RULE"] = "businessRuleTask"; ShapeBpmnElementKind["GLOBAL_TASK"] = "globalTask"; ShapeBpmnElementKind["GLOBAL_TASK_USER"] = "globalUserTask"; ShapeBpmnElementKind["GLOBAL_TASK_MANUAL"] = "globalManualTask"; ShapeBpmnElementKind["GLOBAL_TASK_SCRIPT"] = "globalScriptTask"; ShapeBpmnElementKind["GLOBAL_TASK_BUSINESS_RULE"] = "globalBusinessRuleTask"; ShapeBpmnElementKind["GROUP"] = "group"; ShapeBpmnElementKind["TEXT_ANNOTATION"] = "textAnnotation"; ShapeBpmnElementKind["GATEWAY_PARALLEL"] = "parallelGateway"; ShapeBpmnElementKind["GATEWAY_EXCLUSIVE"] = "exclusiveGateway"; ShapeBpmnElementKind["GATEWAY_INCLUSIVE"] = "inclusiveGateway"; ShapeBpmnElementKind["GATEWAY_EVENT_BASED"] = "eventBasedGateway"; ShapeBpmnElementKind["GATEWAY_COMPLEX"] = "complexGateway"; ShapeBpmnElementKind["EVENT_START"] = "startEvent"; ShapeBpmnElementKind["EVENT_END"] = "endEvent"; ShapeBpmnElementKind["EVENT_INTERMEDIATE_CATCH"] = "intermediateCatchEvent"; ShapeBpmnElementKind["EVENT_INTERMEDIATE_THROW"] = "intermediateThrowEvent"; ShapeBpmnElementKind["EVENT_BOUNDARY"] = "boundaryEvent"; })(ShapeBpmnElementKind || (ShapeBpmnElementKind = {})); /** * @category BPMN */ var ShapeBpmnCallActivityKind; (function (ShapeBpmnCallActivityKind) { ShapeBpmnCallActivityKind["CALLING_PROCESS"] = "process"; ShapeBpmnCallActivityKind["CALLING_GLOBAL_TASK"] = "global task"; })(ShapeBpmnCallActivityKind || (ShapeBpmnCallActivityKind = {})); /** * Values available for the `eventGatewayType` property in the BPMN specification. * @category BPMN */ var ShapeBpmnEventBasedGatewayKind; (function (ShapeBpmnEventBasedGatewayKind) { ShapeBpmnEventBasedGatewayKind["Exclusive"] = "Exclusive"; /** When no type is provided in the BPMN source. */ ShapeBpmnEventBasedGatewayKind["None"] = "None"; ShapeBpmnEventBasedGatewayKind["Parallel"] = "Parallel"; })(ShapeBpmnEventBasedGatewayKind || (ShapeBpmnEventBasedGatewayKind = {})); /** * Base name of the EventDefinition fields in the BPMN XSD for event kinds. In the xsd, the value is <enum_value>EventDefinition. * * For instance, TERMINATE --> terminateEventDefinition * @category BPMN */ var ShapeBpmnEventDefinitionKind; (function (ShapeBpmnEventDefinitionKind) { ShapeBpmnEventDefinitionKind["NONE"] = "none"; ShapeBpmnEventDefinitionKind["TERMINATE"] = "terminate"; ShapeBpmnEventDefinitionKind["CANCEL"] = "cancel"; ShapeBpmnEventDefinitionKind["COMPENSATION"] = "compensate"; ShapeBpmnEventDefinitionKind["CONDITIONAL"] = "conditional"; ShapeBpmnEventDefinitionKind["ERROR"] = "error"; ShapeBpmnEventDefinitionKind["ESCALATION"] = "escalation"; ShapeBpmnEventDefinitionKind["LINK"] = "link"; ShapeBpmnEventDefinitionKind["MESSAGE"] = "message"; ShapeBpmnEventDefinitionKind["SIGNAL"] = "signal"; ShapeBpmnEventDefinitionKind["TIMER"] = "timer"; })(ShapeBpmnEventDefinitionKind || (ShapeBpmnEventDefinitionKind = {})); /** * @category BPMN */ var ShapeBpmnMarkerKind; (function (ShapeBpmnMarkerKind) { ShapeBpmnMarkerKind["ADHOC"] = "adhoc"; ShapeBpmnMarkerKind["COMPENSATION"] = "compensation"; ShapeBpmnMarkerKind["EXPAND"] = "expand"; ShapeBpmnMarkerKind["LOOP"] = "loop"; ShapeBpmnMarkerKind["MULTI_INSTANCE_PARALLEL"] = "parallel multi instance"; ShapeBpmnMarkerKind["MULTI_INSTANCE_SEQUENTIAL"] = "sequential multi instance"; })(ShapeBpmnMarkerKind || (ShapeBpmnMarkerKind = {})); /** * Base name of the BPMN specification for sub-process kinds. * @category BPMN */ var ShapeBpmnSubProcessKind; (function (ShapeBpmnSubProcessKind) { ShapeBpmnSubProcessKind["EMBEDDED"] = "embedded"; ShapeBpmnSubProcessKind["EVENT"] = "event"; // The following may be only needed for rendering, as we have special types for adHoc and transaction subprocess in ShapeBpmnElementKind // TRANSACTION = 'transaction', // AD_HOC = 'ad_hoc', })(ShapeBpmnSubProcessKind || (ShapeBpmnSubProcessKind = {})); /* Copyright 2021 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. */ function convertEmptyStringAndObject(element, acceptEmptyString) { if (element === '') { return acceptEmptyString ? {} : undefined; } return element; } /** * @internal */ function ensureIsArray(elements, acceptEmptyString = false) { if (elements === undefined || elements === null) { return []; } return ((!Array.isArray(elements) ? [elements] : elements) // convert empty elements .map(element => convertEmptyStringAndObject(element, acceptEmptyString)) // remove empty elements .filter(Boolean)); } /** * @internal */ function filter(arrayToFilter, suffix, options) { let pattern = ''; if (options === null || options === void 0 ? void 0 : options.startingWith) { pattern = pattern.concat(`^(${options.startingWith}).*`); } else if (options === null || options === void 0 ? void 0 : options.notStartingWith) { pattern = pattern.concat(`^(?!(${options.notStartingWith})).*`); } pattern = pattern.concat(`${suffix}$`); return arrayToFilter.filter(element => ((options === null || options === void 0 ? void 0 : options.ignoreCase) ? new RegExp(pattern, 'i').test(element) : new RegExp(pattern).test(element))); } /* 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. */ /** * Utils to simplify the management of {@link ShapeBpmnElementKind}. * * This class is mainly used for internal purpose. You may use it to customize the BPMN theme as proposed in the examples but be aware it is subject to change. * * @category BPMN * @experimental */ class ShapeUtil { static isEvent(kind) { return isKindOf(EVENT_KINDS, kind); } static eventKinds() { return [...EVENT_KINDS]; } static isBoundaryEvent(kind) { return ShapeBpmnElementKind.EVENT_BOUNDARY === kind; } static isStartEvent(kind) { return ShapeBpmnElementKind.EVENT_START === kind; } static isCallActivity(kind) { return ShapeBpmnElementKind.CALL_ACTIVITY === kind; } static isSubProcess(kind) { return ShapeBpmnElementKind.SUB_PROCESS === kind; } static canHaveNoneEvent(kind) { return ShapeBpmnElementKind.EVENT_INTERMEDIATE_THROW === kind || ShapeBpmnElementKind.EVENT_END === kind || ShapeBpmnElementKind.EVENT_START === kind; } static isActivity(kind) { return isKindOf(ACTIVITY_KINDS, kind); } static activityKinds() { return [...ACTIVITY_KINDS]; } static isWithDefaultSequenceFlow(kind) { return FLOW_NODE_WITH_DEFAULT_SEQUENCE_FLOW_KINDS.includes(kind); } /** * Returns `true` if `kind` is related to a task, for instance {@link ShapeBpmnElementKind.TASK}, {@link ShapeBpmnElementKind.TASK_SERVICE}, but not a {@link ShapeBpmnElementKind.GLOBAL_TASK}. */ static isTask(kind) { return isKindOf(TASK_KINDS, kind); } /** * Returns all kinds related to a task, for instance {@link ShapeBpmnElementKind.TASK}, {@link ShapeBpmnElementKind.TASK_SEND}, but not a {@link ShapeBpmnElementKind.GLOBAL_TASK}. */ static taskKinds() { return [...TASK_KINDS]; } static gatewayKinds() { return [...GATEWAY_KINDS]; } static isGateway(kind) { return isKindOf(GATEWAY_KINDS, kind); } static flowNodeKinds() { return Object.values(ShapeBpmnElementKind).filter(kind => !ShapeUtil.isPoolOrLane(kind)); } static isPoolOrLane(kind) { return kind == ShapeBpmnElementKind.POOL || kind == ShapeBpmnElementKind.LANE; } } function filterKind(suffix, options) { return filter(Object.values(ShapeBpmnElementKind), suffix, options); } function isKindOf(referenceKinds, kind) { return Object.values(referenceKinds) .map(value => value) .includes(kind); } const EVENT_KINDS = filterKind('Event'); const GATEWAY_KINDS = filterKind('Gateway'); const TASK_KINDS = filterKind('Task', { ignoreCase: true, notStartingWith: 'global' }); const ACTIVITY_KINDS = [...TASK_KINDS, ShapeBpmnElementKind.CALL_ACTIVITY, ShapeBpmnElementKind.SUB_PROCESS]; const FLOW_NODE_WITH_DEFAULT_SEQUENCE_FLOW_KINDS = [ ...ACTIVITY_KINDS, ShapeBpmnElementKind.GATEWAY_EXCLUSIVE, ShapeBpmnElementKind.GATEWAY_INCLUSIVE, ShapeBpmnElementKind.GATEWAY_COMPLEX, ]; /** * Elements that are effectively used in BPMN diagram as base for eventDefinition i.e all {@link ShapeBpmnEventDefinitionKind} elements except {@link ShapeBpmnEventDefinitionKind.NONE} * @internal */ const eventDefinitionKinds = Object.values(ShapeBpmnEventDefinitionKind).filter(kind => kind != ShapeBpmnEventDefinitionKind.NONE); /* Copyright 2021 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. */ /** * Enum values are using the real name of the field in the BPMN XSD. * @category BPMN */ var AssociationDirectionKind; (function (AssociationDirectionKind) { AssociationDirectionKind["NONE"] = "None"; AssociationDirectionKind["ONE"] = "One"; AssociationDirectionKind["BOTH"] = "Both"; })(AssociationDirectionKind || (AssociationDirectionKind = {})); /** * Enum values are using the real name of the field in the BPMN XSD. * @category BPMN */ var FlowKind; (function (FlowKind) { FlowKind["SEQUENCE_FLOW"] = "sequenceFlow"; FlowKind["MESSAGE_FLOW"] = "messageFlow"; FlowKind["ASSOCIATION_FLOW"] = "association"; })(FlowKind || (FlowKind = {})); /** * Enum values are using the real name of the `visible message` field in the BPMN XSD, except for `none` that is not present in the specification. * @category BPMN */ var MessageVisibleKind; (function (MessageVisibleKind) { MessageVisibleKind["NONE"] = "none"; MessageVisibleKind["INITIATING"] = "initiating"; MessageVisibleKind["NON_INITIATING"] = "non_initiating"; })(MessageVisibleKind || (MessageVisibleKind = {})); /** * Enum values are used internally to identify sequence the flow markers and to manage their related style. * @category BPMN */ var SequenceFlowKind; (function (SequenceFlowKind) { SequenceFlowKind["NORMAL"] = "normal"; SequenceFlowKind["DEFAULT"] = "default"; SequenceFlowKind["CONDITIONAL_FROM_ACTIVITY"] = "conditional_from_activity"; SequenceFlowKind["CONDITIONAL_FROM_GATEWAY"] = "conditional_from_gateway"; })(SequenceFlowKind || (SequenceFlowKind = {})); /* Copyright 2021 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. */ /** * The `mxgraph` context that allows access to the mxGraph objects. * * **WARNING**: this is for advanced users. * * Here are some examples where calling the mxGraph API directly can be useful: * ```javascript * // Get the mxGraph version * const mxGraphVersion = mxgraph.mxClient.VERSION; * // Call mxUtils in custom BPMN Shapes * c.setFillColor(mxgraph.mxUtils.getValue(this.style, BpmnStyleIdentifier.EDGE_START_FILL_COLOR, this.stroke)); * ``` * * @since 0.30.0 */ const mxgraph = initialize(); function initialize() { // set options globally, as it is not working when passing options to the factory (https://github.com/jgraph/mxgraph/issues/479) // Required otherwise 'Uncaught ReferenceError: assignment to undeclared variable mx...' window.mxForceIncludes = false; window.mxLoadResources = false; // Required otherwise we got 'Uncaught ReferenceError: assignment to undeclared variable mx...' window.mxLoadStylesheets = false; window.mxResourceExtension = '.txt'; return factory({}); } /* Copyright 2021 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. */ /** * Define BPMN specific keys used in mxGraph styles. Use constants defined in this class instead of hard coded string values. * * **WARN**: You may use it to customize the BPMN Theme as suggested in the examples. But be aware that the way the default BPMN theme can be modified is subject to change. * * @category BPMN Theme * @experimental */ class BpmnStyleIdentifier { } // edge Object.defineProperty(BpmnStyleIdentifier, "EDGE", { enumerable: true, configurable: true, writable: true, value: 'bpmn.edge' }); Object.defineProperty(BpmnStyleIdentifier, "EDGE_START_FILL_COLOR", { enumerable: true, configurable: true, writable: true, value: 'bpmn.edge.startFillColor' }); Object.defineProperty(BpmnStyleIdentifier, "EDGE_END_FILL_COLOR", { enumerable: true, configurable: true, writable: true, value: 'bpmn.edge.endFillColor' }); // kind Object.defineProperty(BpmnStyleIdentifier, "EVENT_BASED_GATEWAY_KIND", { enumerable: true, configurable: true, writable: true, value: 'bpmn.gatewayKind' }); Object.defineProperty(BpmnStyleIdentifier, "EVENT_DEFINITION_KIND", { enumerable: true, configurable: true, writable: true, value: 'bpmn.eventDefinitionKind' }); Object.defineProperty(BpmnStyleIdentifier, "GLOBAL_TASK_KIND", { enumerable: true, configurable: true, writable: true, value: 'bpmn.globalTaskKind' }); Object.defineProperty(BpmnStyleIdentifier, "SUB_PROCESS_KIND", { enumerable: true, configurable: true, writable: true, value: 'bpmn.subProcessKind' }); // state Object.defineProperty(BpmnStyleIdentifier, "IS_INITIATING", { enumerable: true, configurable: true, writable: true, value: 'bpmn.isInitiating' }); Object.defineProperty(BpmnStyleIdentifier, "IS_INSTANTIATING", { enumerable: true, configurable: true, writable: true, value: 'bpmn.isInstantiating' }); Object.defineProperty(BpmnStyleIdentifier, "IS_INTERRUPTING", { enumerable: true, configurable: true, writable: true, value: 'bpmn.isInterrupting' }); // other identifiers Object.defineProperty(BpmnStyleIdentifier, "EXTRA_CSS_CLASSES", { enumerable: true, configurable: true, writable: true, value: 'bpmn.extra.css.classes' }); Object.defineProperty(BpmnStyleIdentifier, "MARKERS", { enumerable: true, configurable: true, writable: true, value: 'bpmn.markers' }); Object.defineProperty(BpmnStyleIdentifier, "MESSAGE_FLOW_ICON", { enumerable: true, configurable: true, writable: true, value: 'bpmn.messageFlowIcon' }); /** * **WARN**: You may use it to customize the BPMN Theme as suggested in the examples. But be aware that the way the default BPMN theme can be modified is subject to change. * * @category BPMN Theme * @experimental */ class MarkerIdentifier { } Object.defineProperty(MarkerIdentifier, "ARROW_DASH", { enumerable: true, configurable: true, writable: true, value: 'bpmn.dash' }); /* 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. */ /** * Store all rendering defaults used by `bpmn-visualization`. * * **WARN**: You may use it to customize the BPMN Theme as suggested in the examples. But be aware that the way the default BPMN theme can be modified is subject to change. * * @category BPMN Theme * @experimental */ var StyleDefault; (function (StyleDefault) { StyleDefault[StyleDefault["STROKE_WIDTH_THIN"] = 2] = "STROKE_WIDTH_THIN"; StyleDefault[StyleDefault["STROKE_WIDTH_THICK"] = 5] = "STROKE_WIDTH_THICK"; StyleDefault[StyleDefault["SHAPE_ACTIVITY_BOTTOM_MARGIN"] = 7] = "SHAPE_ACTIVITY_BOTTOM_MARGIN"; StyleDefault[StyleDefault["SHAPE_ACTIVITY_TOP_MARGIN"] = 7] = "SHAPE_ACTIVITY_TOP_MARGIN"; StyleDefault[StyleDefault["SHAPE_ACTIVITY_LEFT_MARGIN"] = 7] = "SHAPE_ACTIVITY_LEFT_MARGIN"; StyleDefault[StyleDefault["SHAPE_ACTIVITY_FROM_CENTER_MARGIN"] = 7] = "SHAPE_ACTIVITY_FROM_CENTER_MARGIN"; StyleDefault[StyleDefault["SHAPE_ACTIVITY_MARKER_ICON_MARGIN"] = 5] = "SHAPE_ACTIVITY_MARKER_ICON_MARGIN"; StyleDefault[StyleDefault["SHAPE_ACTIVITY_MARKER_ICON_SIZE"] = 20] = "SHAPE_ACTIVITY_MARKER_ICON_SIZE"; StyleDefault[StyleDefault["POOL_LABEL_SIZE"] = 30] = "POOL_LABEL_SIZE"; StyleDefault["POOL_LABEL_FILL_COLOR"] = "none"; StyleDefault[StyleDefault["LANE_LABEL_SIZE"] = 30] = "LANE_LABEL_SIZE"; StyleDefault["LANE_LABEL_FILL_COLOR"] = "none"; StyleDefault[StyleDefault["TEXT_ANNOTATION_BORDER_LENGTH"] = 10] = "TEXT_ANNOTATION_BORDER_LENGTH"; StyleDefault["TEXT_ANNOTATION_FILL_COLOR"] = "none"; StyleDefault["GROUP_FILL_COLOR"] = "none"; // General StyleDefault["DEFAULT_FILL_COLOR"] = "White"; StyleDefault["DEFAULT_STROKE_COLOR"] = "Black"; StyleDefault["DEFAULT_FONT_FAMILY"] = "Arial, Helvetica, sans-serif"; StyleDefault[StyleDefault["DEFAULT_FONT_SIZE"] = 11] = "DEFAULT_FONT_SIZE"; StyleDefault["DEFAULT_FONT_COLOR"] = "Black"; StyleDefault[StyleDefault["DEFAULT_MARGIN"] = 0] = "DEFAULT_MARGIN"; // Shape defaults StyleDefault[StyleDefault["SHAPE_ARC_SIZE"] = 20] = "SHAPE_ARC_SIZE"; // Overlay defaults StyleDefault["DEFAULT_OVERLAY_FILL_COLOR"] = "White"; StyleDefault[StyleDefault["DEFAULT_OVERLAY_FILL_OPACITY"] = 100] = "DEFAULT_OVERLAY_FILL_OPACITY"; StyleDefault["DEFAULT_OVERLAY_STROKE_COLOR"] = "Black"; StyleDefault[StyleDefault["DEFAULT_OVERLAY_STROKE_WIDTH"] = 1] = "DEFAULT_OVERLAY_STROKE_WIDTH"; StyleDefault[StyleDefault["DEFAULT_OVERLAY_FONT_SIZE"] = 11] = "DEFAULT_OVERLAY_FONT_SIZE"; StyleDefault["DEFAULT_OVERLAY_FONT_COLOR"] = "Black"; // Edge StyleDefault["SEQUENCE_FLOW_CONDITIONAL_FROM_ACTIVITY_MARKER_FILL_COLOR"] = "White"; StyleDefault["MESSAGE_FLOW_MARKER_START_FILL_COLOR"] = "White"; StyleDefault["MESSAGE_FLOW_MARKER_END_FILL_COLOR"] = "White"; })(StyleDefault || (StyleDefault = {})); /** * Get the BPMN 'instantiate' information from the style. * @param style the mxGraph style * @internal * @private */ const getBpmnIsInstantiating = (style) => mxgraph.mxUtils.getValue(style, BpmnStyleIdentifier.IS_INSTANTIATING, 'false') == 'true'; /* 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. */ const arrowDefaultSize = 12; /** * Configure the styles used for BPMN rendering. * * **WARN**: You may use it to customize the BPMN Theme as suggested in the examples. But be aware that the way the default BPMN theme can be modified is subject to change. * * @category BPMN Theme * @experimental */ class StyleConfigurator { constructor(graph) { Object.defineProperty(this, "graph", { enumerable: true, configurable: true, writable: true, value: graph }); Object.defineProperty(this, "specificFlowStyles", { enumerable: true, configurable: true, writable: true, value: new MapWithDefault([ [ FlowKind.SEQUENCE_FLOW, (style) => { style[mxgraph.mxConstants.STYLE_ENDARROW] = mxgraph.mxConstants.ARROW_BLOCK_THIN; }, ], [ FlowKind.MESSAGE_FLOW, (style) => { style[mxgraph.mxConstants.STYLE_DASHED] = true; style[mxgraph.mxConstants.STYLE_DASH_PATTERN] = '8 5'; style[mxgraph.mxConstants.STYLE_STARTARROW] = mxgraph.mxConstants.ARROW_OVAL; style[mxgraph.mxConstants.STYLE_STARTSIZE] = 8; style[mxgraph.mxConstants.STYLE_STARTFILL] = true; style[BpmnStyleIdentifier.EDGE_START_FILL_COLOR] = StyleDefault.MESSAGE_FLOW_MARKER_START_FILL_COLOR; style[mxgraph.mxConstants.STYLE_ENDARROW] = mxgraph.mxConstants.ARROW_BLOCK_THIN; style[mxgraph.mxConstants.STYLE_ENDFILL] = true; style[BpmnStyleIdentifier.EDGE_END_FILL_COLOR] = StyleDefault.MESSAGE_FLOW_MARKER_END_FILL_COLOR; }, ], [ FlowKind.ASSOCIATION_FLOW, (style) => { style[mxgraph.mxConstants.STYLE_DASHED] = true; style[mxgraph.mxConstants.STYLE_DASH_PATTERN] = '1 2'; // STYLE_ENDARROW and STYLE_STARTARROW are defined in specific AssociationDirectionKind styles when needed style[mxgraph.mxConstants.STYLE_STARTSIZE] = arrowDefaultSize; }, ], ]) }); Object.defineProperty(this, "specificSequenceFlowStyles", { enumerable: true, configurable: true, writable: true, value: new MapWithDefault([ [ SequenceFlowKind.DEFAULT, (style) => { style[mxgraph.mxConstants.STYLE_STARTARROW] = MarkerIdentifier.ARROW_DASH; }, ], [ SequenceFlowKind.CONDITIONAL_FROM_ACTIVITY, (style) => { style[mxgraph.mxConstants.STYLE_STARTARROW] = mxgraph.mxConstants.ARROW_DIAMOND_THIN; style[mxgraph.mxConstants.STYLE_STARTSIZE] = 18; style[mxgraph.mxConstants.STYLE_STARTFILL] = true; style[BpmnStyleIdentifier.EDGE_START_FILL_COLOR] = StyleDefault.SEQUENCE_FLOW_CONDITIONAL_FROM_ACTIVITY_MARKER_FILL_COLOR; }, ], ]) }); Object.defineProperty(this, "specificAssociationFlowStyles", { enumerable: true, configurable: true, writable: true, value: new MapWithDefault([ [ AssociationDirectionKind.NONE, // eslint-disable-next-line @typescript-eslint/no-unused-vars -- prefix parameter name - common practice to acknowledge the fact that some parameter is unused (e.g. in TypeScript compiler) (_style) => { // the style is fully managed by the FlowKind.ASSOCIATION_FLOW style }, ], [ AssociationDirectionKind.ONE, (style) => { style[mxgraph.mxConstants.STYLE_ENDARROW] = mxgraph.mxConstants.ARROW_OPEN_THIN; }, ], [ AssociationDirectionKind.BOTH, (style) => { style[mxgraph.mxConstants.STYLE_STARTARROW] = mxgraph.mxConstants.ARROW_OPEN_THIN; style[mxgraph.mxConstants.STYLE_ENDARROW] = mxgraph.mxConstants.ARROW_OPEN_THIN; }, ], ]) }); } configureStyles() { this.configureDefaultVertexStyle(); this.configurePoolStyle(); this.configureLaneStyle(); this.configureTextAnnotationStyle(); this.configureGroupStyle(); this.configureActivityStyles(); this.configureEventStyles(); this.configureGatewayStyles(); this.configureDefaultEdgeStyle(); this.configureFlowStyles(); } getStylesheet() { return this.graph.getStylesheet(); } putCellStyle(name, style) { this.getStylesheet().putCellStyle(name, style); } configureDefaultVertexStyle() { const style = this.getStylesheet().getDefaultVertexStyle(); configureCommonDefaultStyle(style); style[mxgraph.mxConstants.STYLE_ABSOLUTE_ARCSIZE] = true; style[mxgraph.mxConstants.STYLE_ARCSIZE] = StyleDefault.SHAPE_ARC_SIZE; } configurePoolStyle() { const style = {}; style[mxgraph.mxConstants.STYLE_SHAPE] = mxgraph.mxConstants.SHAPE_SWIMLANE; // label style style[mxgraph.mxConstants.STYLE_VERTICAL_ALIGN] = mxgraph.mxConstants.ALIGN_MIDDLE; style[mxgraph.mxConstants.STYLE_ALIGN] = mxgraph.mxConstants.ALIGN_CENTER; style[mxgraph.mxConstants.STYLE_STARTSIZE] = StyleDefault.POOL_LABEL_SIZE; style[mxgraph.mxConstants.STYLE_FILLCOLOR] = StyleDefault.POOL_LABEL_FILL_COLOR; this.graph.getStylesheet().putCellStyle(ShapeBpmnElementKind.POOL, style); } configureLaneStyle() { const style = {}; style[mxgraph.mxConstants.STYLE_SHAPE] = mxgraph.mxConstants.SHAPE_SWIMLANE; // label style style[mxgraph.mxConstants.STYLE_VERTICAL_ALIGN] = mxgraph.mxConstants.ALIGN_MIDDLE; style[mxgraph.mxConstants.STYLE_ALIGN] = mxgraph.mxConstants.ALIGN_CENTER; style[mxgraph.mxConstants.STYLE_SWIMLANE_LINE] = 0; // hide the line between the title region and the content area style[mxgraph.mxConstants.STYLE_STARTSIZE] = StyleDefault.LANE_LABEL_SIZE; style[mxgraph.mxConstants.STYLE_FILLCOLOR] = StyleDefault.LANE_LABEL_FILL_COLOR; this.graph.getStylesheet().putCellStyle(ShapeBpmnElementKind.LANE, style); } configureEventStyles() { ShapeUtil.eventKinds().forEach(kind => { const style = {}; style[mxgraph.mxConstants.STYLE_SHAPE] = kind; style[mxgraph.mxConstants.STYLE_PERIMETER] = mxgraph.mxPerimeter.EllipsePerimeter; style[mxgraph.mxConstants.STYLE_STROKEWIDTH] = kind == ShapeBpmnElementKind.EVENT_END ? StyleDefault.STROKE_WIDTH_THICK : StyleDefault.STROKE_WIDTH_THIN; style[mxgraph.mxConstants.STYLE_VERTICAL_LABEL_POSITION] = mxgraph.mxConstants.ALIGN_BOTTOM; this.putCellStyle(kind, style); }); } configureTextAnnotationStyle() { const style = {}; style[mxgraph.mxConstants.STYLE_SHAPE] = ShapeBpmnElementKind.TEXT_ANNOTATION; style[mxgraph.mxConstants.STYLE_VERTICAL_ALIGN] = mxgraph.mxConstants.ALIGN_MIDDLE; style[mxgraph.mxConstants.STYLE_ALIGN] = mxgraph.mxConstants.ALIGN_LEFT; style[mxgraph.mxConstants.STYLE_SPACING_LEFT] = 5; style[mxgraph.mxConstants.STYLE_FILLCOLOR] = StyleDefault.TEXT_ANNOTATION_FILL_COLOR; style[mxgraph.mxConstants.STYLE_STROKEWIDTH] = StyleDefault.STROKE_WIDTH_THIN; this.putCellStyle(ShapeBpmnElementKind.TEXT_ANNOTATION, style); } configureGroupStyle() { const style = {}; style[mxgraph.mxConstants.STYLE_ROUNDED] = true; style[mxgraph.mxConstants.STYLE_DASHED] = true; style[mxgraph.mxConstants.STYLE_DASH_PATTERN] = '7 4 1 4'; style[mxgraph.mxConstants.STYLE_STROKEWIDTH] = StyleDefault.STROKE_WIDTH_THIN; style[mxgraph.mxConstants.STYLE_FILLCOLOR] = StyleDefault.GROUP_FILL_COLOR; // Default label positioning style[mxgraph.mxConstants.STYLE_ALIGN] = mxgraph.mxConstants.ALIGN_CENTER; style[mxgraph.mxConstants.STYLE_VERTICAL_ALIGN] = mxgraph.mxConstants.ALIGN_TOP; this.putCellStyle(ShapeBpmnElementKind.GROUP, style); } configureActivityStyles() { ShapeUtil.activityKinds().forEach(kind => { const style = {}; style[mxgraph.mxConstants.STYLE_SHAPE] = kind; style[mxgraph.mxConstants.STYLE_ROUNDED] = true; // required by the BPMN specification style[mxgraph.mxConstants.STYLE_VERTICAL_ALIGN] = mxgraph.mxConstants.ALIGN_MIDDLE; style[mxgraph.mxConstants.STYLE_STROKEWIDTH] = kind == ShapeBpmnElementKind.CALL_ACTIVITY ? StyleDefault.STROKE_WIDTH_THICK : StyleDefault.STROKE_WIDTH_THIN; this.putCellStyle(kind, style); }); } configureGatewayStyles() { ShapeUtil.gatewayKinds().forEach(kind => { const style = {}; style[mxgraph.mxConstants.STYLE_SHAPE] = kind; style[mxgraph.mxConstants.STYLE_PERIMETER] = mxgraph.mxPerimeter.RhombusPerimeter; style[mxgraph.mxConstants.STYLE_STROKEWIDTH] = StyleDefault.STROKE_WIDTH_THIN; style[mxgraph.mxConstants.STYLE_VERTICAL_ALIGN] = mxgraph.mxConstants.ALIGN_TOP; // Default label positioning style[mxgraph.mxConstants.STYLE_LABEL_POSITION] = mxgraph.mxConstants.ALIGN_LEFT; style[mxgraph.mxConstants.STYLE_VERTICAL_LABEL_POSITION] = mxgraph.mxConstants.ALIGN_TOP; this.putCellStyle(kind, style); }); } configureDefaultEdgeStyle() { const style = this.getStylesheet().getDefaultEdgeStyle(); configureCommonDefaultStyle(style); style[mxgraph.mxConstants.STYLE_SHAPE] = BpmnStyleIdentifier.EDGE; style[mxgraph.mxConstants.STYLE_ENDSIZE] = arrowDefaultSize; style[mxgraph.mxConstants.STYLE_STROKEWIDTH] = 1.5; style[mxgraph.mxConstants.STYLE_ROUNDED] = true; style[mxgraph.mxConstants.STYLE_ARCSIZE] = 5; style[mxgraph.mxConstants.STYLE_VERTICAL_ALIGN] = mxgraph.mxConstants.ALIGN_BOTTOM; // The end arrow must be redefined in specific style delete style[mxgraph.mxConstants.STYLE_ENDARROW]; } configureEdgeStyles(styleKinds, specificStyles) { styleKinds.forEach(kind => { const style = {}; specificStyles.get(kind)(style); this.graph.getStylesheet().putCellStyle(kind.toString(), style); }); } configureFlowStyles() { this.configureEdgeStyles(Object.values(FlowKind), this.specificFlowStyles); this.configureEdgeStyles(Object.values(SequenceFlowKind), this.specificSequenceFlowStyles); this.configureEdgeStyles(Object.values(AssociationDirectionKind), this.specificAssociationFlowStyles); } } function configureCommonDefaultStyle(style) { style[mxgraph.mxConstants.STYLE_FONTFAMILY] = StyleDefault.DEFAULT_FONT_FAMILY; style[mxgraph.mxConstants.STYLE_FONTSIZE] = StyleDefault.DEFAULT_FONT_SIZE; style[mxgraph.mxConstants.STYLE_FONTCOLOR] = StyleDefault.DEFAULT_FONT_COLOR; style[mxgraph.mxConstants.STYLE_FILLCOLOR] = StyleDefault.DEFAULT_FILL_COLOR; style[mxgraph.mxConstants.STYLE_STROKECOLOR] = StyleDefault.DEFAULT_STROKE_COLOR; style[mxgraph.mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = mxgraph.mxConstants.NONE; // only works with html labels (enabled by GraphConfigurator) style[mxgraph.mxConstants.STYLE_WHITE_SPACE] = 'wrap'; } class MapWithDefault extends Map { get(key) { var _a; return ((_a = super.get(key)) !== null && _a !== void 0 ? _a : (() => { // do nothing intentionally, there is no extra style to configure })); } } /* 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. */ /** * Compute the icon size proportionally to a ratio of the shape size. The proportions of the icon are left untouched. * @internal */ function computeScaledIconSize(initialIconSize, iconStyleConfiguration, shapeConfiguration, ratioFromShape) { let iconWidthProportionalToShape; let iconHeightProportionalToShape; if (initialIconSize.height < initialIconSize.width || (initialIconSize.height == initialIconSize.width && shapeConfiguration.width <= shapeConfiguration.height)) { iconWidthProportionalToShape = shapeConfiguration.width; iconHeightProportionalToShape = (shapeConfiguration.width * initialIconSize.height) / initialIconSize.width; } else { iconWidthProportionalToShape = (shapeConfiguration.height * initialIconSize.width) / initialIconSize.height; iconHeightProportionalToShape = shapeConfiguration.height; } const inset = iconStyleConfiguration.strokeWidth ? (iconStyleConfiguration.strokeWidth - 1) * 2 : 0; const paintIconWidth = iconWidthProportionalToShape * ratioFromShape - inset; const paintIconHeight = iconHeightProportionalToShape * ratioFromShape - inset; return { width: paintIconWidth, height: paintIconHeight }; } /** * Wrapper of `mxAbstractCanvas2D` to simplify method calls when painting icons/markers of BPMN shapes. * * It can scale dimensions passed to the method of the original `mxAbstractCanvas2D`. * * **WARN**: You may use it to customize the BPMN Theme as suggested in the examples. But be aware that the way the default BPMN theme can be modified is subject to change. * * @example * The vanilla canvas calls when a scale factor must be applied to position * ```javascript * const scaleX = 0.26; * const scaleY = 0.35; * c.moveTo(8 * scaleX, 39 * scaleY); * c.lineTo(12 * scaleX, 25 * scaleY); * ``` * * @example * With `BpmnCanvas` * ```javascript * const canvas = new BpmnCanvas(c, 0.26, 0.35); * canvas.moveTo(8, 39); * canvas.lineTo(12, 25); * ``` * * @category BPMN Theme * @experimental */ class BpmnCanvas { constructor({ canvas, shapeConfig, iconConfig }) { Object.defineProperty(this, "canvas", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "iconOriginalSize", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "scaleX", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "scaleY", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "iconPaintingOriginX", { enumerable: true, configurable: true, writable: true, value: 0 }); Object.defineProperty(this, "iconPaintingOriginY", { enumerable: true, configurable: true, writable: true, value: 0 }); Object.defineProperty(this, "shapeConfiguration", { enumerable: true, configurable: true, writable: true, value: void 0 }); this.canvas = canvas; this.shapeConfiguration = shapeConfig; this.iconOriginalSize = iconConfig.originalSize; const ratioFromShape = iconConfig.ratioFromParent; if (ratioFromShape) { const scaledIconSize = computeScaledIconSize(this.iconOriginalSize, iconConfig.styleConfig, this.shapeConfiguration, ratioFromShape); this.scaleX = scaledIconSize.width / this.iconOriginalSize.width; this.scaleY = scaledIconSize.height / this.iconOriginalSize.height; } else { this.scaleX = 1; this.scaleY = 1; } this.updateCanvasStyle(iconConfig.styleConfig); iconConfig.setIconOriginFunct(this); } /** * Set the icon origin to the top left corner of the shape. * * @param shapeDimensionProportion proportion of the width/height used to translate the icon origin from the shape origin. * @internal */ setIconOriginToShapeTopLeftProportionally(shapeDimensionProportion) { const shape = this.shapeConfiguration; this.iconPaintingOriginX = shape.x + shape.width / shapeDimensionProportion; this.iconPaintingOriginY = shape.y + shape.height / shapeDimensionProportion; } /** * Set the icon origin to the top left corner of the shape. */ setIconOriginToShapeTopLeft(topMargin = StyleDefault.SHAPE_ACTIVITY_TOP_MARGIN, leftMargin = StyleDefault.SHAPE_ACTIVITY_LEFT_MARGIN) { const shape = this.shapeConfiguration; this.iconPaintingOriginX = shape.x + leftMargin; this.iconPaintingOriginY = shape.y + topMargin; } /** * Set the icon origin to ensure that the icon is centered on the shape. */ setIconOriginForIconCentered() { const shape = this.shapeConfiguration; this.iconPaintingOriginX = shape.x + (shape.width - this.iconOriginalSize.width * this.scaleX) / 2; this.iconPaintingOriginY = shape.y + (shape.height - this.iconOriginalSize.height * this.scaleY) / 2; } /** * Set the icon origin to ensure that, on the shape, the icon is horizontally centered and vertically aligned to the bottom. */ setIconOriginForIconBottomCentered(bottomMargin = StyleDefault.SHAPE_ACTIVITY_BOTTOM_MARGIN) { const shape = this.shapeConfiguration; this.iconPaintingOriginX = shape.x + (shape.width - this.iconOriginalSize.width * this.scaleX) / 2; this.iconPaintingOriginY = shape.y + (shape.height - this.iconOriginalSize.height * this.scaleY - bottomMargin); } /** * Set the icon origin to ensure that, on the shape, the icon is vertically aligned to the bottom and translate to the left from the horizontal center. */ setIconOriginForIconOnBottomLeft(bottomMargin = StyleDefault.SHAPE_ACTIVITY_BOTTOM_MARGIN, fromCenterMargin = StyleDefault.SHAPE_ACTIVITY_FROM_CENTER_MARGIN) { const shape = this.shapeConfiguration; this.iconPaintingOriginX = shape.x + (shape.width - this.iconOriginalSize.width * this.scaleX) / 3 - fromCenterMargin; this.iconPaintingOriginY = shape.y + (shape.height - this.iconOriginalSize.height * this.scaleY - bottomMargin); } /** * Translate the icon origin using the scale factor associated to the horizontal and vertical directions. * * The values should be given with using the icon original size (as translated values will be scaled as other values passed to method of this class). * * @param dx the horizontal translation * @param dy the vertical translation */ translateIconOrigin(dx, dy) { this.iconPaintingOriginX += this.scaleX * dx; this.iconPaintingOriginY += this.scaleY * dy; } computeScaleFromOriginX(x) { return this.iconPaintingOriginX + x * this.scaleX; } computeScaleFromOriginY(y) { return this.iconPaintingOriginY + y * this.scaleY; } updateCanvasStyle({ isFilled, strokeColor, fillColor, strokeWidth }) { if (isFilled) { this.canvas.setFillColor(strokeColor); } else { this.canvas.setFillColor(fillColor); } this.canvas.setStrokeWidth(strokeWidth); } arcTo(rx, ry, angle, largeArcFlag, sweepFlag, x, y) { this.canvas.arcTo(rx * this.scaleX, ry * this.scaleY, angle, largeArcFlag, sweepFlag, this.computeScaleFromOriginX(x), this.computeScaleFromOriginY(y)); } begin() { this.canvas.begin(); } close() { this.canvas.close(); } curveTo(x1, y1, x2, y2, x3, y3) { this.canvas.curveTo(this.computeScaleFromOriginX(x1), this.computeScaleFromOriginY(y1), this.computeScaleFromOriginX(x2), this.computeScaleFromOriginY(y2), this.computeScaleFromOriginX(x3), this.computeScaleFromOriginY(y3)); } fill() { this.canvas.fill(); } fillAndStroke() { this.canvas.fillAndStroke(); } setFillColor(fillColor) { this.canvas.setFillColor(fillColor); } stroke() { this.canvas.stroke(); } setStrokeColor(color) { this.canvas.setStrokeColor(color); } setRoundLineJoin() { this.canvas.setLineJoin('round'); } lineTo(x, y) { this.canvas.lineTo(this.computeScaleFromOriginX(x), this.computeScaleFromOriginY(y)); } moveTo(x, y) { this.canvas.moveTo(this.computeScaleFromOriginX(x), this.computeScaleFromOriginY(y)); } rect(x, y, w, h) { this.canvas.rect(this.computeScaleFromOriginX(x), this.computeScaleFromOriginY(y), w * this.scaleX, h * this.scaleY); } roundrect(x, y, w, h, dx, dy) { this.canvas.roundrect(this.computeScaleFromOriginX(x), this.computeScaleFromOriginY(y), w * this.scaleX, h * this.scaleY, dx, dy); } ellipse(x, y, w, h) { this.canvas.ellipse(this.computeScaleFromOriginX(x), this.computeScaleFromOriginY(y), w * this.scaleX, h * this.scaleY); } rotateOnIconCenter(theta) { const rotationCenterX = this.iconPaintingOriginX + (this.iconOriginalSize.width / 2) * this.scaleX; const rotationCenterY = this.iconPaintingOriginY + (this.iconOriginalSize.height / 2) * this.scaleY; this.canvas.rotate(theta, false, false, rotationCenterX, rotationCenterY); } } /* 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. */ /** * @internal */ function buildPaintParameter({ canvas, x, y, width, height, shape, ratioFromParent, isFilled, iconStrokeWidth, }) { const shapeStrokeWidth = shape.strokewidth || mxgraph.mxUtils.getValue(shape.style, mxgraph.mxConstants.STYLE_STROKEWIDTH, StyleDefault.STROKE_WIDTH_THIN); const fillColor = shape.fill || mxgraph.mxUtils.getValue(shape.style, mxgraph.mxConstants.STYLE_FILLCOLOR, StyleDefault.DEFAULT_FILL_COLOR); const strokeColor = shape.stroke || mxgraph.mxUtils.getValue(shape.style, mxgraph.mxConstants.STYLE_STROKECOLOR, StyleDefault.DEFAULT_STROKE_COLOR); const margin = mxgraph.mxUtils.getValue(shape.style, mxgraph.mxConstants.STYLE_MARGIN, StyleDefault.DEFAULT_MARGIN); ratioFromParent !== null && ratioFromParent !== void 0 ? ratioFromParent : (ratioFromParent = 0.25); isFilled !== null && isFilled !== void 0 ? isFilled : (isFilled = false); iconStrokeWidth !== null && iconStrokeWidth !== void 0 ? iconStrokeWidth : (iconStrokeWidth = 0); return { canvas, ratioFromParent, setIconOriginFunct: (internalCanvas) => internalCanvas.setIconOriginForIconCentered(), shapeConfig: { x, y, width, height, strokeWidth: shapeStrokeWidth }, iconStyleConfig: { isFilled, fillColor, strokeColor, strokeWidth: iconStrokeWidth, margin }, }; } /** * Default implementation for the icons. * * **WARN**: You may use it to customize the BPMN Theme as suggested in the examples. But be aware that the way the default BPMN theme can be modified is subject to change. * * @category BPMN Theme * @experimental */ class IconPainter { paintEmptyIcon() {