From 1d6d0e269838d0a041ad658419f261dba9477062 Mon Sep 17 00:00:00 2001 From: Jarek Danielak Date: Wed, 19 Feb 2025 10:24:03 +0100 Subject: [PATCH] fix: move text annotations when a participant is resized Related to https://github.com/camunda/camunda-modeler/issues/4172 --- lib/features/space-tool/BpmnSpaceTool.js | 46 +++++++- .../BpmnSpaceTool.participants.bpmn | 44 +++++++- .../features/space-tool/BpmnSpaceToolSpec.js | 100 +++++++++++++++++- 3 files changed, 187 insertions(+), 3 deletions(-) diff --git a/lib/features/space-tool/BpmnSpaceTool.js b/lib/features/space-tool/BpmnSpaceTool.js index 9512c8993f..fc5fdea74d 100644 --- a/lib/features/space-tool/BpmnSpaceTool.js +++ b/lib/features/space-tool/BpmnSpaceTool.js @@ -2,7 +2,9 @@ import inherits from 'inherits-browser'; import SpaceTool from 'diagram-js/lib/features/space-tool/SpaceTool'; -import { getBusinessObject, is } from '../../util/ModelUtil'; +import { getEnclosedElements, getBBox } from 'diagram-js/lib/util/Elements'; + +import { getBusinessObject, is, isAny } from '../../util/ModelUtil'; import { isHorizontal } from '../../util/DiUtil'; @@ -59,6 +61,33 @@ BpmnSpaceTool.prototype.calculateAdjustments = function(elements, axis, delta, s return true; }); + // Make sure elements positioned on the root (e.g. text annotations) + // are moved when the participant enclosing them is resized. + const shapesToMove = [ 'bpmn:TextAnnotation' ]; + + const participants = adjustments.resizingShapes.filter(shape => is(shape, 'bpmn:Participant')); + + const movingShapes = participants.reduce((movingShapes, participant) => { + + const rootChildren = participant.parent.children; + + const elementsToMove = rootChildren.filter(child => isAny(child, shapesToMove)); + + if (!elementsToMove.length) { + return movingShapes; + } + + const bbox = getBBox(participant); + + const enclosed = Object.values(getEnclosedElements(elementsToMove, bbox)); + + const shouldMove = enclosed.filter(el => shouldBeMoved(el, axis, delta, start)); + + return [ ...movingShapes, ...shouldMove ]; + }, []); + + adjustments.movingShapes = [ ...adjustments.movingShapes, ...movingShapes ]; + return adjustments; }; @@ -67,4 +96,19 @@ BpmnSpaceTool.prototype.calculateAdjustments = function(elements, axis, delta, s function isCollapsedPool(shape) { return is(shape, 'bpmn:Participant') && !getBusinessObject(shape).processRef; +} + +// True if element is in range of the space tool +// Based on the internal logic of SpaceTool#calculateAdjustments +// TODO(@jarekdanielak): Make it available as an internal function of SpaceTool +function shouldBeMoved(element, axis, delta, start) { + + const shapeStart = axis === 'x' ? element.x : element.y; + const shapeEnd = axis === 'x' ? element.x + element.width : element.y + element.height; + + if ((delta > 0 && shapeStart > start) || (delta < 0 && shapeEnd < start)) { + return true; + } + + return false; } \ No newline at end of file diff --git a/test/spec/features/space-tool/BpmnSpaceTool.participants.bpmn b/test/spec/features/space-tool/BpmnSpaceTool.participants.bpmn index 8ef0f497ca..5dd9390f13 100644 --- a/test/spec/features/space-tool/BpmnSpaceTool.participants.bpmn +++ b/test/spec/features/space-tool/BpmnSpaceTool.participants.bpmn @@ -1,10 +1,25 @@ - + + + + text 1 + + + text 2 + + + text 3 + + + + + + @@ -15,6 +30,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/spec/features/space-tool/BpmnSpaceToolSpec.js b/test/spec/features/space-tool/BpmnSpaceToolSpec.js index a3edcacbf2..9102ddd38a 100644 --- a/test/spec/features/space-tool/BpmnSpaceToolSpec.js +++ b/test/spec/features/space-tool/BpmnSpaceToolSpec.js @@ -551,6 +551,102 @@ describe('features/space-tool - BpmnSpaceTool', function() { }); })); + + it('should move text annotations in a participant', inject(function(dragging, elementRegistry, spaceTool) { + + // given + var textAnnotation = elementRegistry.get('TextAnnotation_1'); + var textAnnotationX = textAnnotation.x; + + var task = elementRegistry.get('Activity_1'); + var taskMid = getMid(task); + var rightOfTask = task.x + task.width + 10; + + // when + var element = elementRegistry.get('Participant_3'); + var gfx = elementRegistry.getGraphics(element); + var hover = { element, gfx }; + + makeSpace({ x: rightOfTask, y: taskMid.y }, { dx: 100 }, false, hover); + + // then + expect(textAnnotation.x).to.equal(textAnnotationX + 100); + })); + + + it('should only move text annotations in space tool range', inject(function(dragging, elementRegistry, spaceTool) { + + // given + var textAnnotationToMove = elementRegistry.get('TextAnnotation_1'); + var textAnnotationToMove_X = textAnnotationToMove.x; + + var textAnnotationToStay = elementRegistry.get('TextAnnotation_3'); + var textAnnotationToStay_X = textAnnotationToStay.x; + + var task = elementRegistry.get('Activity_1'); + var taskMid = getMid(task); + var rightOfTask = task.x + task.width + 10; + + // when + var element = elementRegistry.get('Participant_3'); + var gfx = elementRegistry.getGraphics(element); + var hover = { element, gfx }; + + makeSpace({ x: rightOfTask, y: taskMid.y }, { dx: 100 }, false, hover); + + // then + expect(textAnnotationToMove.x).to.equal(textAnnotationToMove_X + 100); + expect(textAnnotationToStay.x).to.equal(textAnnotationToStay_X); + })); + + + it('should only move text annotations in space tool range (inverted)', inject(function(dragging, elementRegistry, spaceTool) { + + // given + var textAnnotationToMove = elementRegistry.get('TextAnnotation_3'); + var textAnnotationToMove_X = textAnnotationToMove.x; + + var textAnnotationToStay = elementRegistry.get('TextAnnotation_1'); + var textAnnotationToStay_X = textAnnotationToStay.x; + + var task = elementRegistry.get('Activity_1'); + var taskMid = getMid(task); + var rightOfTask = task.x + task.width + 10; + + // when + var element = elementRegistry.get('Participant_3'); + var gfx = elementRegistry.getGraphics(element); + var hover = { element, gfx }; + + makeSpace({ x: rightOfTask, y: taskMid.y }, { dx: -100 }, true, hover); + + // then + expect(textAnnotationToMove.x).to.equal(textAnnotationToMove_X - 100); + expect(textAnnotationToStay.x).to.equal(textAnnotationToStay_X); + })); + + + it('should not move text annotations outside of participant', inject(function(dragging, elementRegistry, spaceTool) { + + // given + var textAnnotation = elementRegistry.get('TextAnnotation_2'); + var textAnnotationX = textAnnotation.x; + + var task = elementRegistry.get('Activity_1'); + var taskMid = getMid(task); + var rightOfTask = task.x + task.width + 10; + + // when + var element = elementRegistry.get('Participant_3'); + var gfx = elementRegistry.getGraphics(element); + var hover = { element, gfx }; + + makeSpace({ x: rightOfTask, y: taskMid.y }, { dx: 100 }, false, hover); + + // then + expect(textAnnotation.x).to.equal(textAnnotationX); + })); + }); }); @@ -558,7 +654,7 @@ describe('features/space-tool - BpmnSpaceTool', function() { // helpers ////////// -function makeSpace(start, delta, invert) { +function makeSpace(start, delta, invert, hover) { var modifier = invert ? invertModifier : {}; var end = { @@ -569,6 +665,8 @@ function makeSpace(start, delta, invert) { return getBpmnJS().invoke(function(spaceTool, dragging) { spaceTool.activateMakeSpace(canvasEvent(start)); + hover && dragging.hover(hover); + dragging.move(canvasEvent(end, modifier)); dragging.end();