123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- import {
- pick,
- assign
- } from 'min-dash';
- import {
- resizeBounds,
- ensureConstraints,
- computeChildrenBBox,
- getMinResizeBounds
- } from './ResizeUtil';
- import {
- asTRBL,
- roundBounds
- } from '../../layout/LayoutUtil';
- var DEFAULT_MIN_WIDTH = 10;
- /**
- * A component that provides resizing of shapes on the canvas.
- *
- * The following components are part of shape resize:
- *
- * * adding resize handles,
- * * creating a visual during resize
- * * checking resize rules
- * * committing a change once finished
- *
- *
- * ## Customizing
- *
- * It's possible to customize the resizing behaviour by intercepting 'resize.start'
- * and providing the following parameters through the 'context':
- *
- * * minDimensions ({ width, height }): minimum shape dimensions
- *
- * * childrenBoxPadding ({ left, top, bottom, right } || number):
- * gap between the minimum bounding box and the container
- *
- * f.ex:
- *
- * ```javascript
- * eventBus.on('resize.start', 1500, function(event) {
- * var context = event.context,
- *
- * context.minDimensions = { width: 140, height: 120 };
- *
- * // Passing general padding
- * context.childrenBoxPadding = 30;
- *
- * // Passing padding to a specific side
- * context.childrenBoxPadding.left = 20;
- * });
- * ```
- */
- export default function Resize(eventBus, rules, modeling, dragging) {
- this._dragging = dragging;
- this._rules = rules;
- var self = this;
- /**
- * Handle resize move by specified delta.
- *
- * @param {Object} context
- * @param {Point} delta
- */
- function handleMove(context, delta) {
- var shape = context.shape,
- direction = context.direction,
- resizeConstraints = context.resizeConstraints,
- newBounds;
- context.delta = delta;
- newBounds = resizeBounds(shape, direction, delta);
- // ensure constraints during resize
- context.newBounds = ensureConstraints(newBounds, resizeConstraints);
- // update + cache executable state
- context.canExecute = self.canResize(context);
- }
- /**
- * Handle resize start.
- *
- * @param {Object} context
- */
- function handleStart(context) {
- var resizeConstraints = context.resizeConstraints,
- // evaluate minBounds for backwards compatibility
- minBounds = context.minBounds;
- if (resizeConstraints !== undefined) {
- return;
- }
- if (minBounds === undefined) {
- minBounds = self.computeMinResizeBox(context);
- }
- context.resizeConstraints = {
- min: asTRBL(minBounds)
- };
- }
- /**
- * Handle resize end.
- *
- * @param {Object} context
- */
- function handleEnd(context) {
- var shape = context.shape,
- canExecute = context.canExecute,
- newBounds = context.newBounds;
- if (canExecute) {
- // ensure we have actual pixel values for new bounds
- // (important when zoom level was > 1 during move)
- newBounds = roundBounds(newBounds);
- // perform the actual resize
- modeling.resizeShape(shape, newBounds);
- }
- }
- eventBus.on('resize.start', function(event) {
- handleStart(event.context);
- });
- eventBus.on('resize.move', function(event) {
- var delta = {
- x: event.dx,
- y: event.dy
- };
- handleMove(event.context, delta);
- });
- eventBus.on('resize.end', function(event) {
- handleEnd(event.context);
- });
- }
- Resize.prototype.canResize = function(context) {
- var rules = this._rules;
- var ctx = pick(context, [ 'newBounds', 'shape', 'delta', 'direction' ]);
- return rules.allowed('shape.resize', ctx);
- };
- /**
- * Activate a resize operation.
- *
- * You may specify additional contextual information and must specify a
- * resize direction during activation of the resize event.
- *
- * @param {MouseEvent} event
- * @param {djs.model.Shape} shape
- * @param {Object|String} contextOrDirection
- */
- Resize.prototype.activate = function(event, shape, contextOrDirection) {
- var dragging = this._dragging,
- context,
- direction;
- if (typeof contextOrDirection === 'string') {
- contextOrDirection = {
- direction: contextOrDirection
- };
- }
- context = assign({ shape: shape }, contextOrDirection);
- direction = context.direction;
- if (!direction) {
- throw new Error('must provide a direction (nw|se|ne|sw)');
- }
- var referencePoint = {
- x: /w/.test(direction) ? shape.x : shape.x + shape.width,
- y: /n/.test(direction) ? shape.y : shape.y + shape.height
- };
- dragging.init(event, referencePoint, 'resize', {
- autoActivate: true,
- cursor: 'resize-' + (/nw|se/.test(direction) ? 'nwse' : 'nesw'),
- data: {
- shape: shape,
- context: context
- }
- });
- };
- Resize.prototype.computeMinResizeBox = function(context) {
- var shape = context.shape,
- direction = context.direction,
- minDimensions,
- childrenBounds;
- minDimensions = context.minDimensions || {
- width: DEFAULT_MIN_WIDTH,
- height: DEFAULT_MIN_WIDTH
- };
- // get children bounds
- childrenBounds = computeChildrenBBox(shape, context.childrenBoxPadding);
- // get correct minimum bounds from given resize direction
- // basically ensures that the minBounds is max(childrenBounds, minDimensions)
- return getMinResizeBounds(direction, shape, minDimensions, childrenBounds);
- };
- Resize.$inject = [
- 'eventBus',
- 'rules',
- 'modeling',
- 'dragging'
- ];
|