feat: add alignment and distribution menu multi-element context pad

Closes #1680
Closes #1691
This commit is contained in:
Maciej Barelkowski
2022-06-10 08:54:57 +02:00
committed by fake-join[bot]
parent 51aa2cd575
commit befe8b82c8
28 changed files with 1010 additions and 133 deletions

View File

@ -8,7 +8,7 @@
--color-grey-225-10-80: hsl(225, 10%, 80%);
--color-grey-225-10-85: hsl(225, 10%, 85%);
--color-grey-225-10-90: hsl(225, 10%, 90%);
--color-grey-225-10-95: hsl(225, 10%, 95%);
--color-grey-225-10-95: hsl(225, 10%, 95%);
--color-grey-225-10-97: hsl(225, 10%, 97%);
--color-blue-205-100-45: hsl(205, 100%, 45%);
@ -24,8 +24,8 @@
--color-red-360-100-97: hsl(360, 100%, 97%);
--color-white: hsl(0, 0%, 100%);
--color-black: hsl(0, 0%, 0%);
--color-black-opacity-05: hsla(0, 0%, 0%, 5%);
--color-black: hsl(0, 0%, 0%);
--color-black-opacity-05: hsla(0, 0%, 0%, 5%);
--color-black-opacity-10: hsla(0, 0%, 0%, 10%);
--breadcrumbs-font-family: var(--bjs-font-family);
@ -113,4 +113,33 @@
.selected .bjs-drilldown-empty {
display: inherit;
}
}
[data-popup="align-elements"] .djs-popup-body {
display: flex;
}
[data-popup="align-elements"] .djs-popup-body [data-group] + [data-group] {
border-left: 1px solid var(--popup-border-color);
}
[data-popup="align-elements"] [data-group="align"] {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
[data-popup="align-elements"] .djs-popup-body .entry {
height: 20px;
width: 20px;
padding: 6px 8px;
}
[data-popup="align-elements"] .djs-popup-body .entry img {
height: 100%;
width: 100%;
}
[data-popup="align-elements"] .bjs-align-elements-menu-entry {
display: inline-block;
}

View File

@ -10,7 +10,7 @@ import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas';
import TouchModule from 'diagram-js/lib/navigation/touch';
import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll';
import AlignElementsModule from 'diagram-js/lib/features/align-elements';
import AlignElementsModule from './features/align-elements';
import AutoPlaceModule from './features/auto-place';
import AutoResizeModule from './features/auto-resize';
import AutoScrollModule from 'diagram-js/lib/features/auto-scroll';

View File

@ -0,0 +1,87 @@
import {
assign
} from 'min-dash';
import ICONS from './AlignElementsIcons';
var LOW_PRIORITY = 900;
/**
* A provider for align elements context pad button
*/
export default function AlignElementsContextPadProvider(contextPad, popupMenu, translate, canvas) {
contextPad.registerProvider(LOW_PRIORITY, this);
this._contextPad = contextPad;
this._popupMenu = popupMenu;
this._translate = translate;
this._canvas = canvas;
}
AlignElementsContextPadProvider.$inject = [
'contextPad',
'popupMenu',
'translate',
'canvas'
];
AlignElementsContextPadProvider.prototype.getMultiElementContextPadEntries = function(elements) {
var actions = {};
if (this._isAllowed(elements)) {
assign(actions, this._getEntries(elements));
}
return actions;
};
AlignElementsContextPadProvider.prototype._isAllowed = function(elements) {
return !this._popupMenu.isEmpty(elements, 'align-elements');
};
AlignElementsContextPadProvider.prototype._getEntries = function(elements) {
var self = this;
return {
'align-elements': {
group: 'align-elements',
title: self._translate('Align elements'),
imageUrl: ICONS['align'],
action: {
click: function(event, elements) {
var position = self._getMenuPosition(elements);
assign(position, {
cursor: {
x: event.x,
y: event.y
}
});
self._popupMenu.open(elements, 'align-elements', position);
}
}
}
};
};
AlignElementsContextPadProvider.prototype._getMenuPosition = function(elements) {
var Y_OFFSET = 5;
var diagramContainer = this._canvas.getContainer(),
pad = this._contextPad.getPad(elements).html;
var diagramRect = diagramContainer.getBoundingClientRect(),
padRect = pad.getBoundingClientRect();
var top = padRect.top - diagramRect.top;
var left = padRect.left - diagramRect.left;
var pos = {
x: left,
y: top + padRect.height + Y_OFFSET
};
return pos;
};

View File

@ -0,0 +1,15 @@
/**
* To change the icons, modify the SVGs in `./resources`, execute `npx svgo -f resources --datauri enc -o dist`,
* and then replace respective icons with the optimized data URIs in `./dist`.
*/
var icons = {
align: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%202000%202000%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M200%20150v1700%22%2F%3E%3Crect%20x%3D%22500%22%20y%3D%22150%22%20width%3D%221300%22%20height%3D%22700%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22500%22%20y%3D%221150%22%20width%3D%22700%22%20height%3D%22700%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
bottom: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M150%201650h1500%22%2F%3E%3Crect%20x%3D%22150%22%20y%3D%22350%22%20width%3D%22600%22%20height%3D%221300%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%221050%22%20y%3D%22850%22%20width%3D%22600%22%20height%3D%22800%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
center: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M900%20150v1500%22%2F%3E%3Crect%20x%3D%22250%22%20y%3D%22150%22%20width%3D%221300%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22500%22%20y%3D%221050%22%20width%3D%22800%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
left: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M100%20150v1500%22%2F%3E%3Crect%20x%3D%22100%22%20y%3D%22150%22%20width%3D%221300%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22100%22%20y%3D%221050%22%20width%3D%22800%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
right: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M1650%20150v1500%22%2F%3E%3Crect%20x%3D%22350%22%20y%3D%22150%22%20width%3D%221300%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22850%22%20y%3D%221050%22%20width%3D%22800%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
top: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M150%20150h1500%22%2F%3E%3Crect%20x%3D%22150%22%20y%3D%22150%22%20width%3D%22600%22%20height%3D%221300%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%221050%22%20y%3D%22150%22%20width%3D%22600%22%20height%3D%22800%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
middle: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M150%20900h1500%22%2F%3E%3Crect%20x%3D%22150%22%20y%3D%22250%22%20width%3D%22600%22%20height%3D%221300%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%221050%22%20y%3D%22500%22%20width%3D%22600%22%20height%3D%22800%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E'
};
export default icons;

View File

@ -0,0 +1,72 @@
import ICONS from './AlignElementsIcons';
import {
assign,
forEach,
} from 'min-dash';
var ALIGNMENT_OPTIONS = [
'left',
'center',
'right',
'top',
'middle',
'bottom'
];
/**
* A provider for align elements popup menu.
*/
export default function AlignElementsMenuProvider(popupMenu, alignElements, translate, rules) {
this._alignElements = alignElements;
this._translate = translate;
this._popupMenu = popupMenu;
this._rules = rules;
popupMenu.registerProvider('align-elements', this);
}
AlignElementsMenuProvider.$inject = [
'popupMenu',
'alignElements',
'translate',
'rules'
];
AlignElementsMenuProvider.prototype.getPopupMenuEntries = function(elements) {
var entries = {};
if (this._isAllowed(elements)) {
assign(entries, this._getEntries(elements));
}
return entries;
};
AlignElementsMenuProvider.prototype._isAllowed = function(elements) {
return this._rules.allowed('elements.align', { elements: elements });
};
AlignElementsMenuProvider.prototype._getEntries = function(elements) {
var alignElements = this._alignElements,
translate = this._translate,
popupMenu = this._popupMenu;
var entries = {};
forEach(ALIGNMENT_OPTIONS, function(alignment) {
entries[ 'align-elements-' + alignment ] = {
group: 'align',
title: translate('Align elements ' + alignment),
className: 'bjs-align-elements-menu-entry',
imageUrl: ICONS[alignment],
action: function(event, entry) {
alignElements.trigger(elements, alignment);
popupMenu.close();
}
};
});
return entries;
};

View File

@ -0,0 +1,39 @@
import inherits from 'inherits-browser';
import RuleProvider from 'diagram-js/lib/features/rules/RuleProvider';
import { getParents } from 'diagram-js/lib/util/Elements';
import {
filter
} from 'min-dash';
/**
* Rule provider for alignment of BPMN elements.
*/
export default function BpmnAlignElements(eventBus) {
RuleProvider.call(this, eventBus);
}
BpmnAlignElements.$inject = [ 'eventBus' ];
inherits(BpmnAlignElements, RuleProvider);
BpmnAlignElements.prototype.init = function() {
this.addRule('elements.align', function(context) {
var elements = context.elements;
// filter out elements which cannot be aligned
var filteredElements = filter(elements, function(element) {
return !(element.waypoints || element.host || element.labelTarget);
});
// filter out elements which are children of any of the selected elements
filteredElements = getParents(filteredElements);
if (filteredElements.length < 2) {
return false;
}
return filteredElements;
});
};

View File

@ -0,0 +1,23 @@
import AlignElementsModule from 'diagram-js/lib/features/align-elements';
import ContextPadModule from 'diagram-js/lib/features/context-pad';
import PopupMenuModule from 'diagram-js/lib/features/popup-menu';
import AlignElementsContextPadProvider from './AlignElementsContextPadProvider';
import AlignElementsMenuProvider from './AlignElementsMenuProvider';
import BpmnAlignElements from './BpmnAlignElements';
export default {
__depends__: [
AlignElementsModule,
ContextPadModule,
PopupMenuModule
],
__init__: [
'alignElementsContextPadProvider',
'alignElementsMenuProvider',
'bpmnAlignElements'
],
alignElementsContextPadProvider: [ 'type', AlignElementsContextPadProvider ],
alignElementsMenuProvider: [ 'type', AlignElementsMenuProvider ],
bpmnAlignElements: [ 'type', BpmnAlignElements]
};

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
<line x1="150" y1="1650" x2="1650" y2="1650" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
<rect x="150" y="350" width="600" height="1300" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
<rect x="1050" y="850" width="600" height="800" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
</svg>

After

Width:  |  Height:  |  Size: 448 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
<line x1="900" y1="150" x2="900" y2="1650" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
<rect x="250" y="150" width="1300" height="600" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
<rect x="500" y="1050" width="800" height="600" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
</svg>

After

Width:  |  Height:  |  Size: 446 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
<line x1="100" y1="150" x2="100" y2="1650" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
<rect x="100" y="150" width="1300" height="600" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
<rect x="100" y="1050" width="800" height="600" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
</svg>

After

Width:  |  Height:  |  Size: 446 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
<line x1="1650" y1="150" x2="1650" y2="1650" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
<rect x="350" y="150" width="1300" height="600" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
<rect x="850" y="1050" width="800" height="600" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
</svg>

After

Width:  |  Height:  |  Size: 448 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000">
<line x1="200" y1="150" x2="200" y2="1850" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
<rect x="500" y="150" width="1300" height="700" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
<rect x="500" y="1150" width="700" height="700" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
</svg>

After

Width:  |  Height:  |  Size: 446 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
<line x1="150" y1="150" x2="1650" y2="150" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
<rect x="150" y="150" width="600" height="1300" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
<rect x="1050" y="150" width="600" height="800" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
</svg>

After

Width:  |  Height:  |  Size: 446 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
<line x1="150" y1="900" x2="1650" y2="900" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
<rect x="150" y="250" width="600" height="1300" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
<rect x="1050" y="500" width="600" height="800" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
</svg>

After

Width:  |  Height:  |  Size: 446 B

View File

@ -1,3 +1,8 @@
import inherits from 'inherits-browser';
import RuleProvider from 'diagram-js/lib/features/rules/RuleProvider';
import { getParents } from 'diagram-js/lib/util/Elements';
import {
filter
} from 'min-dash';
@ -11,10 +16,19 @@ import {
* Registers element exclude filters for elements that
* currently do not support distribution.
*/
export default function BpmnDistributeElements(distributeElements) {
export default function BpmnDistributeElements(distributeElements, eventBus, rules) {
RuleProvider.call(this, eventBus);
}
distributeElements.registerFilter(function(elements) {
return filter(elements, function(element) {
BpmnDistributeElements.$inject = [ 'distributeElements', 'eventBus', 'rules' ];
inherits(BpmnDistributeElements, RuleProvider);
BpmnDistributeElements.prototype.init = function() {
this.addRule('elements.distribute', function(context) {
var elements = context.elements;
elements = filter(elements, function(element) {
var cannotDistribute = isAny(element, [
'bpmn:Association',
'bpmn:BoundaryEvent',
@ -22,14 +36,20 @@ export default function BpmnDistributeElements(distributeElements) {
'bpmn:DataOutputAssociation',
'bpmn:Lane',
'bpmn:MessageFlow',
'bpmn:Participant',
'bpmn:SequenceFlow',
'bpmn:TextAnnotation'
]);
return !(element.labelTarget || cannotDistribute);
});
});
}
BpmnDistributeElements.$inject = [ 'distributeElements' ];
// filter out elements which are children of any of the selected elements
elements = getParents(elements);
if (elements.length < 3) {
return false;
}
return elements;
});
};

View File

@ -0,0 +1,10 @@
/**
* To change the icons, modify the SVGs in `./resources`, execute `npx svgo -f resources --datauri enc -o dist`,
* and then replace respective icons with the optimized data URIs in `./dist`.
*/
var icons = {
horizontal: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linejoin%3Around%22%20d%3D%22M450%20400V150h900v250%22%2F%3E%3Crect%20x%3D%22150%22%20y%3D%22450%22%20width%3D%22600%22%20height%3D%221200%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%221050%22%20y%3D%22450%22%20width%3D%22600%22%20height%3D%22800%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
vertical: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linejoin%3Around%22%20d%3D%22M400%201350H150V450h250%22%2F%3E%3Crect%20x%3D%22450%22%20y%3D%22150%22%20width%3D%221200%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22450%22%20y%3D%221050%22%20width%3D%22800%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
};
export default icons;

View File

@ -0,0 +1,69 @@
import ICONS from './DistributeElementsIcons';
import { assign } from 'min-dash';
var LOW_PRIORITY = 900;
/**
* A provider for distribute elements popup menu.
*/
export default function DistributeElementsMenuProvider(
popupMenu, distributeElements, translate, rules) {
this._distributeElements = distributeElements;
this._translate = translate;
this._popupMenu = popupMenu;
this._rules = rules;
popupMenu.registerProvider('align-elements', LOW_PRIORITY, this);
}
DistributeElementsMenuProvider.$inject = [
'popupMenu',
'distributeElements',
'translate',
'rules'
];
DistributeElementsMenuProvider.prototype.getPopupMenuEntries = function(elements) {
var entries = {};
if (this._isAllowed(elements)) {
assign(entries, this._getEntries(elements));
}
return entries;
};
DistributeElementsMenuProvider.prototype._isAllowed = function(elements) {
return this._rules.allowed('elements.distribute', { elements: elements });
};
DistributeElementsMenuProvider.prototype._getEntries = function(elements) {
var distributeElements = this._distributeElements,
translate = this._translate,
popupMenu = this._popupMenu;
var entries = {
'distribute-elements-horizontal': {
group: 'distribute',
title: translate('Distribute elements horizontally'),
className: 'bjs-align-elements-menu-entry',
imageUrl: ICONS['horizontal'],
action: function(event, entry) {
distributeElements.trigger(elements, 'horizontal');
popupMenu.close();
}
},
'distribute-elements-vertical': {
group: 'distribute',
title: translate('Distribute elements vertically'),
imageUrl: ICONS['vertical'],
action: function(event, entry) {
distributeElements.trigger(elements, 'vertical');
popupMenu.close();
}
},
};
return entries;
};

View File

@ -1,12 +1,19 @@
import DistributeElementsModule from 'diagram-js/lib/features/distribute-elements';
import PopupMenuModule from 'diagram-js/lib/features/popup-menu';
import BpmnDistributeElements from './BpmnDistributeElements';
import DistributeElementsMenuProvider from './DistributeElementsMenuProvider';
export default {
__depends__: [
PopupMenuModule,
DistributeElementsModule
],
__init__: [ 'bpmnDistributeElements' ],
bpmnDistributeElements: [ 'type', BpmnDistributeElements ]
__init__: [
'bpmnDistributeElements',
'distributeElementsMenuProvider'
],
bpmnDistributeElements: [ 'type', BpmnDistributeElements ],
distributeElementsMenuProvider: [ 'type', DistributeElementsMenuProvider ]
};

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
<polyline points="450 400 450 150 1350 150 1350 400" style="fill:none;stroke:currentColor;stroke-width:100;stroke-linejoin:round;"/>
<rect x="150" y="450" width="600" height="1200" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
<rect x="1050" y="450" width="600" height="800" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
</svg>

After

Width:  |  Height:  |  Size: 467 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
<polyline points="400 1350 150 1350 150 450 400 450" style="fill:none;stroke:currentColor;stroke-width:100;stroke-linejoin:round;"/>
<rect x="450" y="150" width="1200" height="600" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
<rect x="450" y="1050" width="800" height="600" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
</svg>

After

Width:  |  Height:  |  Size: 467 B

View File

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<semantic:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:semantic="http://www.omg.org/spec/BPMN/20100524/MODEL" id="_1275940932088" targetNamespace="http://www.trisotech.com/definitions/_1275940932088" exporter="Camunda Modeler" exporterVersion="1.2.0-dev">
<semantic:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:semantic="http://www.omg.org/spec/BPMN/20100524/MODEL" id="_1275940932088" targetNamespace="http://www.trisotech.com/definitions/_1275940932088" exporter="Camunda Modeler" exporterVersion="5.0.0">
<semantic:message id="_1275940932310" />
<semantic:message id="_1275940932433" />
<semantic:message id="_1275940932198" />
<semantic:process id="_6-2" isExecutable="false">
<semantic:sequenceFlow id="SequenceFlow_08zyuyv" name="hello" sourceRef="Task_boundary_evt" targetRef="Task_hello" />
<semantic:boundaryEvent id="BoundaryEvent_0n2gx06" attachedToRef="Task_boundary_evt" />
<semantic:task id="Task_hello" name="hello">
<semantic:incoming>SequenceFlow_08zyuyv</semantic:incoming>
</semantic:task>
<semantic:task id="Task_boundary_evt">
<semantic:outgoing>SequenceFlow_08zyuyv</semantic:outgoing>
</semantic:task>
<semantic:boundaryEvent id="BoundaryEvent_1" attachedToRef="Task_boundary_evt" />
<semantic:sequenceFlow id="SequenceFlow_08zyuyv" name="hello" sourceRef="Task_boundary_evt" targetRef="Task_hello" />
</semantic:process>
<semantic:collaboration id="C1275940932557">
<semantic:participant id="_6-53" name="" processRef="_6-2" />
@ -21,14 +21,14 @@
</semantic:collaboration>
<semantic:process id="_6-1" isExecutable="false">
<semantic:laneSet id="ls_6-438">
<semantic:lane id="_6-650" name="">
<semantic:flowNodeRef>Task_lane</semantic:flowNodeRef>
<semantic:lane id="_6-448" name="">
<semantic:flowNodeRef>EndEvent_lane</semantic:flowNodeRef>
</semantic:lane>
<semantic:lane id="_6-446" name="">
<semantic:flowNodeRef>SubProcess_lane</semantic:flowNodeRef>
</semantic:lane>
<semantic:lane id="_6-448" name="">
<semantic:flowNodeRef>EndEvent_lane</semantic:flowNodeRef>
<semantic:lane id="_6-650" name="">
<semantic:flowNodeRef>Task_lane</semantic:flowNodeRef>
</semantic:lane>
</semantic:laneSet>
<semantic:task id="Task_lane">
@ -41,92 +41,92 @@
<semantic:incoming>SequenceFlow_1nrce3c</semantic:incoming>
<semantic:outgoing>SequenceFlow_0qa7db7</semantic:outgoing>
</semantic:subProcess>
<semantic:sequenceFlow id="SequenceFlow_1nrce3c" sourceRef="Task_lane" targetRef="SubProcess_lane" />
<semantic:sequenceFlow id="SequenceFlow_0qa7db7" sourceRef="SubProcess_lane" targetRef="EndEvent_lane" />
<semantic:sequenceFlow id="SequenceFlow_1nrce3c" sourceRef="Task_lane" targetRef="SubProcess_lane" />
</semantic:process>
<bpmndi:BPMNDiagram id="Trisotech.Visio-_6" name="Untitled Diagram" documentation="" resolution="96.00000267028808">
<bpmndi:BPMNPlane bpmnElement="C1275940932557">
<bpmndi:BPMNShape id="Trisotech.Visio__6-53" bpmnElement="_6-53" isHorizontal="true">
<dc:Bounds x="12" y="12" width="1044" height="294" />
<dc:Bounds x="152" y="82" width="1044" height="294" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_08zyuyv_di" bpmnElement="SequenceFlow_08zyuyv">
<di:waypoint x="435" y="186" />
<di:waypoint x="533" y="186" />
<di:waypoint x="533" y="217" />
<bpmndi:BPMNLabel>
<dc:Bounds x="471" y="160" width="24" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Task_0s45gnz_di" bpmnElement="Task_hello">
<dc:Bounds x="483" y="217" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_07vyznk_di" bpmnElement="Task_boundary_evt">
<dc:Bounds x="335" y="146" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BoundaryEvent_0n2gx06_di" bpmnElement="BoundaryEvent_1">
<dc:Bounds x="336" y="208" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="169.036" y="173.79" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Trisotech.Visio__6-438" bpmnElement="_6-438" isHorizontal="true">
<dc:Bounds x="68" y="358" width="825" height="539" />
<dc:Bounds x="208" y="428" width="825" height="539" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Trisotech.Visio__6__6-448" bpmnElement="_6-448" isHorizontal="true">
<dc:Bounds x="98" y="712" width="795" height="185" />
<dc:Bounds x="238" y="782" width="795" height="185" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Trisotech.Visio__6__6-446" bpmnElement="_6-446" isHorizontal="true">
<dc:Bounds x="98" y="472" width="795" height="240" />
<dc:Bounds x="238" y="542" width="795" height="240" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Trisotech.Visio__6__6-650" bpmnElement="_6-650" isHorizontal="true">
<dc:Bounds x="98" y="358" width="795" height="114" />
<dc:Bounds x="238" y="428" width="795" height="114" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_0qh67cn_di" bpmnElement="Task_lane">
<dc:Bounds x="136" y="375" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_0qa7db7_di" bpmnElement="SequenceFlow_0qa7db7">
<di:waypoint x="629" y="766" />
<di:waypoint x="629" y="893" />
<di:waypoint x="924" y="893" />
<bpmndi:BPMNLabel>
<dc:Bounds x="470.5" y="618.5" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="SequenceFlow_1nrce3c_di" bpmnElement="SequenceFlow_1nrce3c">
<di:waypoint xsi:type="dc:Point" x="236" y="415" />
<di:waypoint xsi:type="dc:Point" x="275" y="415" />
<di:waypoint xsi:type="dc:Point" x="275" y="596" />
<di:waypoint xsi:type="dc:Point" x="314" y="596" />
<di:waypoint x="376" y="485" />
<di:waypoint x="415" y="485" />
<di:waypoint x="415" y="666" />
<di:waypoint x="454" y="666" />
<bpmndi:BPMNLabel>
<dc:Bounds x="242" y="468" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Task_0qh67cn_di" bpmnElement="Task_lane">
<dc:Bounds x="276" y="445" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="EndEvent_1jdsxxr_di" bpmnElement="EndEvent_lane">
<dc:Bounds x="784" y="805" width="36" height="36" />
<dc:Bounds x="924" y="875" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="757" y="841" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="SubProcess_06gy2ot_di" bpmnElement="SubProcess_lane" isExpanded="true">
<dc:Bounds x="314" y="496" width="350" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_0qa7db7_di" bpmnElement="SequenceFlow_0qa7db7">
<di:waypoint xsi:type="dc:Point" x="489" y="696" />
<di:waypoint xsi:type="dc:Point" x="489" y="823" />
<di:waypoint xsi:type="dc:Point" x="784" y="823" />
<bpmndi:BPMNLabel>
<dc:Bounds x="470.5" y="618.5" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Task_07vyznk_di" bpmnElement="Task_boundary_evt">
<dc:Bounds x="195.036" y="75.78999999999999" width="100" height="80" />
<dc:Bounds x="454" y="566" width="350" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="MessageFlow_1pvlume_di" bpmnElement="MessageFlow_1pvlume">
<di:waypoint xsi:type="dc:Point" x="245" y="156" />
<di:waypoint xsi:type="dc:Point" x="245" y="262" />
<di:waypoint xsi:type="dc:Point" x="184" y="262" />
<di:waypoint xsi:type="dc:Point" x="184" y="375" />
<di:waypoint x="385" y="226" />
<di:waypoint x="385" y="332" />
<di:waypoint x="324" y="332" />
<di:waypoint x="324" y="445" />
<bpmndi:BPMNLabel>
<dc:Bounds x="98" y="254.5" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="BoundaryEvent_0n2gx06_di" bpmnElement="BoundaryEvent_0n2gx06">
<dc:Bounds x="196.036" y="137.79" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="169.036" y="173.79" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_0s45gnz_di" bpmnElement="Task_hello">
<dc:Bounds x="343.036" y="146.79" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_08zyuyv_di" bpmnElement="SequenceFlow_08zyuyv">
<di:waypoint xsi:type="dc:Point" x="295" y="116" />
<di:waypoint xsi:type="dc:Point" x="393" y="116" />
<di:waypoint xsi:type="dc:Point" x="393" y="147" />
<bpmndi:BPMNLabel>
<dc:Bounds x="298" y="89.5" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="MessageFlow_1omk2ha_di" bpmnElement="MessageFlow_1omk2ha">
<di:waypoint xsi:type="dc:Point" x="393" y="227" />
<di:waypoint xsi:type="dc:Point" x="393" y="496" />
<di:waypoint x="533" y="297" />
<di:waypoint x="533" y="566" />
<bpmndi:BPMNLabel>
<dc:Bounds x="386" y="349" width="90" height="20" />
</bpmndi:BPMNLabel>

View File

@ -1,5 +1,5 @@
<?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:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.2.2">
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.0.0">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>SequenceFlow_0vrvkcp</bpmn:outgoing>
@ -15,44 +15,53 @@
<bpmn:incoming>SequenceFlow_1jet52k</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="SequenceFlow_1jet52k" sourceRef="BoundaryEvent_1" targetRef="EndEvent_1" />
<bpmn:subProcess id="SubProcess">
<bpmn:startEvent id="SubProcessChild" />
</bpmn:subProcess>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNEdge id="SequenceFlow_1jet52k_di" bpmnElement="SequenceFlow_1jet52k">
<di:waypoint x="378" y="119" />
<di:waypoint x="601" y="119" />
<bpmndi:BPMNLabel>
<dc:Bounds x="324.5" y="94" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="SequenceFlow_0vrvkcp_di" bpmnElement="SequenceFlow_0vrvkcp">
<di:waypoint x="193" y="79" />
<di:waypoint x="260" y="79" />
<bpmndi:BPMNLabel>
<dc:Bounds x="61.5" y="54" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="37" y="61" width="36" height="36" />
<dc:Bounds x="157" y="61" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="10" y="97" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_1qacn6w_di" bpmnElement="Task_1">
<dc:Bounds x="140" y="39" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_0vrvkcp_di" bpmnElement="SequenceFlow_0vrvkcp">
<di:waypoint xsi:type="dc:Point" x="73" y="79" />
<di:waypoint xsi:type="dc:Point" x="140" y="79" />
<bpmndi:BPMNLabel>
<dc:Bounds x="61.5" y="54" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="BoundaryEvent_10ce33p_di" bpmnElement="BoundaryEvent_1">
<dc:Bounds x="222" y="101" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="195" y="137" width="90" height="20" />
</bpmndi:BPMNLabel>
<dc:Bounds x="260" y="39" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="EndEvent_0lfg1uu_di" bpmnElement="EndEvent_1">
<dc:Bounds x="481" y="101" width="36" height="36" />
<dc:Bounds x="601" y="101" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="454" y="137" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_1jet52k_di" bpmnElement="SequenceFlow_1jet52k">
<di:waypoint xsi:type="dc:Point" x="258" y="119" />
<di:waypoint xsi:type="dc:Point" x="481" y="119" />
<bpmndi:BPMNShape id="Activity_1kbeku9_di" bpmnElement="SubProcess" isExpanded="true">
<dc:Bounds x="610" y="200" width="350" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0h7npxb_di" bpmnElement="SubProcessChild">
<dc:Bounds x="650" y="282" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BoundaryEvent_10ce33p_di" bpmnElement="BoundaryEvent_1">
<dc:Bounds x="342" y="101" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="324.5" y="94" width="90" height="20" />
<dc:Bounds x="195" y="137" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,50 @@
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.0.0">
<bpmn:collaboration id="Collaboration_1wywxe9">
<bpmn:participant id="Participant_1o654rf" processRef="Process_1" />
<bpmn:participant id="Participant_0lc2m2k" processRef="Process_0bbetmh" />
<bpmn:participant id="Participant_0cnn1z4" processRef="Process_14ju0cc" />
</bpmn:collaboration>
<bpmn:process id="Process_1" isExecutable="false" />
<bpmn:process id="Process_0bbetmh" isExecutable="false">
<bpmn:laneSet id="LaneSet_0ahmhbw">
<bpmn:lane id="Lane_0i9fng7" />
<bpmn:lane id="Lane_1yxptwb" />
<bpmn:lane id="Lane_03o4rm2" />
</bpmn:laneSet>
</bpmn:process>
<bpmn:process id="Process_14ju0cc" isExecutable="false">
<bpmn:laneSet id="LaneSet_0jckrsk">
<bpmn:lane id="Lane_1jivykj" />
<bpmn:lane id="Lane_04b9l7u" />
</bpmn:laneSet>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1wywxe9">
<bpmndi:BPMNShape id="Participant_1o654rf_di" bpmnElement="Participant_1o654rf" isHorizontal="true">
<dc:Bounds x="160" y="80" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_0lc2m2k_di" bpmnElement="Participant_0lc2m2k" isHorizontal="true">
<dc:Bounds x="160" y="490" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_0i9fng7_di" bpmnElement="Lane_0i9fng7" isHorizontal="true">
<dc:Bounds x="190" y="490" width="570" height="83" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_1yxptwb_di" bpmnElement="Lane_1yxptwb" isHorizontal="true">
<dc:Bounds x="190" y="573" width="570" height="83" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_03o4rm2_di" bpmnElement="Lane_03o4rm2" isHorizontal="true">
<dc:Bounds x="190" y="656" width="570" height="84" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_0cnn1z4_di" bpmnElement="Participant_0cnn1z4" isHorizontal="true">
<dc:Bounds x="160" y="780" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_1jivykj_di" bpmnElement="Lane_1jivykj" isHorizontal="true">
<dc:Bounds x="190" y="780" width="570" height="125" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_04b9l7u_di" bpmnElement="Lane_04b9l7u" isHorizontal="true">
<dc:Bounds x="190" y="905" width="570" height="125" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,100 @@
import {
bootstrapModeler,
getBpmnJS,
inject
} from 'test/TestHelper';
import {
query as domQuery
} from 'min-dom';
import alignElementsModule from 'lib/features/align-elements';
import modelingModule from 'lib/features/modeling';
import coreModule from 'lib/core';
describe('features/align-elements - context pad', function() {
var testModules = [ alignElementsModule, modelingModule, coreModule ];
var basicXML = require('../../../fixtures/bpmn/align-elements.bpmn');
beforeEach(bootstrapModeler(basicXML, { modules: testModules }));
it('should provide button to open menu', inject(function(elementRegistry, contextPad) {
// given
var elements = [
elementRegistry.get('EndEvent_lane'),
elementRegistry.get('Task_lane'),
elementRegistry.get('SubProcess_lane')
];
// when
contextPad.open(elements);
// then
expect(getEntry(elements, 'align-elements')).to.exist;
}));
it('should NOT provide button if no actions are available', inject(
function(elementRegistry, contextPad, popupMenu) {
// given
var elements = [
elementRegistry.get('EndEvent_lane'),
elementRegistry.get('Task_lane'),
elementRegistry.get('SubProcess_lane')
];
popupMenu.registerProvider('align-elements', 0, {
getPopupMenuEntries: function() {
return function() {
return {};
};
}
});
// when
contextPad.open(elements);
// then
expect(getEntry(elements, 'align-elements')).not.to.exist;
})
);
it('should open popup menu when item is clicked', inject(
function(elementRegistry, contextPad, popupMenu) {
// given
var elements = [
elementRegistry.get('EndEvent_lane'),
elementRegistry.get('Task_lane'),
elementRegistry.get('SubProcess_lane')
];
contextPad.open(elements);
// when
var entry = getEntry(elements, 'align-elements');
entry.click();
// then
expect(popupMenu.isOpen()).to.be.true;
})
);
});
// helper //////////////////////////////////////////////////////////////////////
function getEntry(target, actionName) {
return padEntry(getBpmnJS().invoke(function(contextPad) {
return contextPad.getPad(target).html;
}), actionName);
}
function padEntry(element, name) {
return domQuery('[data-action="' + name + '"]', element);
}

View File

@ -0,0 +1,93 @@
import {
bootstrapModeler,
getBpmnJS,
inject
} from 'test/TestHelper';
import {
query as domQuery
} from 'min-dom';
import {
forEach
} from 'min-dash';
import alignElementsModule from 'lib/features/align-elements';
import modelingModule from 'lib/features/modeling';
import coreModule from 'lib/core';
describe('features/align-elements - popup menu', function() {
var testModules = [ alignElementsModule, modelingModule, coreModule ];
var basicXML = require('../../../fixtures/bpmn/align-elements.bpmn');
beforeEach(bootstrapModeler(basicXML, { modules: testModules }));
it('should provide alignment buttons', inject(function(elementRegistry, popupMenu) {
// given
var elements = [
elementRegistry.get('EndEvent_lane'),
elementRegistry.get('Task_lane'),
elementRegistry.get('SubProcess_lane')
];
// when
popupMenu.open(elements, 'align-elements', {
x: 0,
y: 0
});
// then
forEach([
'left',
'center',
'right',
'top',
'middle',
'bottom'
], function(alignment) {
expect(getEntry('align-elements-' + alignment)).to.exist;
});
}));
it('should close popup menu when button is clicked', inject(
function(elementRegistry, popupMenu) {
// given
var elements = [
elementRegistry.get('EndEvent_lane'),
elementRegistry.get('Task_lane'),
elementRegistry.get('SubProcess_lane')
];
popupMenu.open(elements, 'align-elements', {
x: 0,
y: 0
});
var entry = getEntry('align-elements-center');
// when
entry.click();
// then
expect(popupMenu.isOpen()).to.be.false;
})
);
});
// helper //////////////////////////////////////////////////////////////////////
function getEntry(actionName) {
return padEntry(getBpmnJS().invoke(function(popupMenu) {
return popupMenu._current.container;
}), actionName);
}
function padEntry(element, name) {
return domQuery('[data-id="' + name + '"]', element);
}

View File

@ -3,7 +3,7 @@ import {
inject
} from 'test/TestHelper';
import alignElementsModule from 'diagram-js/lib/features/align-elements';
import alignElementsModule from 'lib/features/align-elements';
import modelingModule from 'lib/features/modeling';
import coreModule from 'lib/core';
@ -31,10 +31,10 @@ describe('features/align-elements', function() {
alignElements.trigger(elements, 'left');
// then
expect(taskBoundEvt.x).to.equal(136);
expect(task.x).to.equal(136);
expect(subProcess.x).to.equal(136);
expect(endEvent.x).to.equal(136);
expect(taskBoundEvt.x).to.equal(276);
expect(task.x).to.equal(276);
expect(subProcess.x).to.equal(276);
expect(endEvent.x).to.equal(276);
}));
@ -51,10 +51,10 @@ describe('features/align-elements', function() {
alignElements.trigger(elements, 'right');
// then
expect(task.x).to.equal(720);
expect(taskHello.x).to.equal(720);
expect(subProcess.x).to.equal(470);
expect(endEvent.x).to.equal(784);
expect(task.x).to.equal(860);
expect(taskHello.x).to.equal(860);
expect(subProcess.x).to.equal(610);
expect(endEvent.x).to.equal(924);
}));
@ -71,10 +71,10 @@ describe('features/align-elements', function() {
alignElements.trigger(elements, 'center');
// then
expect(task.x).to.equal(428);
expect(taskHello.x).to.equal(428);
expect(subProcess.x).to.equal(303);
expect(endEvent.x).to.equal(460);
expect(task.x).to.equal(568);
expect(taskHello.x).to.equal(568);
expect(subProcess.x).to.equal(443);
expect(endEvent.x).to.equal(600);
}));
@ -90,9 +90,9 @@ describe('features/align-elements', function() {
alignElements.trigger(elements, 'top');
// then
expect(task.y).to.equal(375);
expect(subProcess.y).to.equal(375);
expect(endEvent.y).to.equal(375);
expect(task.y).to.equal(445);
expect(subProcess.y).to.equal(445);
expect(endEvent.y).to.equal(445);
}));
@ -108,9 +108,9 @@ describe('features/align-elements', function() {
alignElements.trigger(elements, 'bottom');
// then
expect(task.y).to.equal(761);
expect(subProcess.y).to.equal(641);
expect(endEvent.y).to.equal(805);
expect(task.y).to.equal(831);
expect(subProcess.y).to.equal(711);
expect(endEvent.y).to.equal(875);
}));
@ -126,11 +126,59 @@ describe('features/align-elements', function() {
alignElements.trigger(elements, 'middle');
// then
expect(task.y).to.equal(568);
expect(subProcess.y).to.equal(508);
expect(endEvent.y).to.equal(590);
expect(task.y).to.equal(638);
expect(subProcess.y).to.equal(578);
expect(endEvent.y).to.equal(660);
}));
});
describe('rules', function() {
it('should not align boundary event', inject(function(alignElements, elementRegistry) {
// given
var boundaryEvent = elementRegistry.get('BoundaryEvent_1'),
host = elementRegistry.get('Task_boundary_evt');
var elements = [
host,
elementRegistry.get('Task_hello'),
boundaryEvent
];
var initialRelativePosition = {
x: boundaryEvent.x - host.x,
y: boundaryEvent.y - host.y
};
// when
alignElements.trigger(elements, 'middle');
// then
expect(boundaryEvent.x).to.equal(initialRelativePosition.x + host.x);
expect(boundaryEvent.y).to.equal(initialRelativePosition.y + host.y);
}));
it('should not align container children', inject(
function(alignElements, elementRegistry) {
// given
var elements = elementRegistry.getAll('SubProcessChild').slice(1),
child = elementRegistry.get('Task_hello');
var initialRelativePosition = {
x: child.x - child.parent.x,
y: child.y - child.parent.y
};
// when
alignElements.trigger(elements, 'middle');
// then
expect(child.x).to.equal(initialRelativePosition.x + child.parent.x);
expect(child.y).to.equal(initialRelativePosition.y + child.parent.y);
})
);
});
});

