fix(move): adjust positioning of all attached labels

This commit is contained in:
Nico Rehwaldt 2014-11-28 11:38:06 +01:00
parent 3af41e2e7e
commit 9e37037ac6
4 changed files with 160 additions and 106 deletions

View File

@ -59,14 +59,21 @@ function LabelSupport(eventBus, modeling, bpmnFactory) {
// move labels with shapes
eventBus.on([
'commandStack.shape.move.postExecute'
'commandStack.shapes.move.postExecute'
], function(e) {
var context = e.context,
shape = context.shape;
if (shape.label && context.hints.layout !== false) {
modeling.moveShape(shape.label, context.delta);
}
var context = e.context,
closure = context.closure,
enclosedElements = closure.enclosedElements;
// ensure we move all labels with their respective elements
// if they have not been moved already
_.forEach(enclosedElements, function(e) {
if (e.label && !enclosedElements[e.label.id]) {
modeling.moveShape(e.label, context.delta, e.parent);
}
});
});

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" id="simple" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" id="simple" exporter="camunda modeler" exporterVersion="2.6.0" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn2:process id="Process_1" isExecutable="false">
<bpmn2:subProcess id="SubProcess_1" name="Sub Process 1">
<bpmn2:incoming>SequenceFlow_3</bpmn2:incoming>
<bpmn2:outgoing>SequenceFlow_2</bpmn2:outgoing>
<bpmn2:startEvent id="StartEvent_1" name="Start Event 1">
<bpmn2:outgoing>SequenceFlow_1</bpmn2:outgoing>
@ -15,6 +16,10 @@
<bpmn2:incoming>SequenceFlow_2</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:sequenceFlow id="SequenceFlow_2" name="" sourceRef="SubProcess_1" targetRef="EndEvent_1"/>
<bpmn2:startEvent id="StartEvent_2" name="Start">
<bpmn2:outgoing>SequenceFlow_3</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:sequenceFlow id="SequenceFlow_3" name="Flow" sourceRef="StartEvent_2" targetRef="SubProcess_1"/>
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
@ -38,6 +43,19 @@
<di:waypoint xsi:type="dc:Point" x="600.0" y="230.0"/>
<di:waypoint xsi:type="dc:Point" x="650.0" y="230.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_11" bpmnElement="StartEvent_2">
<dc:Bounds height="36.0" width="36.0" x="108.0" y="212.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="126.0" y="253.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_3" bpmnElement="SequenceFlow_3" sourceElement="_BPMNShape_StartEvent_11" targetElement="_BPMNShape_SubProcess_2">
<di:waypoint xsi:type="dc:Point" x="144.0" y="230.0"/>
<di:waypoint xsi:type="dc:Point" x="300.0" y="230.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="21.0" width="33.0" x="192.0" y="204.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

View File

@ -107,7 +107,110 @@ describe('features/modeling - move shape', function() {
}));
it('should move label with element', inject(function(elementRegistry, modeling) {
describe('undo support', function() {
it('should undo', inject(function(elementRegistry, commandStack, modeling) {
// given
var startEventElement = elementRegistry.get('StartEvent_1'),
startEvent = startEventElement.businessObject;
var oldPosition = {
x: startEventElement.x,
y: startEventElement.y
};
modeling.moveShape(startEventElement, { x: 0, y: 50 });
// when
commandStack.undo();
// then
expect(startEvent.di.bounds.x).toBe(oldPosition.x);
expect(startEvent.di.bounds.y).toBe(oldPosition.y);
}));
it('should undo on label', inject(function(elementRegistry, commandStack, modeling) {
// given
var labelElement = elementRegistry.get('StartEvent_1_label'),
startEvent = labelElement.businessObject;
var oldPosition = {
x: labelElement.x,
y: labelElement.y
};
modeling.moveShape(labelElement, { x: 0, y: 50 });
// when
commandStack.undo();
// then
expect(startEvent.di.label.bounds.x).toBe(oldPosition.x);
expect(startEvent.di.label.bounds.y).toBe(oldPosition.y);
}));
});
describe('redo support', function() {
it('should redo', inject(function(elementRegistry, commandStack, modeling) {
// given
var startEventElement = elementRegistry.get('StartEvent_1'),
startEvent = startEventElement.businessObject;
modeling.moveShape(startEventElement, { x: 0, y: 50 });
var newPosition = {
x: startEventElement.x,
y: startEventElement.y
};
// when
commandStack.undo();
commandStack.redo();
// then
expect(startEvent.di.bounds.x).toBe(newPosition.x);
expect(startEvent.di.bounds.y).toBe(newPosition.y);
}));
it('should redo on label', inject(function(elementRegistry, commandStack, modeling) {
// given
var labelElement = elementRegistry.get('StartEvent_1_label'),
startEvent = labelElement.businessObject;
modeling.moveShape(labelElement, { x: 0, y: 50 });
var newPosition = {
x: labelElement.x,
y: labelElement.y
};
// when
commandStack.undo();
commandStack.redo();
// then
expect(startEvent.di.label.bounds.x).toBe(newPosition.x);
expect(startEvent.di.label.bounds.y).toBe(newPosition.y);
}));
});
});
describe('label suport', function() {
it('should move label with shape', inject(function(elementRegistry, modeling) {
// given
var startEventElement = elementRegistry.get('StartEvent_1'),
@ -121,110 +224,34 @@ describe('features/modeling - move shape', function() {
};
// when
modeling.moveShape(startEventElement, { x: 40, y: -80 });
modeling.moveShapes([ startEventElement ], { x: 40, y: -80 });
// then
expect(label.x).toBe(labelPosition.x + 40);
expect(label.y).toBe(labelPosition.y - 80);
}));
});
describe('undo support', function() {
it('should undo', inject(function(elementRegistry, commandStack, modeling) {
it('should move label with connection', inject(function(elementRegistry, modeling) {
// given
var startEventElement = elementRegistry.get('StartEvent_1'),
startEvent = startEventElement.businessObject;
var startEventElement = elementRegistry.get('StartEvent_2'),
startEvent = startEventElement.businessObject,
subProcessElement = elementRegistry.get('SubProcess_1'),
subProcess = startEventElement.businessObject,
flowLabel = elementRegistry.get('SequenceFlow_3_label');
var oldPosition = {
x: startEventElement.x,
y: startEventElement.y
};
modeling.moveShape(startEventElement, { x: 0, y: 50 });
// when
commandStack.undo();
// then
expect(startEvent.di.bounds.x).toBe(oldPosition.x);
expect(startEvent.di.bounds.y).toBe(oldPosition.y);
}));
it('should undo on label', inject(function(elementRegistry, commandStack, modeling) {
// given
var labelElement = elementRegistry.get('StartEvent_1_label'),
startEvent = labelElement.businessObject;
var oldPosition = {
x: labelElement.x,
y: labelElement.y
};
modeling.moveShape(labelElement, { x: 0, y: 50 });
// when
commandStack.undo();
// then
expect(startEvent.di.label.bounds.x).toBe(oldPosition.x);
expect(startEvent.di.label.bounds.y).toBe(oldPosition.y);
}));
});
describe('redo support', function() {
it('should redo', inject(function(elementRegistry, commandStack, modeling) {
// given
var startEventElement = elementRegistry.get('StartEvent_1'),
startEvent = startEventElement.businessObject;
modeling.moveShape(startEventElement, { x: 0, y: 50 });
var newPosition = {
x: startEventElement.x,
y: startEventElement.y
var labelPosition = {
x: flowLabel.x,
y: flowLabel.y
};
// when
commandStack.undo();
commandStack.redo();
modeling.moveShapes([ startEventElement, subProcessElement ], { x: 40, y: -80 });
// then
expect(startEvent.di.bounds.x).toBe(newPosition.x);
expect(startEvent.di.bounds.y).toBe(newPosition.y);
}));
it('should redo on label', inject(function(elementRegistry, commandStack, modeling) {
// given
var labelElement = elementRegistry.get('StartEvent_1_label'),
startEvent = labelElement.businessObject;
modeling.moveShape(labelElement, { x: 0, y: 50 });
var newPosition = {
x: labelElement.x,
y: labelElement.y
};
// when
commandStack.undo();
commandStack.redo();
// then
expect(startEvent.di.label.bounds.x).toBe(newPosition.x);
expect(startEvent.di.label.bounds.y).toBe(newPosition.y);
expect(flowLabel.x).toBe(labelPosition.x + 40);
expect(flowLabel.y).toBe(labelPosition.y - 80);
}));
});

View File

@ -70,7 +70,7 @@ describe('import - importer', function() {
runImport(diagram, xml, function(err, warnings) {
// then
expect(eventCount).toEqual(7);
expect(eventCount).toEqual(9);
done(err);
});
@ -81,7 +81,7 @@ describe('import - importer', function() {
describe('basics', function() {
it('should import process', function(done) {
it('should import simple process', function(done) {
// given
var xml = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf8');
@ -103,13 +103,15 @@ describe('import - importer', function() {
// then
expect(events).toEqual([
{ type: 'add', semantic: 'Process_1', di: 'BPMNPlane_1', diagramElement: 'Process_1' },
{ type: 'add', semantic: 'SubProcess_1', di: '_BPMNShape_SubProcess_2', diagramElement: 'SubProcess_1' },
{ type: 'add', semantic: 'StartEvent_1', di: '_BPMNShape_StartEvent_2', diagramElement: 'StartEvent_1' },
{ type: 'add', semantic: 'Task_1', di: '_BPMNShape_Task_2', diagramElement: 'Task_1' },
{ type: 'add', semantic: 'EndEvent_1', di: '_BPMNShape_EndEvent_2', diagramElement: 'EndEvent_1' },
{ type: 'add', semantic: 'SequenceFlow_1', di: 'BPMNEdge_SequenceFlow_1', diagramElement: 'SequenceFlow_1' },
{ type: 'add', semantic: 'SequenceFlow_2', di: 'BPMNEdge_SequenceFlow_2', diagramElement: 'SequenceFlow_2' }
{ type: 'add', semantic: 'Process_1', di: 'BPMNPlane_1', diagramElement: 'Process_1' },
{ type: 'add', semantic: 'SubProcess_1', di: '_BPMNShape_SubProcess_2', diagramElement: 'SubProcess_1' },
{ type: 'add', semantic: 'StartEvent_1', di: '_BPMNShape_StartEvent_2', diagramElement: 'StartEvent_1' },
{ type: 'add', semantic: 'Task_1', di: '_BPMNShape_Task_2', diagramElement: 'Task_1' },
{ type: 'add', semantic: 'EndEvent_1', di: '_BPMNShape_EndEvent_2', diagramElement: 'EndEvent_1' },
{ type: 'add', semantic: 'StartEvent_2', di: '_BPMNShape_StartEvent_11', diagramElement: 'StartEvent_2' },
{ type: 'add', semantic: 'SequenceFlow_1', di: 'BPMNEdge_SequenceFlow_1', diagramElement: 'SequenceFlow_1' },
{ type: 'add', semantic: 'SequenceFlow_2', di: 'BPMNEdge_SequenceFlow_2', diagramElement: 'SequenceFlow_2' },
{ type: 'add', semantic: 'SequenceFlow_3', di: 'BPMNEdge_SequenceFlow_3', diagramElement: 'SequenceFlow_3' }
]);
done(err);