1、功能介绍

bpmn-js是一个渲染工具包和一个(流程节点)建模器的结合。在使用的时候,既可以是查看模式,也可以是建模(编辑)模式。

1.1、以代码包形式使用查看器

通过在浏览器引入bpmn-viewer,然后使用BpmnJS创建查看器对象,读取bpmnXml配置文件即可。

let viewer = new BpmnJS({container: '#canvas'});
viewer.importXML(bpmnXml, function(err) {
    if (err) {
        
    } else {
        let canvas = viewer.get('canvas');
        canvas.zoom('fit-viewport');  // 适应当前可以区域大小
    }
});

1.2、使用建模器

1.2.1、创建建模器对象

创建自定义建模器,必须使用npm方式将bpmn-js引入项目中。

import Modeler from 'bpmn-js/lib/Modeler';

// 创建建模器对象
let modeler = mew Modeler({container: '#canvans'});

// 读取流程配置
modeler.importXML(bpmnXml, function(err) {
	// 执行后续处理
});
1.2.2、添加默认样式

引入建模器默认样式到页面中。

<link rel="stylesheet" href="bpmn-js/dist/assets/diagram-js.css" />
<link rel="stylesheet" href="bpmn-js/dist/assets/bpmn-font/css/bpmn.css" />

@import 'bpmn-js/dist/assets/diagram-js.css';
@import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css';
1.2.3、注册生命周期事件监听
// 给建模器注册元素变更事件
modeler.on('element.changed', function(e) {
    let ele = e.element;
});

// 给查看器注册元素交互事件
let eventBus = viewer.get('eventBus');
evnetBus.on('element.hover', function(e) {
    console.log(e.element.id);
});

// 元素事件有:element.hover、click、dbclick、mousedown、mounseup

甚至可以直接注册原生的DOM事件监听,因为每一个元素都被默认添加了一个key为data-element-id的自定义特征。

1.2.4、建模器扩展

可以使用附加模块在创建的时候拓展查看器和建模器,通过自定义模块修改或替换原有功能。

// 引入原始模块
import OriginModule from 'diagram-js-origin';

// 引入自定义拓展
import CustomRules from './custom-rules';
import CustomContextPad from './custom-context-pad';

// 拓展建模器
let modeler = new Modeler({
    container: '#canvas',
    additionalModules: [
        OriginModules,
        CustomRules,
        CustomContextPad
    ]
});

查看3.3拓展示例

2、内部原理介绍

bpmn-js构建在两个插件库之上:

  • bpmn-moddle:用于读写bpmnXml文档,等于元数据模型定义器。如果要拓展bpmnXml中支持的标签,看来就要拓展这货了。
  • diagram-js:用于绘制图表的形状,连线,触发图表事件等。

bpms-js在其之上,建立文档和图表渲染之间的对应关系。

2.1、diagram 图表交互与模型

diagram-js是一个用于在页面上绘制和修改图表的工具集,用于渲染虚拟元素并在其上构建用户体验。它提供了一个用于构建图表模块的简单模型和核心实现服务,同时建立了一套针对图形元素及其关系的数据模型。

2.1.1、模块系统模型

diagram使用依赖注入方式发现和装配虚拟图表组件,底层依赖didi插件。


ps: 依赖注入

didi插件是一个专门的js版依赖注入控制容器。

依赖注入di又叫控制反转ioc,的典型实现是spring,就是通过配置来向引擎注册需要的或者自定义的组件。

依赖注入使组件和组件依赖的实例化与组件行为脱钩,可以起到如下作用:

  • 显式展示依赖项 – 所有依赖项都作为构造函数传递。
  • 代码重用 – 实现了组件间解耦。
  • 更易测试。

didi通过声明各个组件的依赖关系,由框架对其进行管理,并且传递性的对依赖对象进行实例化。

import { Injector } from 'didi';

// 声明构造函数Car,Car的实例依赖Engine对象的实例
function Car(engine) {
    this.start = function() {
        engine.start();
    }
}

// 工厂模式构造函数,返回一个Engine对象
function createPetrolEngine(power) {
    return {
        start: function() {
            console.log('start with' + power + 'hp');
        }
    }
}

// 声明Car模块
const carMoudle = {
    // 声明car变量的构造函数
    'car': ['type', Car],
    // 声明engine变量的构造方式
    'engine': ['factory', createPetrolEngine],
    // 声明基本类型变量的值
    'power': ['value', 1184]
};

