123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- import {
- getDirection
- } from './SpaceUtil';
- import {
- set as cursorSet
- } from '../../util/Cursor';
- import {
- hasPrimaryModifier
- } from '../../util/Mouse';
- var abs = Math.abs,
- round = Math.round;
- var HIGH_PRIORITY = 1500,
- SPACE_TOOL_CURSOR = 'crosshair';
- var AXIS_TO_DIMENSION = { x: 'width', y: 'height' },
- AXIS_INVERTED = { x: 'y', y: 'x' };
- import {
- selfAndAllChildren as getAllChildren
- } from '../../util/Elements';
- import {
- assign,
- forEach
- } from 'min-dash';
- /**
- * A tool that allows users to create and remove space in a diagram.
- *
- * The tool needs to be activated manually via {@link SpaceTool#activate(MouseEvent)}.
- */
- export default function SpaceTool(
- eventBus, dragging, canvas,
- modeling, rules, toolManager) {
- this._canvas = canvas;
- this._dragging = dragging;
- this._modeling = modeling;
- this._rules = rules;
- this._toolManager = toolManager;
- var self = this;
- toolManager.registerTool('space', {
- tool: 'spaceTool.selection',
- dragging: 'spaceTool'
- });
- eventBus.on('spaceTool.selection.end', function(event) {
- var target = event.originalEvent.target;
- // only reactive on diagram click
- // on some occasions, event.hover is not set and we have to check if the target is an svg
- if (!event.hover && !(target instanceof SVGElement)) {
- return;
- }
- eventBus.once('spaceTool.selection.ended', function() {
- self.activateMakeSpace(event.originalEvent);
- });
- });
- eventBus.on('spaceTool.move', HIGH_PRIORITY , function(event) {
- var context = event.context;
- if (!context.initialized) {
- context.initialized = self.initializeMakeSpace(event, context);
- }
- });
- eventBus.on('spaceTool.end', function(event) {
- var context = event.context,
- axis = context.axis,
- direction = context.direction,
- movingShapes = context.movingShapes,
- resizingShapes = context.resizingShapes;
- // skip if create space has not been initialized yet
- if (!context.initialized) {
- return;
- }
- var delta = { x: round(event.dx), y: round(event.dy) };
- delta[ AXIS_INVERTED[ axis ] ] = 0;
- var insideBounds = true;
- // check if the space tool cursor is inside of bounds of
- // any of the shapes that would be resized.
- forEach(resizingShapes, function(shape) {
- if ((direction === 'w' && event.x > shape.x + shape.width) ||
- (direction === 'e' && event.x < shape.x) ||
- (direction === 'n' && event.y > shape.y + shape.height) ||
- (direction === 's' && event.y < shape.y)) {
- insideBounds = false;
- return;
- }
- });
- if (insideBounds) {
- // make space only if the cursor is inside bounds
- self.makeSpace(movingShapes, resizingShapes, delta, direction);
- }
- eventBus.once('spaceTool.ended', function(event) {
- // reactivate space tool after usage
- self.activateSelection(event.originalEvent, true, true);
- });
- });
- }
- SpaceTool.$inject = [
- 'eventBus',
- 'dragging',
- 'canvas',
- 'modeling',
- 'rules',
- 'toolManager'
- ];
- /**
- * Activate space tool selection
- *
- * @param {MouseEvent} event
- * @param {Boolean} autoActivate
- */
- SpaceTool.prototype.activateSelection = function(event, autoActivate, reactivate) {
- this._dragging.init(event, 'spaceTool.selection', {
- trapClick: false,
- cursor: SPACE_TOOL_CURSOR,
- autoActivate: autoActivate,
- data: {
- context: {
- reactivate: reactivate
- }
- }
- });
- };
- /**
- * Activate make space
- *
- * @param {MouseEvent} event
- */
- SpaceTool.prototype.activateMakeSpace = function(event) {
- this._dragging.init(event, 'spaceTool', {
- autoActivate: true,
- cursor: SPACE_TOOL_CURSOR,
- data: {
- context: {}
- }
- });
- };
- /**
- * Actually make space on the diagram
- *
- * @param {Array<djs.model.Shape>} movingShapes
- * @param {Array<djs.model.Shape>} resizingShapes
- * @param {Point} delta
- * @param {String} direction
- */
- SpaceTool.prototype.makeSpace = function(movingShapes, resizingShapes, delta, direction) {
- return this._modeling.createSpace(movingShapes, resizingShapes, delta, direction);
- };
- /**
- * Initialize make space and return true if that was successful.
- *
- * @param {Event} event
- * @param {Object} context
- *
- * @return {Boolean} true, if successful
- */
- SpaceTool.prototype.initializeMakeSpace = function(event, context) {
- var axis = abs(event.dx) > abs(event.dy) ? 'x' : 'y',
- offset = event['d' + axis],
- // start point of create space operation
- spacePos = event[axis] - offset;
- if (abs(offset) < 5) {
- return false;
- }
- // invert the offset in order to remove space when moving left
- if (offset < 0) {
- offset *= -1;
- }
- // inverts the offset to choose the shapes
- // on the opposite side of the resizer if
- // a key modifier is pressed
- if (hasPrimaryModifier(event)) {
- offset *= -1;
- }
- var rootShape = this._canvas.getRootElement();
- var allShapes = getAllChildren(rootShape, true);
- var adjustments = this.calculateAdjustments(allShapes, axis, offset, spacePos);
- // store data in context
- assign(context, adjustments, {
- axis: axis,
- direction: getDirection(axis, offset)
- });
- cursorSet('resize-' + (axis === 'x' ? 'ew' : 'ns'));
- return true;
- };
- /**
- * Calculate adjustments needed when making space
- *
- * @param {Array<djs.model.Shape>} elements
- * @param {String} axis
- * @param {Number} offset
- * @param {Number} spacePos
- *
- * @return {Object}
- */
- SpaceTool.prototype.calculateAdjustments = function(elements, axis, offset, spacePos) {
- var movingShapes = [],
- resizingShapes = [];
- var rules = this._rules;
- // collect all elements that need to be moved _AND_
- // resized given on the initial create space position
- elements.forEach(function(shape) {
- var shapeStart = shape[axis],
- shapeEnd = shapeStart + shape[AXIS_TO_DIMENSION[axis]];
- // checking if it's root
- if (!shape.parent) {
- return;
- }
- // checking if it's a shape
- if (shape.waypoints) {
- return;
- }
- // shape after spacePos
- if (offset > 0 && shapeStart > spacePos) {
- return movingShapes.push(shape);
- }
- // shape before spacePos
- if (offset < 0 && shapeEnd < spacePos) {
- return movingShapes.push(shape);
- }
- // shape on top of spacePos, resize only if allowed
- if (shapeStart < spacePos &&
- shapeEnd > spacePos &&
- rules.allowed('shape.resize', { shape: shape })) {
- return resizingShapes.push(shape);
- }
- });
- return {
- movingShapes: movingShapes,
- resizingShapes: resizingShapes
- };
- };
- SpaceTool.prototype.toggle = function() {
- if (this.isActive()) {
- this._dragging.cancel();
- } else {
- this.activateSelection();
- }
- };
- SpaceTool.prototype.isActive = function() {
- var context = this._dragging.context();
- return context && /^spaceTool/.test(context.prefix);
- };
|