feat(auto-resize): expand participants when moving multiple elements
Closes #353
This commit is contained in:
parent
536eb790a0
commit
857454bbc1
|
@ -2,10 +2,14 @@
|
|||
|
||||
var inherits = require('inherits');
|
||||
|
||||
var is = require('../../util/ModelUtil').is;
|
||||
var is = require('../../util/ModelUtil').is,
|
||||
getBoundingBox = require('diagram-js/lib/util/Elements').getBBox;
|
||||
|
||||
var pick = require('lodash/object/pick'),
|
||||
assign = require('lodash/object/assign');
|
||||
assign = require('lodash/object/assign'),
|
||||
forEach = require('lodash/collection/forEach'),
|
||||
values = require('lodash/object/values'),
|
||||
flatten = require('lodash/array/flatten');
|
||||
|
||||
var CommandInterceptor = require('diagram-js/lib/command/CommandInterceptor');
|
||||
|
||||
|
@ -14,25 +18,34 @@ var PADDING = { top: 2, bottom: 2, left: 15, right: 15 };
|
|||
|
||||
/**
|
||||
* An auto resize component that takes care of expanding parent participants
|
||||
* and lanes if an element is modeled close to an edge of the parent element.
|
||||
* and lanes if elements are modeled close to an edge of the parent element.
|
||||
*/
|
||||
function AutoResize(eventBus, canvas, modeling){
|
||||
|
||||
CommandInterceptor.call(this, eventBus);
|
||||
|
||||
this.postExecuted([ 'shape.create', 'shape.move' ], function(event) {
|
||||
this.postExecuted([ 'shape.create' ], function(event) {
|
||||
var context = event.context,
|
||||
shape = context.shape,
|
||||
parent = context.parent || context.newParent;
|
||||
|
||||
expand(shape, parent);
|
||||
expand([shape], parent);
|
||||
});
|
||||
|
||||
this.postExecuted([ 'elements.move' ], function(event) {
|
||||
|
||||
var context = event.context,
|
||||
elements = flatten(values(context.closure.topLevel)),
|
||||
parent = context.parent || context.newParent;
|
||||
|
||||
expand(elements, parent);
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns an object which indicates near which bounding edge(s)
|
||||
* of a target an element is located.
|
||||
* of a target a bounding box is located.
|
||||
*
|
||||
* @param {Shape} element
|
||||
* @param {Object} bbox bounding box object with x, y, width and height properties
|
||||
* @param {Shape} target
|
||||
* @param {Number} padding
|
||||
*
|
||||
|
@ -40,67 +53,68 @@ function AutoResize(eventBus, canvas, modeling){
|
|||
*
|
||||
* @example
|
||||
*
|
||||
* // If an element is near the bottom left corner of a target the return object is:
|
||||
* // If the bounding box is near the bottom left corner of a target the return object is:
|
||||
* { top: false, bottom: true, left: true, right: false }
|
||||
*
|
||||
*/
|
||||
function isInbounds(element, target, padding) {
|
||||
function isInbounds(bbox, target, padding) {
|
||||
return {
|
||||
top: element.y < target.y + padding.top && element.y + element.height > target.y,
|
||||
bottom: element.y < target.y + target.height &&
|
||||
element.y + element.height > target.y + target.height - padding.bottom,
|
||||
left: element.x < target.x + padding.left && element.x + element.width > target.x,
|
||||
right: element.x < target.x + target.width &&
|
||||
element.x + element.width > target.x + target.width - padding.right,
|
||||
top: bbox.y < target.y + padding.top && bbox.y + bbox.height > target.y,
|
||||
bottom: bbox.y < target.y + target.height && bbox.y + bbox.height > target.y + target.height - padding.bottom,
|
||||
left: bbox.x < target.x + padding.left && bbox.x + bbox.width > target.x,
|
||||
right: bbox.x < target.x + target.width && bbox.x + bbox.width > target.x + target.width - padding.right,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand target elements if the moved element is near or on an edge, considering the position
|
||||
* of the element edge in relation to the parent's edge plus padding. The amount to expand
|
||||
* can be defined for each edge in the OFFSET variables.
|
||||
* Expand the target shape if the bounding box of the moved elements is near or on an edge,
|
||||
* considering the position of the bounding box in relation to the parent's edge plus padding.
|
||||
* The amount to expand can be defined for each edge in the OFFSET object.
|
||||
*
|
||||
* @param {Shape} shape
|
||||
* @param {Array<Shape>} [elements]
|
||||
* @param {Shape} target
|
||||
*/
|
||||
function expand(shape, target) {
|
||||
function expand(elements, target) {
|
||||
|
||||
if (is(shape, 'bpmn:Lane')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (shape.labelTarget) {
|
||||
return;
|
||||
}
|
||||
var bbox = getBoundingBox(elements),
|
||||
canExpand = true;
|
||||
|
||||
if (!is(target, 'bpmn:Participant') && !is(target, 'bpmn:Lane')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (target !== shape.parent) {
|
||||
forEach(elements, function(element) {
|
||||
|
||||
if (is(element, 'bpmn:Lane') || element.labelTarget) {
|
||||
canExpand = false;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (!canExpand) {
|
||||
return;
|
||||
}
|
||||
|
||||
var inbounds = isInbounds(shape, target, PADDING);
|
||||
var inbounds = isInbounds(bbox, target, PADDING);
|
||||
|
||||
var newBounds = pick(target, [ 'x', 'y', 'width', 'height' ]);
|
||||
|
||||
if (inbounds.top) {
|
||||
var topPosition = shape.y - OFFSET.top;
|
||||
var topPosition = bbox.y - OFFSET.top;
|
||||
assign(newBounds, { y: topPosition, height: target.height + target.y - topPosition });
|
||||
}
|
||||
|
||||
if (inbounds.bottom) {
|
||||
assign(newBounds, { height: shape.y + shape.height + OFFSET.bottom - target.y });
|
||||
assign(newBounds, { height: bbox.y + bbox.height + OFFSET.bottom - target.y });
|
||||
}
|
||||
|
||||
if (inbounds.left) {
|
||||
var leftPosition = shape.x - OFFSET.left;
|
||||
var leftPosition = bbox.x - OFFSET.left;
|
||||
assign(newBounds, { x: leftPosition, width: target.width + target.x - leftPosition });
|
||||
}
|
||||
|
||||
if (inbounds.right) {
|
||||
assign(newBounds, { width: shape.x + shape.width + OFFSET.right - target.x });
|
||||
assign(newBounds, { width: bbox.x + bbox.width + OFFSET.right - target.x });
|
||||
}
|
||||
|
||||
modeling.resizeShape(target, newBounds);
|
||||
|
|
|
@ -189,6 +189,34 @@ describe('features/auto-resize', function() {
|
|||
|
||||
});
|
||||
|
||||
describe('after moving multiple elements', function() {
|
||||
|
||||
it('should expand the right edge', inject(function(modeling, selection) {
|
||||
|
||||
// when
|
||||
modeling.moveElements([task, startEvent], { x: 200, y: 0 }, participant);
|
||||
|
||||
// then
|
||||
var expectedBounds = assign(originalBounds, { width: 625 });
|
||||
|
||||
expect(participant).to.have.bounds(expectedBounds);
|
||||
|
||||
}));
|
||||
|
||||
|
||||
it('should expand the bottom edge', inject(function(modeling, selection) {
|
||||
|
||||
// when
|
||||
modeling.moveElements([task, startEvent], { x: 0, y: 48 }, participant);
|
||||
|
||||
// then
|
||||
var expectedBounds = assign(originalBounds, { height: 237 });
|
||||
|
||||
expect(participant).to.have.bounds(expectedBounds);
|
||||
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('after appending', function(){
|
||||
|
||||
|
@ -280,6 +308,25 @@ describe('features/auto-resize', function() {
|
|||
expect(laneShape).to.have.bounds({ x: 307, y: 160, width: 443, height: 260});
|
||||
}));
|
||||
|
||||
|
||||
it('should auto-resize to fit multiple moved elements', inject(function(elementRegistry, modeling) {
|
||||
|
||||
// given
|
||||
var laneShape = elementRegistry.get('Lane_Nested'),
|
||||
taskShape = elementRegistry.get('Task_1'),
|
||||
startEventShape = elementRegistry.get('StartEvent_1');
|
||||
|
||||
var originalBounds = getBounds(laneShape);
|
||||
|
||||
// when
|
||||
modeling.moveElements([taskShape, startEventShape], { x: 200, y: 0 }, laneShape);
|
||||
|
||||
// then
|
||||
var expectedBounds = assign(originalBounds, { width: 565 });
|
||||
|
||||
expect(laneShape).to.have.bounds(expectedBounds);
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue