feat(modeler): add bendpoints
It is now possible to add bendpoints to flows or drag bendpoints to update their position / trigger reconnects. Upon bendpoint move a rule is checked to figure out whether or not a bendpoint operation is allowed or not. Closes #123 Closes #138 Closes #139 Closes #165
This commit is contained in:
parent
2236965d4b
commit
85e512c97d
|
@ -65,6 +65,7 @@ Modeler.prototype._modelingModules = [
|
|||
require('diagram-js/lib/features/keyboard'),
|
||||
require('diagram-js/lib/features/snapping'),
|
||||
require('diagram-js/lib/features/move'),
|
||||
require('diagram-js/lib/features/bendpoints'),
|
||||
require('diagram-js/lib/features/resize'),
|
||||
require('diagram-js/lib/features/lasso-tool'),
|
||||
require('./features/modeling'),
|
||||
|
|
|
@ -195,11 +195,12 @@ Viewer.prototype.importDefinitions = function(definitions, done) {
|
|||
}
|
||||
|
||||
this.definitions = definitions;
|
||||
this.diagram = this._createDiagram(this.options);
|
||||
|
||||
this._init(this.diagram);
|
||||
var diagram = this.diagram = this._createDiagram(this.options);
|
||||
|
||||
Importer.importBpmnDiagram(this.diagram, definitions, done);
|
||||
this._init(diagram);
|
||||
|
||||
Importer.importBpmnDiagram(diagram, definitions, done);
|
||||
} catch (e) {
|
||||
done(e);
|
||||
}
|
||||
|
@ -270,7 +271,6 @@ Viewer.prototype.on = function(event, handler) {
|
|||
var diagram = this.diagram,
|
||||
listeners = this.__listeners = this.__listeners || [];
|
||||
|
||||
listeners = this.__listeners || [];
|
||||
listeners.push({ event: event, handler: handler });
|
||||
|
||||
if (diagram) {
|
||||
|
|
|
@ -34,7 +34,12 @@ function BpmnUpdater(eventBus, bpmnFactory, connectionDocking) {
|
|||
}
|
||||
}
|
||||
|
||||
this.executed([ 'connection.layout', 'connection.create' ], cropConnection);
|
||||
this.executed([
|
||||
'connection.layout',
|
||||
'connection.create',
|
||||
'connection.reconnectEnd',
|
||||
'connection.reconnectStart'
|
||||
], cropConnection);
|
||||
|
||||
this.reverted([ 'connection.layout' ], function(e) {
|
||||
delete e.context.cropped;
|
||||
|
@ -78,8 +83,21 @@ function BpmnUpdater(eventBus, bpmnFactory, connectionDocking) {
|
|||
self.updateConnection(e.context.connection);
|
||||
}
|
||||
|
||||
this.executed([ 'connection.create', 'connection.move', 'connection.delete' ], updateConnection);
|
||||
this.reverted([ 'connection.create', 'connection.move', 'connection.delete' ], updateConnection);
|
||||
this.executed([
|
||||
'connection.create',
|
||||
'connection.move',
|
||||
'connection.delete',
|
||||
'connection.reconnectEnd',
|
||||
'connection.reconnectStart'
|
||||
], updateConnection);
|
||||
|
||||
this.reverted([
|
||||
'connection.create',
|
||||
'connection.move',
|
||||
'connection.delete',
|
||||
'connection.reconnectEnd',
|
||||
'connection.reconnectStart'
|
||||
], updateConnection);
|
||||
|
||||
|
||||
// update waypoints
|
||||
|
@ -87,8 +105,21 @@ function BpmnUpdater(eventBus, bpmnFactory, connectionDocking) {
|
|||
self.updateConnectionWaypoints(e.context.connection);
|
||||
}
|
||||
|
||||
this.executed([ 'connection.layout', 'connection.move' ], updateConnectionWaypoints);
|
||||
this.reverted([ 'connection.layout', 'connection.move' ], updateConnectionWaypoints);
|
||||
this.executed([
|
||||
'connection.layout',
|
||||
'connection.move',
|
||||
'connection.updateWaypoints',
|
||||
'connection.reconnectEnd',
|
||||
'connection.reconnectStart'
|
||||
], updateConnectionWaypoints);
|
||||
|
||||
this.reverted([
|
||||
'connection.layout',
|
||||
'connection.move',
|
||||
'connection.updateWaypoints',
|
||||
'connection.reconnectEnd',
|
||||
'connection.reconnectStart'
|
||||
], updateConnectionWaypoints);
|
||||
}
|
||||
|
||||
module.exports = BpmnUpdater;
|
||||
|
|
|
@ -46,7 +46,11 @@ Modeling.prototype.connect = function(source, target, attrs) {
|
|||
targetBo = target.businessObject;
|
||||
|
||||
if (!attrs) {
|
||||
if (sourceBo.$instanceOf('bpmn:FlowNode') && targetBo.$instanceOf('bpmn:FlowNode')) {
|
||||
if (sourceBo.$instanceOf('bpmn:FlowNode') &&
|
||||
targetBo.$instanceOf('bpmn:FlowNode') &&
|
||||
!sourceBo.$instanceOf('bpmn:EndEvent') &&
|
||||
!targetBo.$instanceOf('bpmn:StartEvent')) {
|
||||
|
||||
attrs = {
|
||||
type: 'bpmn:SequenceFlow'
|
||||
};
|
||||
|
|
|
@ -19,23 +19,64 @@ ModelingRules.prototype.init = function() {
|
|||
|
||||
// rules
|
||||
|
||||
this.addRule('connection.create', function(context) {
|
||||
|
||||
var source = context.source,
|
||||
target = context.target;
|
||||
function canConnect(source, target, connection) {
|
||||
|
||||
if (!source || source.labelTarget || !target || target.labelTarget) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return source.businessObject.$parent === target.businessObject.$parent &&
|
||||
source.businessObject.$instanceOf('bpmn:FlowNode') &&
|
||||
!source.businessObject.$instanceOf('bpmn:EndEvent') &&
|
||||
!target.businessObject.$instanceOf('bpmn:StartEvent') &&
|
||||
(target.businessObject.$instanceOf('bpmn:FlowNode') ||
|
||||
target.businessObject.$instanceOf('bpmn:TextAnnotation'));
|
||||
var sourceBo = source.businessObject,
|
||||
targetBo = target.businessObject,
|
||||
connectionBo = connection && connection.businessObject;
|
||||
|
||||
if (sourceBo.$parent !== targetBo.$parent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (connectionBo && connectionBo.$instanceOf('bpmn:SequenceFlow')) {
|
||||
if (!sourceBo.$instanceOf('bpmn:FlowNode') ||
|
||||
!targetBo.$instanceOf('bpmn:FlowNode') ||
|
||||
sourceBo.$instanceOf('bpmn:EndEvent') ||
|
||||
targetBo.$instanceOf('bpmn:StartEvent')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return (sourceBo.$instanceOf('bpmn:FlowNode') ||
|
||||
sourceBo.$instanceOf('bpmn:TextAnnotation')) &&
|
||||
(targetBo.$instanceOf('bpmn:FlowNode') ||
|
||||
targetBo.$instanceOf('bpmn:TextAnnotation'));
|
||||
}
|
||||
|
||||
this.addRule('connection.create', function(context) {
|
||||
var source = context.source,
|
||||
target = context.target;
|
||||
|
||||
return canConnect(source, target);
|
||||
});
|
||||
|
||||
this.addRule('connection.reconnectStart', function(context) {
|
||||
|
||||
var connection = context.connection,
|
||||
source = context.hover,
|
||||
target = connection.target;
|
||||
|
||||
return canConnect(source, target, connection);
|
||||
});
|
||||
|
||||
this.addRule('connection.reconnectEnd', function(context) {
|
||||
|
||||
var connection = context.connection,
|
||||
source = connection.source,
|
||||
target = context.hover;
|
||||
|
||||
return canConnect(source, target, connection);
|
||||
});
|
||||
|
||||
this.addRule('connection.updateWaypoints', function(context) {
|
||||
// OK! but visually ignore
|
||||
return null;
|
||||
});
|
||||
|
||||
this.addRule('shape.resize', function(context) {
|
||||
|
||||
|
|
|
@ -83,6 +83,37 @@ describe('Modeler', function() {
|
|||
});
|
||||
|
||||
|
||||
describe('bendpoint editing support', function() {
|
||||
|
||||
var Events = require('diagram-js/test/util/Events');
|
||||
|
||||
it('should allow to edit bendpoints', function(done) {
|
||||
|
||||
var xml = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf8');
|
||||
|
||||
createModeler(xml, function(err, viewer) {
|
||||
|
||||
// given
|
||||
var bendpointMove = viewer.get('bendpointMove'),
|
||||
dragging = viewer.get('dragging'),
|
||||
elementRegistry = viewer.get('elementRegistry'),
|
||||
createEvent = Events.scopedCreate(viewer.get('canvas'));
|
||||
|
||||
// assume
|
||||
expect(bendpointMove).toBeDefined();
|
||||
|
||||
// when
|
||||
bendpointMove.start(createEvent({ x: 0, y: 0 }), elementRegistry.get('SequenceFlow_1'), 1);
|
||||
dragging.move(createEvent({ x: 200, y: 200 }));
|
||||
|
||||
done(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
it('should handle errors', function(done) {
|
||||
|
||||
var xml = 'invalid stuff';
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
var Matchers = require('../../../Matchers'),
|
||||
TestHelper = require('../../../TestHelper');
|
||||
var TestHelper = require('../../../TestHelper');
|
||||
|
||||
/* global bootstrapModeler, inject */
|
||||
|
||||
|
@ -18,9 +17,6 @@ var LabelUtil = require('../../../../lib/util/Label');
|
|||
|
||||
describe('features/modeling - append shape', function() {
|
||||
|
||||
beforeEach(Matchers.addDeepEquals);
|
||||
|
||||
|
||||
var diagramXML = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf8');
|
||||
|
||||
var testModules = [ coreModule, modelingModule ];
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
'use strict';
|
||||
|
||||
var TestHelper = require('../../../TestHelper');
|
||||
|
||||
/* global bootstrapModeler, inject */
|
||||
|
||||
var _ = require('lodash');
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
var modelingModule = require('../../../../lib/features/modeling'),
|
||||
bendpointsModule = require('diagram-js/lib/features/bendpoints'),
|
||||
coreModule = require('../../../../lib/core');
|
||||
|
||||
|
||||
describe('features/bendpoints', function() {
|
||||
|
||||
var diagramXML = fs.readFileSync('test/fixtures/bpmn/features/drop/drop.bpmn', 'utf8');
|
||||
|
||||
var testModules = [ coreModule, bendpointsModule, modelingModule ];
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
|
||||
|
||||
|
||||
it('should contain bendpoints', inject(function(bendpoints) {
|
||||
expect(bendpoints).toBeDefined();
|
||||
}));
|
||||
|
||||
});
|
|
@ -1,7 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
var Matchers = require('../../../Matchers'),
|
||||
TestHelper = require('../../../TestHelper');
|
||||
var TestHelper = require('../../../TestHelper');
|
||||
|
||||
/* global bootstrapModeler, inject */
|
||||
|
||||
|
@ -15,9 +14,6 @@ var modelingModule = require('../../../../lib/features/modeling'),
|
|||
|
||||
describe('features/move - drop', function() {
|
||||
|
||||
beforeEach(Matchers.addDeepEquals);
|
||||
|
||||
|
||||
var diagramXML = fs.readFileSync('test/fixtures/bpmn/features/drop/drop.bpmn', 'utf8');
|
||||
var diagramXML2 = fs.readFileSync('test/fixtures/bpmn/features/drop/recursive-task.bpmn', 'utf8');
|
||||
|
||||
|
|
Loading…
Reference in New Issue