View File

@ -1,3 +1,5 @@
import { forEach } from 'min-dash';
import {
bootstrapModeler,
inject
@ -7,6 +9,8 @@ import bpmnDistributeElements from 'lib/features/distribute-elements';
import modelingModule from 'lib/features/modeling';
import coreModule from 'lib/core';
import { is } from 'lib/util/ModelUtil';
function last(arr) {
return arr[arr.length - 1];
}
@ -27,7 +31,7 @@ describe('features/distribute-elements', function() {
beforeEach(inject(function(elementRegistry, canvas) {
elements = elementRegistry.filter(function(element) {
return element.parent;
return element.parent && !is(element, 'bpmn:Participant');
});
}));
@ -79,34 +83,96 @@ describe('features/distribute-elements', function() {
describe('filtering elements', function() {
var xml = require('../../../fixtures/bpmn/distribute-elements-filtering.bpmn');
describe('process', function() {
beforeEach(bootstrapModeler(xml, { modules: testModules }));
var xml = require('../../../fixtures/bpmn/distribute-elements-filtering.bpmn'),
elements;
var elements;
beforeEach(inject(function(elementRegistry, canvas) {
elements = elementRegistry.filter(function(element) {
return element.parent;
});
}));
beforeEach(bootstrapModeler(xml, { modules: testModules }));
it('should not distribute boundary events', inject(function(distributeElements, elementRegistry) {
beforeEach(inject(function(elementRegistry) {
elements = elementRegistry.filter(function(element) {
return element.parent;
});
}));
// given
var boundaryEvent = elementRegistry.get('BoundaryEvent_1');
// when
var rangeGroups = distributeElements.trigger(elements, 'horizontal');
it('should not distribute boundary events', inject(function(distributeElements, elementRegistry) {
// then
expect(rangeGroups).to.have.length(3);
// given
var boundaryEvent = elementRegistry.get('BoundaryEvent_1');
expect(rangeGroups[1].elements).not.to.include(boundaryEvent);
// when
var rangeGroups = distributeElements.trigger(elements, 'horizontal');
}));
// then
expect(rangeGroups).to.have.length(3);
forEach(rangeGroups, function(rangeGroup) {
expect(rangeGroup.elements).not.to.include(boundaryEvent);
});
}));
it('should not distribute sub process children', inject(
function(distributeElements, elementRegistry) {
// given
var childElement = elementRegistry.get('SubProcessChild');
// when
var rangeGroups = distributeElements.trigger(elements, 'horizontal');
// then
expect(rangeGroups).to.have.length(3);
forEach(rangeGroups, function(rangeGroup) {
expect(rangeGroup.elements).not.to.include(childElement);
});
})
);
});
describe('collaboration', function() {
var xml = require('../../../fixtures/bpmn/distribute-elements-filtering.collaboration.bpmn'),
elements;
beforeEach(bootstrapModeler(xml, { modules: testModules }));
beforeEach(inject(function(elementRegistry) {
elements = elementRegistry.filter(function(element) {
return element.parent;
});
}));
it('should distribute participants', inject(function(distributeElements, elementRegistry) {
// given
var participants = elementRegistry.filter(function(element) {
return is(element, 'bpmn:Participant');
});
// when
var rangeGroups = distributeElements.trigger(elements, 'vertical');
// then
expect(rangeGroups).to.have.length(3);
var distributedElements = [];
forEach(rangeGroups, function(rangeGroup) {
distributedElements = distributedElements.concat(rangeGroup.elements);
});
expect(distributedElements).to.have.length(3);
expect(distributedElements).to.have.members(participants);
}));
});
});
});

View File

@ -0,0 +1,95 @@
import {
bootstrapModeler,
getBpmnJS,
inject
} from 'test/TestHelper';
import {
query as domQuery
} from 'min-dom';
import {
forEach
} from 'min-dash';
import distributeElementsModule from 'lib/features/distribute-elements';
import modelingModule from 'lib/features/modeling';
import coreModule from 'lib/core';
describe('features/distribute-elements - popup menu', function() {
var testModules = [ distributeElementsModule, modelingModule, coreModule ];
var basicXML = require('../../../fixtures/bpmn/distribute-elements.bpmn');
beforeEach(bootstrapModeler(basicXML, { modules: testModules }));
it('should provide distribution buttons', inject(function(elementRegistry, popupMenu) {
// given
var elements = [
elementRegistry.get('ExclusiveGateway_10cec0a'),
elementRegistry.get('Task_08pns8h'),
elementRegistry.get('Task_0511uak'),
elementRegistry.get('EndEvent_0c9irey')
];
// when
popupMenu.open(elements, 'align-elements', {
x: 0,
y: 0
});
// then
forEach([
'horizontal',
'vertical'
], function(distribution) {
expect(getEntry('distribute-elements-' + distribution)).to.exist;
});
}));
forEach([
'horizontal',
'vertical'
], function(distribution) {
it('should close popup menu when button is clicked', inject(
function(elementRegistry, popupMenu) {
// given
var elements = [
elementRegistry.get('ExclusiveGateway_10cec0a'),
elementRegistry.get('Task_08pns8h'),
elementRegistry.get('Task_0511uak'),
elementRegistry.get('EndEvent_0c9irey')
];
popupMenu.open(elements, 'align-elements', {
x: 0,
y: 0
});
var entry = getEntry('distribute-elements-' + distribution);
// when
entry.click();
// then
expect(popupMenu.isOpen()).to.be.false;
})
);
});
});
// helper //////////////////////////////////////////////////////////////////////
function getEntry(actionName) {
return padEntry(getBpmnJS().invoke(function(popupMenu) {
return popupMenu._current.container;
}), actionName);
}
function padEntry(element, name) {
return domQuery('[data-id="' + name + '"]', element);
}