const injector = new Injector([
    carMoudle
]);
// 实例化(注入)模块
injector.invoke(function(car) {
    car.start();
});

diagram中的modules(模块)指的是能够提供特定服务的一个函数或者实例单元。使用didi在diagram中定义一个module的方式如下示例:

// filename path-to-my-logging-module

import CoreModule from 'diagram-js/lib/core';

// 定义模块服务,该服务为查看器的元素变动事件添加日志纪录功能
function MyLoggingPlugin(eventBus) {
    eventBus.on('element.changed', function(event) {
        console.log('element', event.element, 'change');
    });
}

// 声明该服务需要注入的变量
MyLoggingPlugin.$inject = [ 'eventBus' ];

// 声明并对外暴露模块
export default {
    __depends__: [ CoreModule ], // 声明该模块依赖
    __init__: ['MyLoggingPlugin'], //声明该模块需要在系统初始化的时候被调用
    myLoggingPlugin: [ 'type', MyLoggingPlugin ] //声明该模块的构造函数
}

// file MyDiagram
import MyLoggingPlugin from './path-to-my-logging-module';

let diagram = new Diagram({
    modules: [
        MyLoggingPlugin
    ]
});

export default diagram;

// 使用1.2.4的additionalModules可以将MyDiagram引入建模器
2.1.2、核心服务对象
  • Canvas:提供图形元素新增和移除接口,管理图形元素声明周期,提供图形拖动和页面适应处理等接口。
  • EventBus:事件总线,集成化的提供事件注册和分发功能。
  • ElementFactory:元素工厂,根据diagram内部数据模型创建图形和连接线。
  • GraphicalFactory:图形工厂,创建图形和连接线,实际效果由渲染器(DefaultRenderer)实现。
2.1.3、内部数据模型

diagram为图形和连接线创建了一个简单的数据模型。

  • 一个图形具有一个父节点,一个子节点列表,和一个包含流入和流出连接线的列表。
  • 一个连接线具有一个父链接,还有指向的源图形和目标图形。

系统使用ElementRegistory对象根据数据模型进行图形和连接线的生成。

2.1.4、辅助工具
  • CommonStock:命令栈,用于重做和回退操作。
  • ContextPad:上下文面板,提供围绕元素上下文操作。
  • Overlays:层级工具,提供将其他信息附加到图形元素上的接口。
  • Modeling:模型工具,提供用于更新画布元素(如移动,删除)的接口。

2.2、bpmn-moddle

bpmn-moddle(以下称为BM)用于封装bpmn2.0元数据模型,并提供了读写bpmnXml的方法,它将xml文件解析为对象树,该树在建模期间编辑和验证,并在保存建模的时候导出为xml。

BM建立在两个核心库之上:

  • moddle:对象树定义和处理
  • moddle-xml :基于moddle库读写xml文档。

在核心库之上BM提供了简单的操作接口,比如:

  • fromXML
  • toXML

2.3、整合diagram与BM

bpmn-js使用BM将xml文件解析为对象树,然后建立对象树中的示例(bpmn元素)与diagram中的图形和连接线之间的联系(混合对象),从而在diagram的Canvas上渲染出图表节点来。一个图形元素对象如下示例:

{
    id: 'StartEvent_1',
    x: 100,
    y: 100,
    width: 50,
    height: 50,
    businessObject: {
        $attrs: Object,
        $type: 'bpmn:StartEvent',
        id: 'StartEvent_1',
        $parent: {
           $attrs: Object,
           $parent: ModdleElement,
           $type: 'bpmn:Process',
           flowElements: Array[1],
           id: 'Process_1',
           isExecutable: false
        }
    }
}

可以使用businessObject属性从每个图形元素访问到bpmn对象。

3、示例分析

3.1、为图形元素添加颜色

3.1.1、方案1 – 使用层叠蒙版
viewer.import(diagramXml, function() {
    // 1、使用viewer获得层叠对象和元素注册器
    let overlays = viewer.get('overlays');
    let elementRegistry = viewer.get('elementRegistry');
    
    // 2、获得要添加颜色的图形元素,目的是获得该元素的尺寸数据
    let shape = elementRegistry.get('UserTask_1');
    // 3、使用jquery创建一个DOM,尺寸与图形元素相同
    let $overlayhtml = $('<div class="height-overlay">').css({
        width: shape.width,
        height: shape.height
    });
    
    // 4、使用overlays对象为图形元素添加蒙版层
    overlays.add('UserTask_1', {
        position: {
            top: -5,
            left: -5
        },
        html: $overlayhtml
    });
});
3.1.2、方案2 – 自定义图形元素的颜色拓展

