Skip to content

Commit

Permalink
feat: add alignment and distribution menu multi-element context pad
Browse files Browse the repository at this point in the history
Closes #1680
Closes #1691
  • Loading branch information
barmac committed Jul 6, 2022
1 parent 7a29bdf commit a980d70
Show file tree
Hide file tree
Showing 27 changed files with 895 additions and 112 deletions.
36 changes: 32 additions & 4 deletions assets/bpmn-js.css
Original file line number Diff line number Diff line change
Expand Up @@ -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%);
Expand All @@ -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);
Expand Down Expand Up @@ -113,4 +113,32 @@

.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: -ms-grid;
display: grid;

-ms-grid-columns: 1fr 1fr 1fr;
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%;
}
2 changes: 1 addition & 1 deletion lib/Modeler.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
87 changes: 87 additions & 0 deletions lib/features/align-elements/AlignElementsContextPadProvider.js
Original file line number Diff line number Diff line change
@@ -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;
};
15 changes: 15 additions & 0 deletions lib/features/align-elements/AlignElementsIcons.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 72 additions & 0 deletions lib/features/align-elements/AlignElementsMenuProvider.js
Original file line number Diff line number Diff line change
@@ -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;
};
39 changes: 39 additions & 0 deletions lib/features/align-elements/BpmnAlignElements.js
Original file line number Diff line number Diff line change
@@ -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;
});
};
23 changes: 23 additions & 0 deletions lib/features/align-elements/index.js
Original file line number Diff line number Diff line change
@@ -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]
};
5 changes: 5 additions & 0 deletions lib/features/align-elements/resources/align-bottom-tool.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions lib/features/align-elements/resources/align-left-tool.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions lib/features/align-elements/resources/align-right-tool.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions lib/features/align-elements/resources/align-tool.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions lib/features/align-elements/resources/align-top-tool.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit a980d70

Please sign in to comment.