From dafa6f138c3584182d75ce9f454d1013744e63d5 Mon Sep 17 00:00:00 2001 From: Philipp Fromme Date: Tue, 10 Mar 2020 19:48:21 +0100 Subject: [PATCH] fix(space-tool): consider lanes when resizing participant Related to camunda/camunda-modeler#1703 --- .../modeling/behavior/ResizeBehavior.js | 2 + .../modeling/behavior/SpaceToolBehavior.js | 73 ++++++++++++++++- .../modeling/behavior/util/ResizeUtil.js | 18 ++--- .../behavior/SpaceToolBehaviorSpec.js | 81 ++++++++++++++++++- .../SpaceToolBehaviorSpec.participant.bpmn | 57 +++++++++++++ ... => SpaceToolBehaviorSpec.subprocess.bpmn} | 0 6 files changed, 216 insertions(+), 15 deletions(-) create mode 100644 test/spec/features/modeling/behavior/SpaceToolBehaviorSpec.participant.bpmn rename test/spec/features/modeling/behavior/{SpaceToolBehaviorSpec.bpmn => SpaceToolBehaviorSpec.subprocess.bpmn} (100%) diff --git a/lib/features/modeling/behavior/ResizeBehavior.js b/lib/features/modeling/behavior/ResizeBehavior.js index f72d16d2..935752cf 100644 --- a/lib/features/modeling/behavior/ResizeBehavior.js +++ b/lib/features/modeling/behavior/ResizeBehavior.js @@ -6,6 +6,8 @@ import { getParticipantResizeConstraints } from './util/ResizeUtil'; var HIGH_PRIORITY = 1500; +export var LANE_MIN_DIMENSIONS = { width: 300, height: 60 }; + export var PARTICIPANT_MIN_DIMENSIONS = { width: 300, height: 150 }; export var SUB_PROCESS_MIN_DIMENSIONS = { width: 140, height: 120 }; diff --git a/lib/features/modeling/behavior/SpaceToolBehavior.js b/lib/features/modeling/behavior/SpaceToolBehavior.js index 64e19ee3..593fcef5 100644 --- a/lib/features/modeling/behavior/SpaceToolBehavior.js +++ b/lib/features/modeling/behavior/SpaceToolBehavior.js @@ -1,25 +1,45 @@ -import { forEach } from 'min-dash'; +import { + forEach, + reduce +} from 'min-dash'; import { is } from '../../../util/ModelUtil'; import { isExpanded } from '../../../util/DiUtil'; import { + LANE_MIN_DIMENSIONS, PARTICIPANT_MIN_DIMENSIONS, SUB_PROCESS_MIN_DIMENSIONS, TEXT_ANNOTATION_MIN_DIMENSIONS } from './ResizeBehavior'; +import { getChildLanes } from '../util/LaneUtil'; + +var max = Math.max; + + export default function SpaceToolBehavior(eventBus) { eventBus.on('spaceTool.getMinDimensions', function(context) { var shapes = context.shapes, + axis = context.axis, + start = context.start, minDimensions = {}; forEach(shapes, function(shape) { var id = shape.id; if (is(shape, 'bpmn:Participant')) { - minDimensions[ id ] = PARTICIPANT_MIN_DIMENSIONS; + + if (isHorizontal(axis)) { + minDimensions[ id ] = PARTICIPANT_MIN_DIMENSIONS; + } else { + minDimensions[ id ] = { + width: PARTICIPANT_MIN_DIMENSIONS.width, + height: getParticipantMinHeight(shape, start) + }; + } + } if (is(shape, 'bpmn:SubProcess') && isExpanded(shape)) { @@ -36,3 +56,52 @@ export default function SpaceToolBehavior(eventBus) { } SpaceToolBehavior.$inject = [ 'eventBus' ]; + + +// helpers ////////// + +/** + * Get minimum height for participant taking lanes into account. + * + * @param {} participant + * @param {number} start + * + * @returns {Object} + */ +function getParticipantMinHeight(participant, start) { + var lanes = getChildLanes(participant); + + if (!lanes.length) { + return PARTICIPANT_MIN_DIMENSIONS.height; + } + + function getLanesMinHeight(element) { + return reduce(getChildLanes(element), function(minHeight, lane) { + if (start >= lane.y && start <= lane.y + lane.height) { + + // resizing lane + if (hasChildLanes(lane)) { + minHeight += getLanesMinHeight(lane); + } else { + minHeight += lane.y + LANE_MIN_DIMENSIONS.height - participant.y; + } + } else if (start <= lane.y) { + + // lane after resizing lane + minHeight += lane.height; + } + + return minHeight; + }, 0); + } + + return max(PARTICIPANT_MIN_DIMENSIONS.height, getLanesMinHeight(participant)); +} + +function hasChildLanes(element) { + return !!getChildLanes(element).length; +} + +function isHorizontal(axis) { + return axis === 'x'; +} \ No newline at end of file diff --git a/lib/features/modeling/behavior/util/ResizeUtil.js b/lib/features/modeling/behavior/util/ResizeUtil.js index bf0bb2a9..f0bfd86e 100644 --- a/lib/features/modeling/behavior/util/ResizeUtil.js +++ b/lib/features/modeling/behavior/util/ResizeUtil.js @@ -9,6 +9,8 @@ import { getLanesRoot } from '../../../modeling/util/LaneUtil'; +import { LANE_MIN_DIMENSIONS } from '../ResizeBehavior'; + var abs = Math.abs, min = Math.min, max = Math.max; @@ -31,9 +33,7 @@ function addMax(trbl, attr, value) { return addToTrbl(trbl, attr, value, max); } -var LANE_MIN_HEIGHT = 60, - LANE_MIN_WIDTH = 300, - LANE_RIGHT_PADDING = 20, +var LANE_RIGHT_PADDING = 20, LANE_LEFT_PADDING = 50, LANE_TOP_PADDING = 20, LANE_BOTTOM_PADDING = 20; @@ -54,10 +54,10 @@ export function getParticipantResizeConstraints(laneShape, resizeDirection, bala minTrbl = {}; if (/e/.test(resizeDirection)) { - minTrbl.right = laneTrbl.left + LANE_MIN_WIDTH; + minTrbl.right = laneTrbl.left + LANE_MIN_DIMENSIONS.width; } else if (/w/.test(resizeDirection)) { - minTrbl.left = laneTrbl.right - LANE_MIN_WIDTH; + minTrbl.left = laneTrbl.right - LANE_MIN_DIMENSIONS.width; } allLanes.forEach(function(other) { @@ -72,12 +72,12 @@ export function getParticipantResizeConstraints(laneShape, resizeDirection, bala // max top size (based on next element) if (balanced && abs(laneTrbl.top - otherTrbl.bottom) < 10) { - addMax(maxTrbl, 'top', otherTrbl.top + LANE_MIN_HEIGHT); + addMax(maxTrbl, 'top', otherTrbl.top + LANE_MIN_DIMENSIONS.height); } // min top size (based on self or nested element) if (abs(laneTrbl.top - otherTrbl.top) < 5) { - addMin(minTrbl, 'top', otherTrbl.bottom - LANE_MIN_HEIGHT); + addMin(minTrbl, 'top', otherTrbl.bottom - LANE_MIN_DIMENSIONS.height); } } @@ -89,12 +89,12 @@ export function getParticipantResizeConstraints(laneShape, resizeDirection, bala // max bottom size (based on previous element) if (balanced && abs(laneTrbl.bottom - otherTrbl.top) < 10) { - addMin(maxTrbl, 'bottom', otherTrbl.bottom - LANE_MIN_HEIGHT); + addMin(maxTrbl, 'bottom', otherTrbl.bottom - LANE_MIN_DIMENSIONS.height); } // min bottom size (based on self or nested element) if (abs(laneTrbl.bottom - otherTrbl.bottom) < 5) { - addMax(minTrbl, 'bottom', otherTrbl.top + LANE_MIN_HEIGHT); + addMax(minTrbl, 'bottom', otherTrbl.top + LANE_MIN_DIMENSIONS.height); } } }); diff --git a/test/spec/features/modeling/behavior/SpaceToolBehaviorSpec.js b/test/spec/features/modeling/behavior/SpaceToolBehaviorSpec.js index 7dd9be19..459ed5d9 100644 --- a/test/spec/features/modeling/behavior/SpaceToolBehaviorSpec.js +++ b/test/spec/features/modeling/behavior/SpaceToolBehaviorSpec.js @@ -13,7 +13,11 @@ import { createCanvasEvent as canvasEvent } from '../../../../util/MockEvents'; -import { SUB_PROCESS_MIN_DIMENSIONS } from 'lib/features/modeling/behavior/ResizeBehavior'; +import { + LANE_MIN_DIMENSIONS, + PARTICIPANT_MIN_DIMENSIONS, + SUB_PROCESS_MIN_DIMENSIONS +} from 'lib/features/modeling/behavior/ResizeBehavior'; var testModules = [ coreModule, @@ -26,16 +30,16 @@ var testModules = [ describe('features/modeling - space tool behavior', function() { - describe('participant', function() { + describe('subprocess', function() { describe('minimum dimensions', function() { - var diagramXML = require('./SpaceToolBehaviorSpec.bpmn'); + var diagramXML = require('./SpaceToolBehaviorSpec.subprocess.bpmn'); beforeEach(bootstrapModeler(diagramXML, { modules: testModules })); - it('should ensure minimum dimensions', inject( + it('should ensure subprocess minimum dimensions', inject( function(dragging, elementRegistry, spaceTool) { // given @@ -57,4 +61,73 @@ describe('features/modeling - space tool behavior', function() { }); + describe('participant', function() { + + describe('minimum dimensions', function() { + + var diagramXML = require('./SpaceToolBehaviorSpec.participant.bpmn'); + + beforeEach(bootstrapModeler(diagramXML, { modules: testModules })); + + + it('should ensure participant minimum dimensions', inject( + function(dragging, elementRegistry, spaceTool) { + + // given + var participant = elementRegistry.get('Participant_1'); + + // when + spaceTool.activateMakeSpace(canvasEvent({ x: 300, y: 0 })); + + dragging.move(canvasEvent({ x: 0, y: 0 })); + + dragging.end(); + + // then + expect(participant.width).to.equal(PARTICIPANT_MIN_DIMENSIONS.width); + }) + ); + + + it('should ensure lane minimum dimensions', inject( + function(dragging, elementRegistry, spaceTool) { + + // given + var lane = elementRegistry.get('Lane_1'); + + // when + spaceTool.activateMakeSpace(canvasEvent({ x: 0, y: 400 })); + + dragging.move(canvasEvent({ x: 0, y: 0 })); + + dragging.end(); + + // then + expect(lane.height).to.equal(LANE_MIN_DIMENSIONS.height); + }) + ); + + + it('should ensure nested lane minimum dimensions', inject( + function(dragging, elementRegistry, spaceTool) { + + // given + var lane = elementRegistry.get('Lane_6'); + + // when + spaceTool.activateMakeSpace(canvasEvent({ x: 0, y: 925 })); + + dragging.move(canvasEvent({ x: 0, y: 0 })); + + dragging.end(); + + // then + expect(lane.height).to.equal(LANE_MIN_DIMENSIONS.height); + }) + ); + + }); + + }); + }); \ No newline at end of file diff --git a/test/spec/features/modeling/behavior/SpaceToolBehaviorSpec.participant.bpmn b/test/spec/features/modeling/behavior/SpaceToolBehaviorSpec.participant.bpmn new file mode 100644 index 00000000..a8ea2dc7 --- /dev/null +++ b/test/spec/features/modeling/behavior/SpaceToolBehaviorSpec.participant.bpmn @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/spec/features/modeling/behavior/SpaceToolBehaviorSpec.bpmn b/test/spec/features/modeling/behavior/SpaceToolBehaviorSpec.subprocess.bpmn similarity index 100% rename from test/spec/features/modeling/behavior/SpaceToolBehaviorSpec.bpmn rename to test/spec/features/modeling/behavior/SpaceToolBehaviorSpec.subprocess.bpmn