可以使用模型器(或查看器,这两个对象的区别仅仅是可不可编辑diagram,他们拥有的服务应该差不多)的Modeling对象(的setColor方法)将颜色加入到的bpmn模型中。

// 接3.1.1

// 获取modleing对象(或者叫服务)
let modeling = viewer.get('modeling');
// 添加颜色,setColor第一个参数是图形元素对象的数组,第二个参数是颜色配置
modeling.setColor([ shape ], {
    stroke: 'green',
    fill: 'rgba(0, 80, 0, 0.4)'
}); 

3.2、元素模型

每一个diagram元素对象都可以通过businessObject属性获得对应的底层模型对象的引用。而business Object是根据bpmnXml配置生成的,可以用于读取和设置元素属性。

通过bpmn对象的moddleExtensions配置,可以json的方式自定义元素模型,事实上bpmn默认就拥有上百个类型的元素。

使用元素工厂对象elementsFactory,可以创建json定义中存在的任意元素对象,并设置对象的属性。

3.2.1、元素类型

bpmn默认元素

类型名称父类型属性
InterfaceRootElementname(String), operations(Operation), implementationRef(String),
OperationBaseElementname(String), inMessageRef(Message), outMessageRef(Message), errorRef(Error), implementationRef(String),
EndPointRootElement
AuditingBaseElement
GlobalTaskCallableElementresources(ResourceRole),
MonitoringBaseElement
PerformerResourceRole
ProcessFlowElementsContainer,CallableElementprocessType(ProcessType), isClosed(Boolean), auditing(Auditing), monitoring(Monitoring), properties(Property), laneSets(LaneSet), flowElements(FlowElement), artifacts(Artifact), resources(ResourceRole), correlationSubscriptions(CorrelationSubscription), supports(Process), definitionalCollaborationRef(Collaboration), isExecutable(Boolean),
LaneSetBaseElementlanes(Lane), name(String),
LaneBaseElementname(String), partitionElementRef(BaseElement), partitionElement(BaseElement), flowNodeRef(FlowNode), childLaneSet(LaneSet),
GlobalManualTaskGlobalTask
ManualTaskTask
UserTaskTaskrenderings(Rendering), implementation(String),
RenderingBaseElement
HumanPerformerPerformer
PotentialOwnerHumanPerformer
GlobalUserTaskGlobalTaskimplementation(String), renderings(Rendering),
GatewayFlowNodegatewayDirection(GatewayDirection),
EventBasedGatewayGatewayinstantiate(Boolean), eventGatewayType(EventBasedGatewayType),
ComplexGatewayGatewayactivationCondition(Expression), default(SequenceFlow),
ExclusiveGatewayGatewaydefault(SequenceFlow),
InclusiveGatewayGatewaydefault(SequenceFlow),
ParallelGatewayGateway
RootElementBaseElement
RelationshipBaseElementtype(String), direction(RelationshipDirection), source(Element), target(Element),
BaseElementid(String), documentation(Documentation), extensionDefinitions(ExtensionDefinition), extensionElements(ExtensionElements),
ExtensionmustUnderstand(Boolean), definition(ExtensionDefinition),
ExtensionDefinitionname(String), extensionAttributeDefinitions(ExtensionAttributeDefinition),
ExtensionAttributeDefinitionname(String), type(String), isReference(Boolean), extensionDefinition(ExtensionDefinition),
ExtensionElementsvalueRef(Element), values(Element), extensionAttributeDefinition(ExtensionAttributeDefinition),
DocumentationBaseElementtext(String), textFormat(String),
EventFlowNode,InteractionNodeproperties(Property),
IntermediateCatchEventCatchEvent
IntermediateThrowEventThrowEvent
EndEventThrowEvent
StartEventCatchEventisInterrupting(Boolean),
ThrowEventEventdataInputs(DataInput), dataInputAssociations(DataInputAssociation), inputSet(InputSet), eventDefinitions(EventDefinition), eventDefinitionRef(EventDefinition),
CatchEventEventparallelMultiple(Boolean), dataOutputs(DataOutput), dataOutputAssociations(DataOutputAssociation), outputSet(OutputSet), eventDefinitions(EventDefinition), eventDefinitionRef(EventDefinition),
BoundaryEventCatchEventcancelActivity(Boolean), attachedToRef(Activity),
EventDefinitionRootElement
CancelEventDefinitionEventDefinition
ErrorEventDefinitionEventDefinitionerrorRef(Error),
TerminateEventDefinitionEventDefinition
EscalationEventDefinitionEventDefinitionescalationRef(Escalation),
EscalationRootElementstructureRef(ItemDefinition), name(String), escalationCode(String),
CompensateEventDefinitionEventDefinitionwaitForCompletion(Boolean), activityRef(Activity),
TimerEventDefinitionEventDefinitiontimeDate(Expression), timeCycle(Expression), timeDuration(Expression),
LinkEventDefinitionEventDefinitionname(String), target(LinkEventDefinition), source(LinkEventDefinition),
MessageEventDefinitionEventDefinitionmessageRef(Message), operationRef(Operation),
ConditionalEventDefinitionEventDefinitioncondition(Expression),
SignalEventDefinitionEventDefinitionsignalRef(Signal),
SignalRootElementstructureRef(ItemDefinition), name(String),
ImplicitThrowEventThrowEvent
DataStateBaseElementname(String),
ItemAwareElementBaseElementitemSubjectRef(ItemDefinition), dataState(DataState),
DataAssociationBaseElementsourceRef(ItemAwareElement), targetRef(ItemAwareElement), transformation(FormalExpression), assignment(Assignment),
DataInputItemAwareElementname(String), isCollection(Boolean), inputSetRef(InputSet), inputSetWithOptional(InputSet), inputSetWithWhileExecuting(InputSet),
DataOutputItemAwareElementname(String), isCollection(Boolean), outputSetRef(OutputSet), outputSetWithOptional(OutputSet), outputSetWithWhileExecuting(OutputSet),
InputSetBaseElementname(String), dataInputRefs(DataInput), optionalInputRefs(DataInput), whileExecutingInputRefs(DataInput), outputSetRefs(OutputSet),
OutputSetBaseElementdataOutputRefs(DataOutput), name(String), inputSetRefs(InputSet), optionalOutputRefs(DataOutput), whileExecutingOutputRefs(DataOutput),
PropertyItemAwareElementname(String),
DataInputAssociationDataAssociation
DataOutputAssociationDataAssociation
InputOutputSpecificationBaseElementdataInputs(DataInput), dataOutputs(DataOutput), inputSets(InputSet), outputSets(OutputSet),
DataObjectFlowElement,ItemAwareElementisCollection(Boolean),
InputOutputBindinginputDataRef(InputSet), outputDataRef(OutputSet), operationRef(Operation),
AssignmentBaseElementfrom(Expression), to(Expression),
DataStoreRootElement,ItemAwareElementname(String), capacity(Integer), isUnlimited(Boolean),
DataStoreReferenceItemAwareElement,FlowElementdataStoreRef(DataStore),
DataObjectReferenceItemAwareElement,FlowElementdataObjectRef(DataObject),
ConversationLinkBaseElementsourceRef(InteractionNode), targetRef(InteractionNode), name(String),
ConversationAssociationBaseElementinnerConversationNodeRef(ConversationNode), outerConversationNodeRef(ConversationNode),
CallConversationConversationNodecalledCollaborationRef(Collaboration), participantAssociations(ParticipantAssociation),
ConversationConversationNode
SubConversationConversationNodeconversationNodes(ConversationNode),
ConversationNodeInteractionNode,BaseElementname(String), participantRef(Participant), messageFlowRefs(MessageFlow), correlationKeys(CorrelationKey),
GlobalConversationCollaboration
PartnerEntityRootElementname(String), participantRef(Participant),
PartnerRoleRootElementname(String), participantRef(Participant),
CorrelationPropertyRootElementcorrelationPropertyRetrievalExpression(CorrelationPropertyRetrievalExpression), name(String), type(ItemDefinition),
ErrorRootElementstructureRef(ItemDefinition), name(String), errorCode(String),
CorrelationKeyBaseElementcorrelationPropertyRef(CorrelationProperty), name(String),
ExpressionBaseElementbody(String),
FormalExpressionExpressionlanguage(String), evaluatesToTypeRef(ItemDefinition),
MessageRootElementname(String), itemRef(ItemDefinition),
ItemDefinitionRootElementitemKind(ItemKind), structureRef(String), isCollection(Boolean), import(Import),
FlowElementBaseElementname(String), auditing(Auditing), monitoring(Monitoring), categoryValueRef(CategoryValue),
SequenceFlowFlowElementisImmediate(Boolean), conditionExpression(Expression), sourceRef(FlowNode), targetRef(FlowNode),
FlowElementsContainerBaseElementlaneSets(LaneSet), flowElements(FlowElement),
CallableElementRootElementname(String), ioSpecification(InputOutputSpecification), supportedInterfaceRef(Interface), ioBinding(InputOutputBinding),
FlowNodeFlowElementincoming(SequenceFlow), outgoing(SequenceFlow), lanes(Lane),
CorrelationPropertyRetrievalExpressionBaseElementmessagePath(FormalExpression), messageRef(Message),
CorrelationPropertyBindingBaseElementdataPath(FormalExpression), correlationPropertyRef(CorrelationProperty),
ResourceRootElementname(String), resourceParameters(ResourceParameter),
ResourceParameterBaseElementname(String), isRequired(Boolean), type(ItemDefinition),
CorrelationSubscriptionBaseElementcorrelationKeyRef(CorrelationKey), correlationPropertyBinding(CorrelationPropertyBinding),
MessageFlowBaseElementname(String), sourceRef(InteractionNode), targetRef(InteractionNode), messageRef(Message),
MessageFlowAssociationBaseElementinnerMessageFlowRef(MessageFlow), outerMessageFlowRef(MessageFlow),
InteractionNodeincomingConversationLinks(ConversationLink), outgoingConversationLinks(ConversationLink),
ParticipantInteractionNode,BaseElementname(String), interfaceRef(Interface), participantMultiplicity(ParticipantMultiplicity), endPointRefs(EndPoint), processRef(Process),
ParticipantAssociationBaseElementinnerParticipantRef(Participant), outerParticipantRef(Participant),
ParticipantMultiplicityBaseElementminimum(Integer), maximum(Integer),
CollaborationRootElementname(String), isClosed(Boolean), participants(Participant), messageFlows(MessageFlow), artifacts(Artifact), conversations(ConversationNode), conversationAssociations(ConversationAssociation), participantAssociations(ParticipantAssociation), messageFlowAssociations(MessageFlowAssociation), correlationKeys(CorrelationKey), choreographyRef(Choreography), conversationLinks(ConversationLink),
ChoreographyActivityFlowNodeparticipantRef(Participant), initiatingParticipantRef(Participant), correlationKeys(CorrelationKey), loopType(ChoreographyLoopType),
CallChoreographyChoreographyActivitycalledChoreographyRef(Choreography), participantAssociations(ParticipantAssociation),
SubChoreographyChoreographyActivity,FlowElementsContainerartifacts(Artifact),
ChoreographyTaskChoreographyActivitymessageFlowRef(MessageFlow),
ChoreographyCollaboration,FlowElementsContainer
GlobalChoreographyTaskChoreographyinitiatingParticipantRef(Participant),
TextAnnotationArtifacttext(String), textFormat(String),
GroupArtifactcategoryValueRef(CategoryValue),
AssociationArtifactassociationDirection(AssociationDirection), sourceRef(BaseElement), targetRef(BaseElement),
CategoryRootElementcategoryValue(CategoryValue), name(String),
ArtifactBaseElement
CategoryValueBaseElementcategorizedFlowElements(FlowElement), value(String),
ActivityFlowNodeisForCompensation(Boolean), default(SequenceFlow), ioSpecification(InputOutputSpecification), boundaryEventRefs(BoundaryEvent), properties(Property), dataInputAssociations(DataInputAssociation), dataOutputAssociations(DataOutputAssociation), startQuantity(Integer), resources(ResourceRole), completionQuantity(Integer), loopCharacteristics(LoopCharacteristics),
ServiceTaskTaskimplementation(String), operationRef(Operation),
SubProcessActivity,FlowElementsContainer,InteractionNodetriggeredByEvent(Boolean), artifacts(Artifact),
LoopCharacteristicsBaseElement
MultiInstanceLoopCharacteristicsLoopCharacteristicsisSequential(Boolean), behavior(MultiInstanceBehavior), loopCardinality(Expression), loopDataInputRef(ItemAwareElement), loopDataOutputRef(ItemAwareElement), inputDataItem(DataInput), outputDataItem(DataOutput), complexBehaviorDefinition(ComplexBehaviorDefinition), completionCondition(Expression), oneBehaviorEventRef(EventDefinition), noneBehaviorEventRef(EventDefinition),
StandardLoopCharacteristicsLoopCharacteristicstestBefore(Boolean), loopCondition(Expression), loopMaximum(Integer),
CallActivityActivitycalledElement(String),
TaskActivity,InteractionNode
SendTaskTaskimplementation(String), operationRef(Operation), messageRef(Message),
ReceiveTaskTaskimplementation(String), instantiate(Boolean), operationRef(Operation), messageRef(Message),
ScriptTaskTaskscriptFormat(String), script(String),
BusinessRuleTaskTaskimplementation(String),
AdHocSubProcessSubProcesscompletionCondition(Expression), ordering(AdHocOrdering), cancelRemainingInstances(Boolean),
TransactionSubProcessprotocol(String), method(String),
GlobalScriptTaskGlobalTaskscriptLanguage(String), script(String),
GlobalBusinessRuleTaskGlobalTaskimplementation(String),
ComplexBehaviorDefinitionBaseElementcondition(FormalExpression), event(ImplicitThrowEvent),
ResourceRoleBaseElementresourceRef(Resource), resourceParameterBindings(ResourceParameterBinding), resourceAssignmentExpression(ResourceAssignmentExpression), name(String),
ResourceParameterBindingBaseElementexpression(Expression), parameterRef(ResourceParameter),
ResourceAssignmentExpressionBaseElementexpression(Expression),
ImportimportType(String), location(String), namespace(String),
DefinitionsBaseElementname(String), targetNamespace(String), expressionLanguage(String), typeLanguage(String), imports(Import), extensions(Extension), rootElements(RootElement), diagrams(bpmndi:BPMNDiagram), exporter(String), relationships(Relationship), exporterVersion(String),

