Skip to content

Commit

Permalink
feat(grid-snapping): integrate grid snapping with existing features
Browse files Browse the repository at this point in the history
  • Loading branch information
philippfromme committed Apr 15, 2019
1 parent 261832c commit 3d05d2f
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 19 deletions.
42 changes: 34 additions & 8 deletions lib/features/auto-resize/AutoResize.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export default function AutoResize(eventBus, elementRegistry, modeling, rules) {
return;
}

self._expand(shape.children || [], shape);
self._expand(shape.children || [], shape, true);
});

this.postExecuted([ 'shape.resize' ], function(event) {
Expand Down Expand Up @@ -168,7 +168,7 @@ AutoResize.prototype._getOptimalBounds = function(elements, target) {
* @param {Array<djs.model.Shape>} elements
* @param {djs.model.Shape|String} target|targetId
*/
AutoResize.prototype._expand = function(elements, target) {
AutoResize.prototype._expand = function(elements, target, isToggleCollapse) {

if (typeof target === 'string') {
target = this._elementRegistry.get(target);
Expand All @@ -191,7 +191,9 @@ AutoResize.prototype._expand = function(elements, target) {
}

// resize the parent shape
this.resize(target, newBounds);
this.resize(target, newBounds, {
autoResize: isToggleCollapse ? true : getResizeDirection(target, newBounds)
});

var parent = target.parent;

Expand All @@ -218,11 +220,9 @@ AutoResize.prototype.getOffset = function(shape) {
* Get the activation threshold for each side for which
* resize triggers.
*
* @param {djs.model.Shape} shape
*
* @return {Object} {top, bottom, left, right}
*/
AutoResize.prototype.getPadding = function(shape) {
AutoResize.prototype.getPadding = function() {
return { top: 2, bottom: 2, left: 15, right: 15 };
};

Expand All @@ -233,8 +233,8 @@ AutoResize.prototype.getPadding = function(shape) {
* @param {djs.model.Shape} target
* @param {Object} newBounds
*/
AutoResize.prototype.resize = function(target, newBounds) {
this._modeling.resizeShape(target, newBounds);
AutoResize.prototype.resize = function(target, newBounds, hints) {
this._modeling.resizeShape(target, newBounds, null, hints);
};


Expand All @@ -245,4 +245,30 @@ function boundsChanged(newBounds, oldBounds) {
newBounds.width !== oldBounds.width ||
newBounds.height !== oldBounds.height
);
}

function getResizeDirection(oldBounds, newBounds) {
var direction = '';

if (oldBounds.height < newBounds.height) {

if (oldBounds.y > newBounds.y) {
direction = direction.concat('n');
} else {
direction = direction.concat('s');
}

}

if (oldBounds.width < newBounds.width) {

if (oldBounds.x > newBounds.x) {
direction = direction.concat('e');
} else {
direction = direction.concat('w');
}

}

return direction;
}
52 changes: 43 additions & 9 deletions lib/features/grid-snapping/GridSnapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import { isNumber } from 'min-dash';
var SPACING = 10,
LOWER_PRIORITY = 1200;


/**
* Basic grid snapping that covers connecting, creating, moving, resizing shapes, moving bendpoints
* and connection segments.
*/
export default function GridSnapping(
eventBus,
config,
Expand Down Expand Up @@ -38,7 +41,38 @@ export default function GridSnapping(
'shape.move.move',
'shape.move.end',
'create.move',
'create.end',
'create.end'
], LOWER_PRIORITY, function(event) {
var originalEvent = event.originalEvent;

if (!self.active || (originalEvent && isCmd(originalEvent))) {
return;
}

var snappedValue;

if (!isSnapped(event, 'x')) {
if (event.shape.width % (SPACING * 2) === 0) {
snappedValue = self.snapValue(event.x - event.shape.width / 2, getSnapConstraints(event, 'x'));

setSnapped(event, 'x', snappedValue + event.shape.width / 2);
} else {
setSnapped(event, 'x', self.snapValue(event.x, getSnapConstraints(event, 'x')));
}
}

if (!isSnapped(event, 'y')) {
if (event.shape.height % (SPACING * 2) === 0) {
snappedValue = self.snapValue(event.y - event.shape.height / 2, getSnapConstraints(event, 'y'));

setSnapped(event, 'y', snappedValue + event.shape.height / 2);
} else {
setSnapped(event, 'y', self.snapValue(event.y, getSnapConstraints(event, 'y')));
}
}
});

eventBus.on([
'connect.move',
'connect.end',
'resize.move',
Expand All @@ -56,22 +90,22 @@ export default function GridSnapping(

[ 'x', 'y' ].forEach(function(axis) {
if (!isSnapped(event, axis)) {
self.snap(event, axis);
self.snapEvent(event, axis);
}
});
});
}

GridSnapping.prototype.snap = function(event, axis) {
GridSnapping.prototype.snapEvent = function(event, axis) {
var snapConstraints = getSnapConstraints(event, axis);

var snappedValue = this._getSnappedValue(event[ axis ], snapConstraints);
var snappedValue = this.snapValue(event[ axis ], snapConstraints);

setSnapped(event, axis, snappedValue);
};

GridSnapping.prototype._getSnappedValue = function(value, snapConstraints) {
value = quantize(value, SPACING);
GridSnapping.prototype.snapValue = function(value, snapConstraints, quantum) {
value = quantize(value, quantum || SPACING);

var min, max;

Expand All @@ -80,13 +114,13 @@ GridSnapping.prototype._getSnappedValue = function(value, snapConstraints) {
max = snapConstraints.max;

if (isNumber(min)) {
min = quantize(min, SPACING, 'ceil');
min = quantize(min, quantum || SPACING, 'ceil');

value = Math.max(value, min);
}

if (isNumber(max)) {
max = quantize(max, SPACING, 'floor');
max = quantize(max, quantum || SPACING, 'floor');

value = Math.min(value, max);
}
Expand Down
72 changes: 72 additions & 0 deletions lib/features/grid-snapping/behavior/ResizeBehavior.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import inherits from 'inherits';

import CommandInterceptor from '../../../command/CommandInterceptor';
import { isString } from 'min-dash';


/**
* Integrates resizing with grid snapping.
*/
export default function ResizeBehavior(eventBus, gridSnapping, modeling) {
CommandInterceptor.call(this, eventBus);

this.preExecute('shape.resize', function(event) {
var context = event.context,
hints = context.hints,
autoResize = hints && hints.autoResize;

var shape, direction, newBounds;

if (autoResize) {
shape = context.shape;
newBounds = context.newBounds;

if (isString(autoResize)) {

// snap x, y, width and height depending on direction
direction = autoResize;

if (/e|w/.test(direction)) {
newBounds.width = gridSnapping.snapValue(newBounds.width, {
min: newBounds.width
});
}

if (/e/.test(direction)) {
newBounds.x = shape.x + shape.width - newBounds.width;
}

if (/n|s/.test(direction)) {
newBounds.height = gridSnapping.snapValue(newBounds.height, {
min: newBounds.height
});
}

if (/n/.test(direction)) {
newBounds.y = shape.y + shape.height - newBounds.height;
}
} else {

// snap width and height without moving shape
newBounds.width = gridSnapping.snapValue(newBounds.width, {
min: newBounds.width
}, 20);

newBounds.height = gridSnapping.snapValue(newBounds.height, {
min: newBounds.height
}, 20);

newBounds.x = shape.x + (shape.width / 2) - (newBounds.width / 2);
newBounds.y = shape.y + (shape.height / 2) - (newBounds.height / 2);
}
}
});
}

ResizeBehavior.$inject = [
'eventBus',
'gridSnapping',
'modeling'
];

inherits(ResizeBehavior, CommandInterceptor);
29 changes: 29 additions & 0 deletions lib/features/grid-snapping/behavior/SpaceToolBehavior.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Integrates space tool with grid snapping.
*/
export default function SpaceToolBehavior(eventBus, gridSnapping) {
eventBus.on('spaceTool.move', function(event) {
var context = event.context;

if (!context.initialized) {
return;
}

var axis = context.axis;

if (axis === 'x') {

// snap delta x to multiple of 10
event.dx = gridSnapping.snapValue(event.dx);
} else {

// snap delta y to multiple of 10
event.dy = gridSnapping.snapValue(event.dy);
}
});
}

SpaceToolBehavior.$inject = [
'eventBus',
'gridSnapping'
];
16 changes: 16 additions & 0 deletions lib/features/grid-snapping/behavior/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import GridSnapping from '../GridSnapping';

import ResizeBehavior from './ResizeBehavior';
import SpaceToolBehavior from './SpaceToolBehavior';

export default {
__depends__: [
GridSnapping
],
__init__: [
'gridSnappingResizeBehavior',
'gridSnappingSpaceToolBehavior'
],
gridSnappingResizeBehavior: [ 'type', ResizeBehavior ],
gridSnappingSpaceToolBehavior: [ 'type', SpaceToolBehavior ]
};
5 changes: 3 additions & 2 deletions lib/features/modeling/Modeling.js
Original file line number Diff line number Diff line change
Expand Up @@ -415,11 +415,12 @@ Modeling.prototype.alignElements = function(elements, alignment) {
this._commandStack.execute('elements.align', context);
};

Modeling.prototype.resizeShape = function(shape, newBounds, minBounds) {
Modeling.prototype.resizeShape = function(shape, newBounds, minBounds, hints) {
var context = {
shape: shape,
newBounds: newBounds,
minBounds: minBounds
minBounds: minBounds,
hints: hints
};

this._commandStack.execute('shape.resize', context);
Expand Down

0 comments on commit 3d05d2f

Please sign in to comment.