123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- import inherits from 'inherits';
- import {
- getOrientation,
- getMid,
- asTRBL
- } from 'diagram-js/lib/layout/LayoutUtil';
- import {
- substract
- } from 'diagram-js/lib/util/Math';
- import {
- hasExternalLabel
- } from '../../../util/LabelUtil';
- import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
- var ALIGNMENTS = [
- 'top',
- 'bottom',
- 'left',
- 'right'
- ];
- var ELEMENT_LABEL_DISTANCE = 10;
- /**
- * A component that makes sure that external labels are added
- * together with respective elements and properly updated (DI wise)
- * during move.
- *
- * @param {EventBus} eventBus
- * @param {Modeling} modeling
- */
- export default function AdaptiveLabelPositioningBehavior(eventBus, modeling) {
- CommandInterceptor.call(this, eventBus);
- this.postExecuted([
- 'connection.create',
- 'connection.layout',
- 'connection.updateWaypoints'
- ], function(event) {
- var context = event.context,
- connection = context.connection,
- source = connection.source,
- target = connection.target,
- hints = context.hints || {};
- if (hints.createElementsBehavior !== false) {
- checkLabelAdjustment(source);
- checkLabelAdjustment(target);
- }
- });
- this.postExecuted([
- 'label.create'
- ], function(event) {
- var context = event.context,
- shape = context.shape,
- hints = context.hints || {};
- if (hints.createElementsBehavior !== false) {
- checkLabelAdjustment(shape.labelTarget);
- }
- });
- this.postExecuted([
- 'elements.create'
- ], function(event) {
- var context = event.context,
- elements = context.elements,
- hints = context.hints || {};
- if (hints.createElementsBehavior !== false) {
- elements.forEach(function(element) {
- checkLabelAdjustment(element);
- });
- }
- });
- function checkLabelAdjustment(element) {
- // skip non-existing labels
- if (!hasExternalLabel(element)) {
- return;
- }
- var optimalPosition = getOptimalPosition(element);
- // no optimal position found
- if (!optimalPosition) {
- return;
- }
- adjustLabelPosition(element, optimalPosition);
- }
- function adjustLabelPosition(element, orientation) {
- var elementMid = getMid(element),
- label = element.label,
- labelMid = getMid(label);
- // ignore labels that are being created
- if (!label.parent) {
- return;
- }
- var elementTrbl = asTRBL(element);
- var newLabelMid;
- switch (orientation) {
- case 'top':
- newLabelMid = {
- x: elementMid.x,
- y: elementTrbl.top - ELEMENT_LABEL_DISTANCE - label.height / 2
- };
- break;
- case 'left':
- newLabelMid = {
- x: elementTrbl.left - ELEMENT_LABEL_DISTANCE - label.width / 2,
- y: elementMid.y
- };
- break;
- case 'bottom':
- newLabelMid = {
- x: elementMid.x,
- y: elementTrbl.bottom + ELEMENT_LABEL_DISTANCE + label.height / 2
- };
- break;
- case 'right':
- newLabelMid = {
- x: elementTrbl.right + ELEMENT_LABEL_DISTANCE + label.width / 2,
- y: elementMid.y
- };
- break;
- }
- var delta = substract(newLabelMid, labelMid);
- modeling.moveShape(label, delta);
- }
- }
- inherits(AdaptiveLabelPositioningBehavior, CommandInterceptor);
- AdaptiveLabelPositioningBehavior.$inject = [
- 'eventBus',
- 'modeling'
- ];
- // helpers //////////////////////
- /**
- * Return alignments which are taken by a boundary's host element
- *
- * @param {Shape} element
- *
- * @return {Array<string>}
- */
- function getTakenHostAlignments(element) {
- var hostElement = element.host,
- elementMid = getMid(element),
- hostOrientation = getOrientation(elementMid, hostElement);
- var freeAlignments;
- // check whether there is a multi-orientation, e.g. 'top-left'
- if (hostOrientation.indexOf('-') >= 0) {
- freeAlignments = hostOrientation.split('-');
- } else {
- freeAlignments = [ hostOrientation ];
- }
- var takenAlignments = ALIGNMENTS.filter(function(alignment) {
- return freeAlignments.indexOf(alignment) === -1;
- });
- return takenAlignments;
- }
- /**
- * Return alignments which are taken by related connections
- *
- * @param {Shape} element
- *
- * @return {Array<string>}
- */
- function getTakenConnectionAlignments(element) {
- var elementMid = getMid(element);
- var takenAlignments = [].concat(
- element.incoming.map(function(c) {
- return c.waypoints[c.waypoints.length - 2 ];
- }),
- element.outgoing.map(function(c) {
- return c.waypoints[1];
- })
- ).map(function(point) {
- return getApproximateOrientation(elementMid, point);
- });
- return takenAlignments;
- }
- /**
- * Return the optimal label position around an element
- * or _undefined_, if none was found.
- *
- * @param {Shape} element
- *
- * @return {string} positioning identifier
- */
- function getOptimalPosition(element) {
- var labelMid = getMid(element.label);
- var elementMid = getMid(element);
- var labelOrientation = getApproximateOrientation(elementMid, labelMid);
- if (!isAligned(labelOrientation)) {
- return;
- }
- var takenAlignments = getTakenConnectionAlignments(element);
- if (element.host) {
- var takenHostAlignments = getTakenHostAlignments(element);
- takenAlignments = takenAlignments.concat(takenHostAlignments);
- }
- var freeAlignments = ALIGNMENTS.filter(function(alignment) {
- return takenAlignments.indexOf(alignment) === -1;
- });
- // NOTHING TO DO; label already aligned a.O.K.
- if (freeAlignments.indexOf(labelOrientation) !== -1) {
- return;
- }
- return freeAlignments[0];
- }
- function getApproximateOrientation(p0, p1) {
- return getOrientation(p1, p0, 5);
- }
- function isAligned(orientation) {
- return ALIGNMENTS.indexOf(orientation) !== -1;
- }
|