camunda拓展元素

类型名称拓展父类父元素属性
InOutBindingElementcamunda:source(String), camunda:sourceExpression(String), camunda:target(String), camunda:businessKey(String), camunda:local(Boolean), camunda:variables(String),
InInOutBinding
OutInOutBinding
AsyncCapablebpmn:Activity, bpmn:Gateway, bpmn:Eventcamunda:async(Boolean), camunda:asyncBefore(Boolean), camunda:asyncAfter(Boolean), camunda:exclusive(Boolean),
JobPriorizedbpmn:Process, camunda:AsyncCapablecamunda:jobPriority(String),
SignalEventDefinitionbpmn:SignalEventDefinitioncamunda:async(Boolean),
ErrorEventDefinitionbpmn:ErrorEventDefinitioncamunda:errorCodeVariable(String), camunda:errorMessageVariable(String),
Errorbpmn:Errorcamunda:errorMessage(String),
PotentialStarterElementcamunda:resourceAssignmentExpression(bpmn:ResourceAssignmentExpression),
FormSupportedbpmn:StartEvent, bpmn:UserTaskcamunda:formHandlerClass(String), camunda:formKey(String),
TemplateSupportedbpmn:Process, bpmn:FlowElementcamunda:modelerTemplate(String),
Initiatorbpmn:StartEventcamunda:initiator(String),
ScriptTaskbpmn:ScriptTaskcamunda:resultVariable(String), camunda:resource(String),
Processbpmn:Processcamunda:candidateStarterGroups(String), camunda:candidateStarterUsers(String), camunda:versionTag(String), camunda:historyTimeToLive(String), camunda:isStartableInTasklist(Boolean),
EscalationEventDefinitionbpmn:EscalationEventDefinitioncamunda:escalationCodeVariable(String),
FormalExpressionbpmn:FormalExpressioncamunda:resource(String),
Assignablebpmn:UserTaskcamunda:assignee(String), camunda:candidateUsers(String), camunda:candidateGroups(String), camunda:dueDate(String), camunda:followUpDate(String), camunda:priority(String),
CallActivitybpmn:CallActivitycamunda:calledElementBinding(String), camunda:calledElementVersion(String), camunda:calledElementVersionTag(String), camunda:calledElementTenantId(String), camunda:caseRef(String), camunda:caseBinding(String), camunda:caseVersion(String), camunda:caseTenantId(String), camunda:variableMappingClass(String), camunda:variableMappingDelegateExpression(String),
ServiceTaskLikebpmn:ServiceTask, bpmn:BusinessRuleTask, bpmn:SendTask, bpmn:MessageEventDefinitioncamunda:expression(String), camunda:class(String), camunda:delegateExpression(String), camunda:resultVariable(String), camunda:test(String),
DmnCapablebpmn:BusinessRuleTaskcamunda:decisionRef(String), camunda:decisionRefBinding(String), camunda:decisionRefVersion(String), camunda:mapDecisionResult(String), camunda:decisionRefTenantId(String),
ExternalCapablecamunda:ServiceTaskLikecamunda:type(String), camunda:topic(String),
TaskPriorizedbpmn:Process, camunda:ExternalCapablecamunda:taskPriority(String),
PropertiesElementcamunda:values(camunda:Property),
PropertyElementcamunda:id(String), camunda:name(String), camunda:value(String),
ConnectorElementcamunda:inputOutput(camunda:InputOutput), camunda:connectorId(String),
InputOutputElementcamunda:inputOutput(camunda:InputOutput), camunda:connectorId(String), camunda:inputParameters(camunda:InputParameter), camunda:outputParameters(camunda:OutputParameter),
InputOutputParametercamunda:name(String), camunda:value(String), camunda:definition(camunda:InputOutputParameterDefinition),
InputOutputParameterDefinition
ListInputOutputParameterDefinitioncamunda:items(camunda:InputOutputParameterDefinition),
MapInputOutputParameterDefinitioncamunda:entries(camunda:Entry),
Entrycamunda:key(String), camunda:value(String), camunda:definition(camunda:InputOutputParameterDefinition),
ValueInputOutputParameterDefinitioncamunda:id(String), camunda:name(String), camunda:value(String),
ScriptInputOutputParameterDefinitioncamunda:scriptFormat(String), camunda:resource(String), camunda:value(String),
FieldElementcamunda:name(String), camunda:expression(String), camunda:stringValue(String), camunda:string(String),
InputParameterInputOutputParameter
OutputParameterInputOutputParameter
Collectablebpmn:MultiInstanceLoopCharacteristicscamunda:AsyncCapablecamunda:collection(String), camunda:elementVariable(String),
FailedJobRetryTimeCycleElementcamunda:body(String),
ExecutionListenerElementcamunda:expression(String), camunda:class(String), camunda:delegateExpression(String), camunda:event(String), camunda:script(camunda:Script), camunda:fields(camunda:Field),
TaskListenerElementcamunda:expression(String), camunda:class(String), camunda:delegateExpression(String), camunda:event(String), camunda:script(camunda:Script), camunda:fields(camunda:Field),
FormPropertyElementcamunda:id(String), camunda:name(String), camunda:type(String), camunda:required(String), camunda:readable(String), camunda:writable(String), camunda:variable(String), camunda:expression(String), camunda:datePattern(String), camunda:default(String), camunda:values(camunda:Value),
FormDataElementcamunda:fields(camunda:FormField), camunda:businessKey(String),
FormFieldElementcamunda:id(String), camunda:label(String), camunda:type(String), camunda:datePattern(String), camunda:defaultValue(String), camunda:properties(camunda:Properties), camunda:validation(camunda:Validation), camunda:values(camunda:Value),
ValidationElementcamunda:constraints(camunda:Constraint),
ConstraintElementcamunda:name(String), camunda:config(String),
ConditionalEventDefinitionbpmn:ConditionalEventDefinitioncamunda:variableName(String), camunda:variableEvent(String),
3.2.2、读取元素属性
// 获得元素注册器
let elementRegistry = viewer.get('elementRegistry');

