diagram-js
Version:
A toolbox for displaying and modifying diagrams on the web
215 lines (158 loc) • 4.56 kB
JavaScript
import {
bind,
forEach
} from 'min-dash';
import {
append as svgAppend,
attr as svgAttr,
classes as svgClasses,
clear as svgClear,
create as svgCreate
} from 'tiny-svg';
import {
event as domEvent
} from 'min-dom';
import {
isPrimaryButton
} from '../../util/Mouse';
import {
transform
} from '../../util/SvgTransformUtil';
import { getReferencePoint } from './Resize';
import { isConnection } from '../../util/ModelUtil';
/**
* @typedef {import('../../model/Types').Element} Element
*
* @typedef {import('../../core/Canvas').default} Canvas
* @typedef {import('../../core/EventBus').default} EventBus
* @typedef {import('../resize/Resize').default} Resize
* @typedef {import('../selection/Selection').default} Selection
*/
var HANDLE_OFFSET = -6,
HANDLE_SIZE = 8,
HANDLE_HIT_SIZE = 20;
var CLS_RESIZER = 'djs-resizer';
var directions = [ 'n', 'w', 's', 'e', 'nw', 'ne', 'se', 'sw' ];
/**
* This component is responsible for adding resize handles.
*
* @param {EventBus} eventBus
* @param {Canvas} canvas
* @param {Selection} selection
* @param {Resize} resize
*/
export default function ResizeHandles(eventBus, canvas, selection, resize) {
this._resize = resize;
this._canvas = canvas;
var self = this;
eventBus.on('selection.changed', function(e) {
var newSelection = e.newSelection;
// remove old selection markers
self.removeResizers();
// add new selection markers ONLY if single selection
if (newSelection.length === 1) {
forEach(newSelection, bind(self.addResizer, self));
}
});
eventBus.on('shape.changed', function(e) {
var shape = e.element;
if (selection.isSelected(shape)) {
self.removeResizers();
self.addResizer(shape);
}
});
}
ResizeHandles.prototype.makeDraggable = function(element, gfx, direction) {
var resize = this._resize;
function startResize(event) {
// only trigger on left mouse button
if (isPrimaryButton(event)) {
resize.activate(event, element, direction);
}
}
domEvent.bind(gfx, 'mousedown', startResize);
domEvent.bind(gfx, 'touchstart', startResize);
};
ResizeHandles.prototype._createResizer = function(element, x, y, direction) {
var resizersParent = this._getResizersParent();
var offset = getHandleOffset(direction);
var group = svgCreate('g');
svgClasses(group).add(CLS_RESIZER);
svgClasses(group).add(CLS_RESIZER + '-' + element.id);
svgClasses(group).add(CLS_RESIZER + '-' + direction);
svgAppend(resizersParent, group);
var visual = svgCreate('rect');
svgAttr(visual, {
x: -HANDLE_SIZE / 2 + offset.x,
y: -HANDLE_SIZE / 2 + offset.y,
width: HANDLE_SIZE,
height: HANDLE_SIZE
});
svgClasses(visual).add(CLS_RESIZER + '-visual');
svgAppend(group, visual);
var hit = svgCreate('rect');
svgAttr(hit, {
x: -HANDLE_HIT_SIZE / 2 + offset.x,
y: -HANDLE_HIT_SIZE / 2 + offset.y,
width: HANDLE_HIT_SIZE,
height: HANDLE_HIT_SIZE
});
svgClasses(hit).add(CLS_RESIZER + '-hit');
svgAppend(group, hit);
transform(group, x, y);
return group;
};
ResizeHandles.prototype.createResizer = function(element, direction) {
var point = getReferencePoint(element, direction);
var resizer = this._createResizer(element, point.x, point.y, direction);
this.makeDraggable(element, resizer, direction);
};
// resize handles implementation ///////////////////////////////
/**
* Add resizers for a given element.
*
* @param {Element} element
*/
ResizeHandles.prototype.addResizer = function(element) {
var self = this;
if (isConnection(element) || !this._resize.canResize({ shape: element })) {
return;
}
forEach(directions, function(direction) {
self.createResizer(element, direction);
});
};
/**
* Remove all resizers
*/
ResizeHandles.prototype.removeResizers = function() {
var resizersParent = this._getResizersParent();
svgClear(resizersParent);
};
ResizeHandles.prototype._getResizersParent = function() {
return this._canvas.getLayer('resizers');
};
ResizeHandles.$inject = [
'eventBus',
'canvas',
'selection',
'resize'
];
// helpers //////////
function getHandleOffset(direction) {
var offset = {
x: 0,
y: 0
};
if (direction.indexOf('e') !== -1) {
offset.x = -HANDLE_OFFSET;
} else if (direction.indexOf('w') !== -1) {
offset.x = HANDLE_OFFSET;
}
if (direction.indexOf('s') !== -1) {
offset.y = -HANDLE_OFFSET;
} else if (direction.indexOf('n') !== -1) {
offset.y = HANDLE_OFFSET;
}
return offset;
}