feat(grid-snapping): snap resizable elements top-left

Related to camunda/camunda-modeler#1344
This commit is contained in:
Philipp Fromme 2019-04-18 14:51:30 +02:00 committed by merge-me[bot]
parent 369209ed59
commit 3b756e0725
4 changed files with 280 additions and 0 deletions

View File

@ -0,0 +1,25 @@
import { isAny } from '../modeling/util/ModelingUtil';
export default function BpmnGridSnapping(eventBus) {
eventBus.on([
'create.init',
'shape.move.init'
], function(event) {
var context = event.context,
shape = event.shape;
if (isAny(shape, [
'bpmn:Participant',
'bpmn:SubProcess',
'bpmn:TextAnnotation'
])) {
if (!context.gridSnappingContext) {
context.gridSnappingContext = {};
}
context.gridSnappingContext.snapLocation = 'top-left';
}
});
}
BpmnGridSnapping.$inject = [ 'eventBus' ];

View File

@ -0,0 +1,8 @@
import BpmnGridSnapping from './BpmnGridSnapping';
import GridSnappingModule from 'diagram-js/lib/features/grid-snapping';
export default {
__depends__: [ GridSnappingModule ],
__init__: [ 'bpmnGridSnapping' ],
bpmnGridSnapping: [ 'type', BpmnGridSnapping ]
};

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="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" id="Definitions_1kkksuc" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="2.0.0-0">
<bpmn:collaboration id="Collaboration_1">
<bpmn:participant id="Participant_1" name="Participant_1" processRef="Process_1" />
<bpmn:textAnnotation id="TextAnnotation_1">
<bpmn:text>TextAnnotation_1</bpmn:text>
</bpmn:textAnnotation>
<bpmn:association id="Association_0punwjh" sourceRef="Participant_1" targetRef="TextAnnotation_1" />
</bpmn:collaboration>
<bpmn:process id="Process_1" isExecutable="true">
<bpmn:subProcess id="SubProcess_1" name="SubProcess_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1">
<bpmndi:BPMNShape id="Participant_1brw48p_di" bpmnElement="Participant_1">
<dc:Bounds x="100" y="100" width="590" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="SubProcess_11f0dg1_di" bpmnElement="SubProcess_1" isExpanded="true">
<dc:Bounds x="150" y="130" width="350" height="190" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="TextAnnotation_0bnhhhy_di" bpmnElement="TextAnnotation_1">
<dc:Bounds x="700" y="20" width="110" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Association_0punwjh_di" bpmnElement="Association_0punwjh">
<di:waypoint x="646" y="100" />
<di:waypoint x="706" y="70" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,217 @@
import {
bootstrapModeler,
inject
} from 'test/TestHelper';
import coreModule from 'lib/core';
import createModule from 'diagram-js/lib/features/create';
import gridSnappingModule from 'lib/features/grid-snapping';
import modelingModule from 'lib/features/modeling';
import moveModule from 'diagram-js/lib/features/move';
import {
createCanvasEvent as canvasEvent
} from '../../../util/MockEvents';
import { isString } from 'min-dash';
var LOW_PRIORITY = 500;
describe('features/grid-snapping', function() {
var diagramXML = require('./BpmnGridSnapping.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: [
coreModule,
createModule,
gridSnappingModule,
modelingModule,
moveModule
]
}));
var participant,
subProcess,
textAnnotation;
beforeEach(inject(function(elementRegistry) {
participant = elementRegistry.get('Participant_1');
subProcess = elementRegistry.get('SubProcess_1');
textAnnotation = elementRegistry.get('TextAnnotation_1');
}));
describe('snap top-left', function() {
it('participant', inject(function(dragging, eventBus, move) {
// given
var events = recordEvents(eventBus, [
'shape.move.move',
'shape.move.end'
]);
// when
move.start(canvasEvent({ x: 100, y: 100 }), participant);
dragging.move(canvasEvent({ x: 106, y: 112 }));
dragging.move(canvasEvent({ x: 112, y: 124 }));
dragging.move(canvasEvent({ x: 118, y: 136 }));
dragging.move(canvasEvent({ x: 124, y: 148 }));
dragging.move(canvasEvent({ x: 130, y: 160 }));
dragging.end();
// then
expect(events.map(position('top-left'))).to.eql([
{ x: 110, y: 110 }, // move
{ x: 110, y: 120 }, // move
{ x: 120, y: 140 }, // move
{ x: 120, y: 150 }, // move
{ x: 130, y: 160 }, // move
{ x: 130, y: 160 } // end
]);
// expect snapped to top-left
expect(participant.x).to.equal(130);
expect(participant.y).to.equal(160);
}));
it('sub process', inject(function(dragging, eventBus, move) {
// given
var events = recordEvents(eventBus, [
'shape.move.move',
'shape.move.end'
]);
// when
move.start(canvasEvent({ x: 150, y: 130 }), subProcess);
dragging.move(canvasEvent({ x: 156, y: 142 }));
dragging.move(canvasEvent({ x: 162, y: 154 }));
dragging.move(canvasEvent({ x: 168, y: 166 }));
dragging.move(canvasEvent({ x: 174, y: 178 }));
dragging.move(canvasEvent({ x: 180, y: 190 }));
dragging.end();
// then
expect(events.map(position('top-left'))).to.eql([
{ x: 160, y: 140 }, // move
{ x: 160, y: 150 }, // move
{ x: 170, y: 170 }, // move
{ x: 170, y: 180 }, // move
{ x: 180, y: 190 }, // move
{ x: 180, y: 190 } // end
]);
// expect snapped to top-left
expect(subProcess.x).to.equal(180);
expect(subProcess.y).to.equal(190);
}));
it('text annotation', inject(function(dragging, eventBus, move) {
// given
var events = recordEvents(eventBus, [
'shape.move.move',
'shape.move.end'
]);
// when
move.start(canvasEvent({ x: 700, y: 20 }), textAnnotation);
dragging.move(canvasEvent({ x: 706, y: 32 }));
dragging.move(canvasEvent({ x: 712, y: 44 }));
dragging.move(canvasEvent({ x: 718, y: 56 }));
dragging.move(canvasEvent({ x: 724, y: 68 }));
dragging.move(canvasEvent({ x: 730, y: 80 }));
dragging.end();
// then
expect(events.map(position('top-left'))).to.eql([
{ x: 710, y: 30 }, // move
{ x: 710, y: 40 }, // move
{ x: 720, y: 60 }, // move
{ x: 720, y: 70 }, // move
{ x: 730, y: 80 }, // move
{ x: 730, y: 80 } // end
]);
// expect snapped to top-left
expect(textAnnotation.x).to.equal(730);
expect(textAnnotation.y).to.equal(80);
}));
});
});
// helpers //////////
function recordEvents(eventBus, eventTypes) {
var events = [];
eventTypes.forEach(function(eventType) {
eventBus.on(eventType, LOW_PRIORITY, function(event) {
events.push(event);
});
});
return events;
}
/**
* Returns x and y of an event. If called with string that specifies orientation if will return
* x and y of specified orientation.
*
* @param {Object|string} event - Event or orientation <top|right|bottom|left>
*
* @returns {Object}
*/
function position(event) {
var orientation;
if (isString(event)) {
orientation = event;
return function(event) {
var shape = event.shape;
var x = event.x,
y = event.y;
if (/top/.test(orientation)) {
y -= shape.height / 2;
}
if (/right/.test(orientation)) {
x += shape.width / 2;
}
if (/bottom/.test(orientation)) {
y += shape.height / 2;
}
if (/left/.test(orientation)) {
x -= shape.width / 2;
}
return {
x: x,
y: y
};
};
}
return {
x: event.x,
y: event.y
};
}