// 使用元素注册器获得特定id的元素
let sequenceFlowEmenent = elementRegistry.get('SequenceFlow_1');
// 获取元素的businessObject对象,使用该对象获取元素属性
let sbo = sequenceFlowEmenent.businessObject;
console.log(sbo.name);
3.2.3、编辑元素属性

bpmn定义了几十个默认的元素类型,他们各自有对应的属性配置。使用businessObject可以对这些属性进行赋值。

// 接 3.2.1

// 使用moddle服务创建一个FormalExpression类型的元素,这是一个表达式属性元素
let moddle = viewer.get('moddle');
let newCondition = moddle.create('bpmn:FormalExpression', {
    body: '${ value > 100 }'
});

// 属性赋值,conditionExpression是SequenceFlow类型元素(连接线)的一个属性
sbo.conditionExpression = newCondition;

3.3、自定义元素

示例项目:https://github.com/bpmn-io/bpmn-js-nyan

nyan是一个自定义图形元素的示例总集,完成了一个自定义元素的典型实现。主要组成部分包括:

  • color-picker – 元素背景色设置服务,用于添加自定义上下文面板图标,并在点击后改变节点的颜色。
  • draw – 自定义图形元素渲染器,用于绘制元素显示效果。
  • palette – 自定义工具栏,用于在工具栏产生特殊的元素图标。

