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 authored and fake-join[bot] committed Jul 7, 2022
1 parent 51aa2cd commit befe8b8
Show file tree
Hide file tree
Showing 28 changed files with 1,006 additions and 129 deletions.
37 changes: 33 additions & 4 deletions assets/bpmn-js.css
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,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;
}
2 changes: 1 addition & 1 deletion lib/Modeler.js
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
@@ -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
@@ -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
@@ -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
@@ -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
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
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
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
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
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit befe8b8

Please sign in to comment.