该项目实现了将一个ServiceTask任务节点的图标替换成一个git卡通猫图片。以下分别就上面的三个核心组成部分进行详细介绍。

3.3.1、color-picker

color-picker注册了两个服务模块:colorPicker和coloredRenderer。

  • colorPicker – colorPicker 做了两件事:向上下文面板添加自定义操作项,向命令栈注册自定义命令。通过这两件事colorPicker 实现了通过点击上下文面板中的自定义操作项改变元素的color属性的值。具体实现如下:

    • 1、colorPicker 使用contextPad.registerProvider向上下文面板注册自己。
    • 2、为了实现改变元素颜色目的,colorPicker 使用commandStack注册了自定义命令【shape.updateColor】,使用这个命令执行改变元素颜色特征。
    // commandStack命令的注册
    commandStack.registerHandler('shape.updateColor', UpdateColorHandler);
    
    // 命令函数可以传入一个context对象作为参数
    function UpdateColorHandler(){
        // 命令函数中有两个方法,分别是execute和revert,表示执行和回退
        this.execute = function(context) {
            const { element, color } = context;
            // 缓存原来值,用于回退
            context.oldColor = element.color;
            // 赋予元素颜色新值
            element.color = color;
            
            return element;
        }
        
        this.revert = function(context) {
            // 恢复上一个值
            context.element.color = context.oldColor;
            return context.element;
        }
    }
    
    • 3、定义getContextPadEntries函数,注册一个叫做changeColor的上下文图标。注册该图标的点击事件监听,在点击事件中触发第2步中的自定义命令。
    this.getContextPadEntries = function(element) {
    
        if (is(element, 'bpmn:Event')) {
          return {
            'changeColor': {
              group: 'edit',
              className: 'icon-red',
              title: 'Change element color',
              action: {
                click: changeColor
              }
            }
          };
        }
      };
    
    function changeColor(event, element) {
    
        var color = window.prompt('type a color code');
    
        commandStack.execute('shape.updateColor', { element: element, color: color });
      }
    

    **注意: **以上操作只是改变了元素的color特征值,并不能改变元素颜色。但是自定义命令的触发却能引发页面元素的重新渲染。

  • ColoredRenderer – 在其drawShape中读取元素中存储的color特征值,使用该值改变元素svg对象的fill值,从而实现颜色渲染。

3.3.2、draw – NyanRender

NyanRender和ColoredRenderer 两个模块在类型上是一样的,都是用于自定义渲染图形元素,对比两个模块可知,自定义渲染器必须要在构造函数中实现两个方法:

  • drawShape:使用svg自定义图形形状,因此可以直接拿一个svg图标作为形状使用(svg也支持插入普通图片,如gif的base64字符串)。
    • drawShape返回一个tiny-svg插件的提供的create函数创建的svg对象。
  • canRender:判断那种类型的元素需要使用该渲染器,一般通过ModelUtil提供的is函数即可。
3.3.3、palette – NyanPaletteProvider

NyanPaletteProvider用于在工具栏创建自定义元素图标,该类型模块的的核心函数是getPaletteEntries,与colorPicker 用到的getContextPadEntries方法不同之处在于,这是个原型函数,而getContextPadEntries却是属性函数,这可能是因为工具栏只有一个,而上下文面板有多个的原因。

  • NyanPaletteProvider需要使用palette.registerProvider(this)方式注册到工具栏中。
  • getPaletteEntries 函数返回一个对象,对象的一级属性是表示要添加到工具栏的子对象,也就是可以一次性添加很多图标,这个一级对象有如下属性:
    • group :所属工具栏分组,activity是工具栏的默认分组
    • title:工具标题
    • class-name:字体图标类名
    • imageUrl:图标图片路径,是个base64字符串
  • action:事件注册器,可以注册dragstart事件监听,使用该事件在画布上创建一个图形元素。
  // dragstart 事件触发元素创建
  function dragstartAction(event) {
      // 使用elementFactory创建一个ServiceTask元素,该元素首先需要是bpmn配置json中存在的。
      let shape = elementFactory.create('shape', {
          type: 'bpmn:ServiceTask'
      });
      // 使用create对象创建。create和elementFactory都是bpmn的内置对象,切都已通过NyanPaletteProvider的构造函数注入进来。
      create.start(event, shape);
  }

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