@syncfusion/ej2-diagrams
Version:
Feature-rich diagram control to create diagrams like flow charts, organizational charts, mind maps, and BPMN diagrams. Its rich feature set includes built-in shapes, editing, serializing, exporting, printing, overview, data binding, and automatic layouts.
962 lines • 65.9 kB
JavaScript
import { Rect } from '../primitives/rect';
import { PathElement } from '../core/elements/path-element';
import { SnapConstraints } from '../enum/enum';
import { Connector } from './connector';
import { Selector } from '../objects/node';
import { getBounds } from './../utility/base-util';
import { randomId } from './../utility/base-util';
import { isSelected } from '../interaction/actions';
import { TextElement } from '../core/elements/text-element';
import { DiagramHtmlElement } from '../core/elements/html-element';
/**
* Snapping
*/
var Snapping = /** @class */ (function () {
function Snapping(diagram) {
this.line = [];
this.diagram = diagram;
}
/** @private */
Snapping.prototype.canSnap = function () {
return (this.diagram.snapSettings.constraints
& (SnapConstraints.SnapToObject | SnapConstraints.SnapToLines)) !== 0;
};
Snapping.prototype.getWrapperObject = function (selectedObject, nameTable) {
if (selectedObject.nodes && selectedObject.nodes.length > 0
&& (this.diagram.snapSettings.constraints & SnapConstraints.SnapToLines || this.diagram.snapSettings.constraints
& SnapConstraints.SnapToObject)) {
for (var i = 0; i < selectedObject.nodes.length; i++) {
if (((selectedObject.nodes[parseInt(i.toString(), 10)].shape.type === 'SwimLane' || selectedObject.nodes[parseInt(i.toString(), 10)].isLane)
|| selectedObject.nodes[parseInt(i.toString(), 10)].parentId !== ''
&& nameTable[(selectedObject.nodes[parseInt(i.toString(), 10)].parentId)]
&& nameTable[(selectedObject.nodes[parseInt(i.toString(), 10)].parentId)].isLane) && nameTable['helper']) {
return nameTable['helper'].wrapper;
}
else {
return selectedObject.wrapper;
}
}
}
return selectedObject.wrapper;
};
Snapping.prototype.setSnapLineColor = function () {
return this.diagram.snapSettings.snapLineColor;
};
/**
* Snap to object
*
* @private
*/
Snapping.prototype.snapPoint = function (diagram, selectedObject, towardsLeft, towardsTop, delta, startPoint, endPoint) {
var snapSettings = this.diagram.snapSettings;
var zoomFactor = this.diagram.scroller.currentZoom;
var offset = { x: 0, y: 0 };
var wrapper = this.getWrapperObject(selectedObject, diagram.nameTable);
var bounds = getBounds(wrapper);
var horizontallysnapped = { snapped: false, offset: 0 };
var verticallysnapped = { snapped: false, offset: 0 };
if (this.diagram.snapSettings.constraints & SnapConstraints.SnapToObject) {
//let snapLine: SVGElement;
var snapLine = document.createElementNS('http://www.w3.org/2000/svg', 'g');
snapLine.setAttribute('id', '_SnappingLines');
snapLine.setAttribute('shapeRendering', 'crispEdges');
this.getAdornerLayerSvg().appendChild(snapLine);
this.snapObject(diagram, selectedObject, snapLine, horizontallysnapped, verticallysnapped, delta, startPoint === endPoint);
}
//original position
var left = bounds.x + delta.x;
var top = bounds.y + delta.y;
var right = bounds.x + bounds.width + delta.x;
var bottom = bounds.y + bounds.height + delta.y;
var scaledIntervals = snapSettings.verticalGridlines.scaledIntervals;
//snapped positions
var roundedRight = this.round(right, scaledIntervals, zoomFactor);
var roundedLeft = this.round(left, scaledIntervals, zoomFactor);
scaledIntervals = snapSettings.horizontalGridlines.scaledIntervals;
var roundedTop = this.round(top, scaledIntervals, zoomFactor);
var roundedBottom = this.round(bottom, scaledIntervals, zoomFactor);
//currentposition
var currentright = bounds.x + bounds.width;
var currentbottom = bounds.y + bounds.height;
if (!horizontallysnapped.snapped) {
if (this.diagram.snapSettings.constraints & SnapConstraints.SnapToVerticalLines) {
if (Math.abs(delta.x) >= 1) {
if (towardsLeft) {
if (Math.abs(roundedRight - currentright) > Math.abs(roundedLeft - bounds.x)) {
offset.x += roundedLeft - bounds.x;
}
else {
offset.x += roundedRight - currentright;
}
}
else {
if (Math.abs(roundedRight - currentright) < Math.abs(roundedLeft - bounds.x)) {
offset.x += roundedRight - currentright;
}
else {
offset.x += roundedLeft - bounds.x;
}
}
}
}
else {
offset.x = endPoint.x - startPoint.x;
}
}
else {
if (this.diagram.snapSettings.constraints & SnapConstraints.SnapToObject) {
offset.x = horizontallysnapped.offset;
}
else {
offset.x = endPoint.x - startPoint.x;
}
}
if (!verticallysnapped.snapped) {
if (this.diagram.snapSettings.constraints & SnapConstraints.SnapToHorizontalLines) {
if (Math.abs(delta.y) >= 1) {
if (towardsTop) {
if (Math.abs(roundedBottom - currentbottom) > Math.abs(roundedTop - bounds.y)) {
offset.y += roundedTop - bounds.y;
}
else {
offset.y += roundedBottom - currentbottom;
}
}
else {
if (Math.abs(roundedBottom - currentbottom) < Math.abs(roundedTop - bounds.y)) {
offset.y += roundedBottom - currentbottom;
}
else {
offset.y += roundedTop - bounds.y;
}
}
}
}
else {
offset.y = endPoint.y - startPoint.y;
}
}
else {
offset.y = verticallysnapped.offset;
}
return offset;
};
/**
* @private
*/
Snapping.prototype.round = function (value, snapIntervals, scale) {
if (scale === 1) {
scale = Math.pow(2, Math.floor(Math.log(scale) / Math.log(2)));
}
else {
scale = scale;
}
var cutoff = 0;
var i = 0;
for (i = 0; i < snapIntervals.length; i++) {
cutoff += snapIntervals[parseInt(i.toString(), 10)];
}
cutoff /= scale;
var quotient = Math.floor(Math.abs(value) / cutoff);
var bal = value % cutoff;
var prev = quotient * cutoff;
if (prev !== value) {
if (value >= 0) {
for (i = 0; i < snapIntervals.length; i++) {
if (bal <= snapIntervals[parseInt(i.toString(), 10)] / scale) {
return prev + (bal < (snapIntervals[parseInt(i.toString(), 10)] / (2 * scale))
? 0 : snapIntervals[parseInt(i.toString(), 10)] / scale);
}
else {
prev += snapIntervals[parseInt(i.toString(), 10)] / scale;
bal -= snapIntervals[parseInt(i.toString(), 10)] / scale;
}
}
}
else {
prev = prev * -1;
for (i = snapIntervals.length - 1; i >= 0; i--) {
if (Math.abs(bal) <= snapIntervals[parseInt(i.toString(), 10)] / scale) {
return prev - (Math.abs(bal) < (snapIntervals[parseInt(i.toString(), 10)] / (2 * scale))
? 0 : snapIntervals[parseInt(i.toString(), 10)] / scale);
}
else {
prev -= snapIntervals[parseInt(i.toString(), 10)] / scale;
bal += snapIntervals[parseInt(i.toString(), 10)] / scale;
}
}
}
}
return value;
};
//Snap to Object
Snapping.prototype.snapObject = function (diagram, selectedObject, g, horizontalSnap, verticalSnap, delta, ended) {
var lengthX = null;
var lengthY;
var hTarget;
var vTarget;
var scroller = this.diagram.scroller;
var snapSettings = this.diagram.snapSettings;
var objectsAtLeft = [];
var objectsAtRight = [];
var objectsAtTop = [];
var objectsAtBottom = [];
var wrapper = this.getWrapperObject(selectedObject, diagram.nameTable);
var bounds = getBounds(wrapper);
var scale = diagram.scroller.currentZoom;
var hoffset = -scroller.horizontalOffset;
var voffset = -scroller.verticalOffset;
var snapObjDistance = snapSettings.snapObjectDistance / scale;
var viewPort = new Rect(0, 0, scroller.viewPortWidth, scroller.viewPortHeight);
var hIntersectRect = new Rect(hoffset / scale, (bounds.y - snapObjDistance - 5), viewPort.width / scale, (bounds.height + 2 * snapObjDistance + 10));
var vIntersectRect = new Rect((bounds.x - snapObjDistance - 5), voffset / scale, (bounds.width + 2 * snapObjDistance + 10), viewPort.height / scale);
viewPort = new Rect(hoffset / scale, voffset / scale, viewPort.width / scale, viewPort.height / scale);
var nodes = this.findNodes(diagram.spatialSearch, selectedObject, vIntersectRect, viewPort);
var i;
var target;
var targetBounds;
var nameTable = diagram.nameTable;
for (i = 0; i < nodes.length; i++) {
target = nodes[parseInt(i.toString(), 10)];
if (this.canBeTarget(diagram, target)) {
if (!(this.diagram.nameTable[target.id] instanceof Connector) && this.canConsider(nameTable, selectedObject, target)) {
targetBounds = target.bounds;
if (targetBounds.height + targetBounds.y < delta.y + bounds.y) {
objectsAtTop.push({
obj: target, distance: Math.abs(bounds.y + delta.y - targetBounds.y - targetBounds.height)
});
}
else if (targetBounds.y > bounds.y + delta.y + bounds.height) {
objectsAtBottom.push({ obj: target, distance: Math.abs(bounds.y + delta.y + bounds.height - targetBounds.y) });
}
if (lengthX == null || lengthX > Math.abs(targetBounds.y - bounds.y - delta.y)) {
if (Math.abs(targetBounds.x + targetBounds.width / 2 - (bounds.x + bounds.width / 2 + delta.x)) <=
snapObjDistance) {
hTarget = this.createSnapObject(targetBounds, bounds, 'centerX');
lengthX = Math.abs(targetBounds.y - bounds.y);
}
else if (Math.abs(targetBounds.x + targetBounds.width - (bounds.x + bounds.width + delta.x)) <= snapObjDistance) {
hTarget = this.createSnapObject(targetBounds, bounds, 'right');
lengthX = Math.abs(targetBounds.y - bounds.y);
}
else if (Math.abs(targetBounds.x - (bounds.x + delta.x)) <= snapObjDistance) {
hTarget = this.createSnapObject(targetBounds, bounds, 'left');
lengthX = Math.abs(targetBounds.y - bounds.y);
}
else if (Math.abs(targetBounds.x - (bounds.x + bounds.width + delta.x)) <= snapObjDistance) {
hTarget = this.createSnapObject(targetBounds, bounds, 'rightLeft');
lengthX = Math.abs(targetBounds.y - bounds.y);
}
else if (Math.abs(targetBounds.x + targetBounds.width - (bounds.x + delta.x)) <= snapObjDistance) {
hTarget = this.createSnapObject(targetBounds, bounds, 'leftRight');
lengthX = Math.abs(targetBounds.y - bounds.y);
}
}
}
}
}
nodes = this.findNodes(diagram.spatialSearch, selectedObject, hIntersectRect, viewPort);
for (var j = 0; j < nodes.length; j++) {
target = nodes[parseInt(j.toString(), 10)];
if (this.canBeTarget(diagram, target)) {
if (!(this.diagram.nameTable[target.id] instanceof Connector) && this.canConsider(nameTable, selectedObject, target)) {
targetBounds = target.bounds;
if (targetBounds.x + targetBounds.width < bounds.x + delta.x) {
objectsAtLeft[objectsAtLeft.length] = {
obj: target, distance: Math.abs((bounds.x + delta.x) - targetBounds.x - targetBounds.width)
};
}
if (targetBounds.x > bounds.x + delta.x + bounds.width) {
objectsAtRight[objectsAtRight.length] = {
obj: target, distance: Math.abs(bounds.x + delta.x + bounds.width - targetBounds.x)
};
}
if (lengthY == null || lengthY > Math.abs(targetBounds.x - bounds.x - delta.x)) {
if (Math.abs(targetBounds.y + targetBounds.height / 2 - (bounds.y + bounds.height / 2 + delta.y))
<= snapObjDistance) {
vTarget = this.createSnapObject(targetBounds, bounds, 'centerY');
lengthY = Math.abs(targetBounds.x - bounds.x);
}
else if (Math.abs(targetBounds.y - bounds.y - delta.y) <= snapObjDistance) {
vTarget = this.createSnapObject(targetBounds, bounds, 'top');
lengthY = Math.abs(targetBounds.x - bounds.x);
}
else if (Math.abs(targetBounds.y + targetBounds.height - (bounds.y + bounds.height + delta.y)) <=
snapObjDistance) {
vTarget = this.createSnapObject(targetBounds, bounds, 'bottom');
lengthY = Math.abs(targetBounds.x - bounds.x);
}
else if (Math.abs(targetBounds.y + targetBounds.height - bounds.y - delta.y) <= snapObjDistance) {
vTarget = this.createSnapObject(targetBounds, bounds, 'topBottom');
lengthY = Math.abs(targetBounds.x - bounds.x);
}
else if (Math.abs(targetBounds.y - (bounds.y + bounds.height + delta.y)) <= snapObjDistance) {
vTarget = this.createSnapObject(targetBounds, bounds, 'bottomTop');
lengthY = Math.abs(targetBounds.x - bounds.x);
}
}
}
}
}
this.createGuidelines(diagram, hTarget, vTarget, g, horizontalSnap, verticalSnap, ended);
if (!horizontalSnap.snapped) {
this.createHSpacingLines(diagram, g, selectedObject, objectsAtLeft, objectsAtRight, horizontalSnap, verticalSnap, ended, delta, snapObjDistance);
}
if (!verticalSnap.snapped) {
this.createVSpacingLines(diagram, g, selectedObject, objectsAtTop, objectsAtBottom, horizontalSnap, verticalSnap, ended, delta, snapObjDistance);
}
};
/**
* @private
*/
Snapping.prototype.snapConnectorEnd = function (point) {
var snapSettings = this.diagram.snapSettings;
var zoomFactor = this.diagram.scroller.currentZoom;
if (snapSettings.constraints & SnapConstraints.SnapToLines) {
point.x = this.round(point.x, snapSettings.verticalGridlines.scaledIntervals, zoomFactor);
point.y = this.round(point.y, snapSettings.horizontalGridlines.scaledIntervals, zoomFactor);
}
return point;
};
Snapping.prototype.canBeTarget = function (diagram, node) {
node = this.diagram.nameTable[node.id];
return !(isSelected(this.diagram, node, false));
};
Snapping.prototype.snapSize = function (diagram, horizontalSnap, verticalSnap, snapLine, deltaX, deltaY, selectedObject, ended) {
var lengthX;
var lengthY;
var snapSettings = this.diagram.snapSettings;
var scroller = this.diagram.scroller;
var hTarget;
var vTarget;
var bounds = getBounds(selectedObject.wrapper);
var nameTable = diagram.nameTable;
var sameWidth = [];
var sameHeight = [];
var scale = diagram.scroller.currentZoom;
var hoffset = -scroller.horizontalOffset;
var voffset = -scroller.verticalOffset;
var snapObjDistance = snapSettings.snapObjectDistance / scale;
var viewPort = new Rect(0, 0, scroller.viewPortWidth, scroller.viewPortHeight);
var hintersectedrect = new Rect(hoffset / scale, (bounds.y - 5) / scale, viewPort.width / scale, (bounds.height + 10) / scale);
var vintersectedrect = new Rect((bounds.x - 5) / scale, voffset / scale, (bounds.width + 10) / scale, viewPort.height / scale);
viewPort = new Rect(hoffset / scale, voffset / scale, viewPort.width / scale, viewPort.height / scale);
var nodesInView = [];
var nodes = this.findNodes(diagram.spatialSearch, selectedObject, vintersectedrect, viewPort, nodesInView);
var i;
var target;
var targetBounds;
for (i = 0; i < nodes.length; i++) {
target = nodes[parseInt(i.toString(), 10)];
if (this.canConsider(nameTable, selectedObject, target) && !(this.diagram.nameTable[target.id] instanceof Connector)) {
targetBounds = target.bounds;
if (lengthX == null || lengthX > Math.abs(targetBounds.y - bounds.y)) {
if (horizontalSnap.left) {
if (Math.abs(bounds.x + deltaX - targetBounds.x) <= snapObjDistance) {
hTarget = this.createSnapObject(targetBounds, bounds, 'left');
lengthX = Math.abs(targetBounds.y - bounds.y);
}
else if (Math.abs(bounds.x + deltaX - targetBounds.x - targetBounds.width) <= snapObjDistance) {
hTarget = this.createSnapObject(targetBounds, bounds, 'leftRight');
lengthX = Math.abs(targetBounds.y - bounds.y);
}
}
else if (horizontalSnap.right) {
if (Math.abs(bounds.x + deltaX + bounds.width - targetBounds.x - targetBounds.width) <= snapObjDistance) {
hTarget = this.createSnapObject(targetBounds, bounds, 'right');
lengthX = Math.abs(targetBounds.y - bounds.y);
}
else if (Math.abs(bounds.x + deltaX + bounds.width - targetBounds.x) <= snapObjDistance) {
hTarget = this.createSnapObject(targetBounds, bounds, 'rightLeft');
lengthX = Math.abs(targetBounds.y - bounds.y);
}
}
}
}
}
nodes = this.findNodes(diagram.spatialSearch, selectedObject, hintersectedrect, viewPort);
for (var i_1 = 0; i_1 < nodes.length; i_1++) {
var target_1 = nodes[parseInt(i_1.toString(), 10)];
if (this.canConsider(nameTable, selectedObject, target_1) && !(this.diagram.nameTable[target_1.id] instanceof Connector)) {
var targetBounds_1 = target_1.bounds;
if (lengthY == null || lengthY > Math.abs(targetBounds_1.x - bounds.x)) {
if (verticalSnap.top) {
if (Math.abs(bounds.y + deltaY - targetBounds_1.y) <= snapObjDistance) {
vTarget = this.createSnapObject(targetBounds_1, bounds, 'top');
lengthY = Math.abs(targetBounds_1.x - bounds.x);
}
else if (Math.abs(bounds.y + deltaY - targetBounds_1.y - targetBounds_1.height) <= snapObjDistance) {
vTarget = this.createSnapObject(targetBounds_1, bounds, 'topBottom');
lengthY = Math.abs(targetBounds_1.x - bounds.x);
}
}
else if (verticalSnap.bottom) {
if (Math.abs(bounds.y + bounds.height + deltaY - targetBounds_1.y - targetBounds_1.height) <= snapObjDistance) {
vTarget = this.createSnapObject(targetBounds_1, bounds, 'bottom');
lengthY = Math.abs(targetBounds_1.x - bounds.x);
}
else if (Math.abs(bounds.y + bounds.height + deltaY - targetBounds_1.y) <= snapObjDistance) {
vTarget = this.createSnapObject(targetBounds_1, bounds, 'bottomTop');
lengthY = Math.abs(targetBounds_1.x - bounds.x);
}
}
}
}
}
for (i = 0; i < nodesInView.length; i++) {
target = nodesInView[parseInt(i.toString(), 10)];
if (this.canConsider(nameTable, selectedObject, target)) {
var targetBounds_2 = target.bounds;
var delta = horizontalSnap.left ? -deltaX : deltaX;
var difference = Math.abs(bounds.width + delta - targetBounds_2.width);
var actualDiff = void 0;
if (difference <= snapObjDistance) {
actualDiff = horizontalSnap.left ? -targetBounds_2.width + bounds.width : targetBounds_2.width - bounds.width;
sameWidth[sameWidth.length] = { source: target, difference: difference, offset: actualDiff };
}
delta = verticalSnap.top ? -deltaY : deltaY;
var dify = Math.abs(bounds.height + delta - targetBounds_2.height);
if (dify <= snapObjDistance) {
actualDiff = verticalSnap.top ? -targetBounds_2.height + bounds.height : targetBounds_2.height - bounds.height;
sameHeight[sameHeight.length] = { source: target, difference: dify, offset: actualDiff };
}
}
}
var g;
if (!diagram.getTool) {
var g_1 = this.createGuidelines(diagram, hTarget, vTarget, snapLine, horizontalSnap, verticalSnap, ended);
}
if (!horizontalSnap.snapped && sameWidth.length > 0 && (horizontalSnap.left || horizontalSnap.right)) {
this.addSameWidthLines(diagram, snapLine, sameWidth, horizontalSnap, ended, selectedObject);
}
if (!verticalSnap.snapped && sameHeight.length > 0 && (verticalSnap.top || verticalSnap.bottom)) {
this.addSameHeightLines(diagram, snapLine, sameHeight, verticalSnap, ended, selectedObject);
}
};
/**
* Snap to object on top
*
* @private
*/
Snapping.prototype.snapTop = function (horizontalSnap, verticalSnap, snapLine, deltaX, deltaY, shape, ended, initialBoundsT) {
var dify = deltaY;
verticalSnap.top = true;
var y;
horizontalSnap.left = horizontalSnap.right = false;
var zoomFactor = this.diagram.scroller.currentZoom;
//let initialBoundsT: Rect = new Rect(shape.offsetX, shape.offsetY, shape.width, shape.height);
if (this.diagram.snapSettings.constraints & SnapConstraints.SnapToObject && !shape.rotateAngle) {
//(!this.selectedObject.isLane && !this.selectedObject.isSwimlane)) {
y = initialBoundsT.y - initialBoundsT.height * shape.pivot.y + deltaY - (shape.offsetY - shape.height * shape.pivot.y);
this.snapSize(this.diagram, horizontalSnap, verticalSnap, snapLine, deltaX, y, this.diagram.selectedItems, ended);
}
if (!verticalSnap.snapped) {
if (this.diagram.snapSettings.constraints & SnapConstraints.SnapToHorizontalLines) {
var top_1 = initialBoundsT.y - initialBoundsT.height * shape.pivot.y;
var actualTop = top_1 + deltaY;
var roundedTop = this.round(actualTop, this.diagram.snapSettings.horizontalGridlines.scaledIntervals, zoomFactor);
dify = roundedTop - top_1;
}
}
else {
dify = (deltaY - y) + verticalSnap.offset;
}
return dify;
};
/**
* Snap to object on right
*
* @private
*/
Snapping.prototype.snapRight = function (horizontalSnap, verticalSnap, snapLine, deltaX, deltaY, shape, ended, initialBound) {
var difx = deltaX;
var x;
horizontalSnap.right = true;
verticalSnap.top = verticalSnap.bottom = false;
var zoomFactor = this.diagram.scroller.currentZoom;
//let initialBound: Rect = new Rect(shape.offsetX, shape.offsetY, shape.width, shape.height);
if (this.diagram.snapSettings.constraints & SnapConstraints.SnapToObject && !shape.rotateAngle) {
//(!this.selectedObject.isLane && !this.selectedObject.isSwimlane)) {
x = initialBound.x + initialBound.width * (1 - shape.pivot.x) + deltaX - (shape.offsetX + shape.width * (1 - shape.pivot.x));
this.snapSize(this.diagram, horizontalSnap, verticalSnap, snapLine, x, deltaY, this.diagram.selectedItems, ended);
}
if (!horizontalSnap.snapped) {
if (this.diagram.snapSettings.constraints & SnapConstraints.SnapToVerticalLines) {
var right = initialBound.x + initialBound.width * (1 - shape.pivot.x);
var actualRight = right + deltaX;
var roundedRight = this.round(actualRight, this.diagram.snapSettings.verticalGridlines.scaledIntervals, zoomFactor);
difx = roundedRight - right;
}
}
else {
difx = (deltaX - x) + horizontalSnap.offset;
}
return difx;
};
/**
* Snap to object on left
*
* @private
*/
Snapping.prototype.snapLeft = function (horizontalSnap, verticalSnap, snapLine, deltaX, deltaY, shape, ended, initialBoundsB) {
var difx = deltaX;
var x = 0;
horizontalSnap.left = true;
verticalSnap.top = verticalSnap.bottom = false;
var zoomFactor = this.diagram.scroller.currentZoom;
//let initialBoundsB: Rect = new Rect(shape.offsetX, shape.offsetY, shape.width, shape.height);
if (this.diagram.snapSettings.constraints & SnapConstraints.SnapToObject && !shape.rotateAngle) {
//(!this.selectedObject.isLane && !this.selectedObject.isSwimlane)) {
x = initialBoundsB.x - initialBoundsB.width * shape.pivot.x + deltaX - (shape.offsetX - shape.width * shape.pivot.x);
this.snapSize(this.diagram, horizontalSnap, verticalSnap, snapLine, x, deltaY, this.diagram.selectedItems, ended);
}
if (!horizontalSnap.snapped) {
if (this.diagram.snapSettings.constraints & SnapConstraints.SnapToVerticalLines) {
var left = initialBoundsB.x - initialBoundsB.width * shape.pivot.x;
var actualLeft = left + deltaX;
var roundedLeft = this.round(actualLeft, this.diagram.snapSettings.horizontalGridlines.scaledIntervals, zoomFactor);
difx = roundedLeft - left;
}
}
else {
difx = (deltaX - x) + horizontalSnap.offset;
}
return difx;
};
/**
* Snap to object on bottom
*
* @private
*/
Snapping.prototype.snapBottom = function (horizontalSnap, verticalSnap, snapLine, deltaX, deltaY, shape, ended, initialRect) {
var dify = deltaY;
verticalSnap.bottom = true;
horizontalSnap.left = horizontalSnap.right = false;
var zoomFactor = this.diagram.scroller.currentZoom;
var y = 0;
//let initialRect: Rect = new Rect(shape.offsetX, shape.offsetY, shape.width, shape.height);
if (this.diagram.snapSettings.constraints & SnapConstraints.SnapToObject && !shape.rotateAngle) {
//(!this.selectedObject.isLane && !this.selectedObject.isSwimlane)) {
y = initialRect.y + initialRect.height * (1 - shape.pivot.y) + deltaY - (shape.offsetY + shape.height * (1 - shape.pivot.y));
this.snapSize(this.diagram, horizontalSnap, verticalSnap, snapLine, deltaX, y, this.diagram.selectedItems, ended);
}
// eslint-disable-next-line max-len
var bounds = ((shape instanceof TextElement) || (shape instanceof DiagramHtmlElement)) ? getBounds(shape) :
getBounds(shape.wrapper);
if (!verticalSnap.snapped) {
if (this.diagram.snapSettings.constraints & SnapConstraints.SnapToHorizontalLines) {
var bottom = initialRect.y + initialRect.height * (1 - shape.pivot.y);
var actualBottom = bottom + deltaY;
var roundedBottom = this.round(actualBottom, this.diagram.snapSettings.horizontalGridlines.scaledIntervals, zoomFactor);
dify = roundedBottom - bottom;
}
}
else {
dify = (deltaY - y) + verticalSnap.offset;
}
return dify;
};
//To create the same width and same size lines
Snapping.prototype.createGuidelines = function (diagram, hTarget, vTarget, snapLine, horizontalSnap, verticalSnap, ended) {
if (hTarget) {
horizontalSnap.offset = hTarget.offsetX;
horizontalSnap.snapped = true;
if (!ended) {
if (hTarget.type === 'sideAlign') {
this.renderAlignmentLines(hTarget.start, hTarget.end, snapLine, diagram.scroller.transform);
}
else {
this.renderAlignmentLines(hTarget.start, hTarget.end, snapLine, diagram.scroller.transform);
}
}
}
if (vTarget) {
verticalSnap.offset = vTarget.offsetY;
verticalSnap.snapped = true;
if (!ended) {
if (vTarget.type === 'sideAlign') {
this.renderAlignmentLines(vTarget.start, vTarget.end, snapLine, diagram.scroller.transform);
}
else {
this.renderAlignmentLines(vTarget.start, vTarget.end, snapLine, diagram.scroller.transform);
}
}
}
return snapLine;
};
//To create the alignment lines
Snapping.prototype.renderAlignmentLines = function (start, end, svg, transform) {
start = {
x: (start.x + transform.tx) * transform.scale,
y: (start.y + transform.ty) * transform.scale
};
end = {
x: (end.x + transform.tx) * transform.scale,
y: (end.y + transform.ty) * transform.scale
};
var line1 = {
stroke: this.setSnapLineColor(), strokeWidth: 1, startPoint: { x: start.x, y: start.y },
endPoint: { x: end.x, y: end.y }, fill: this.setSnapLineColor(), dashArray: '', width: 1,
x: 0, y: 0, height: 0, angle: 0, pivotX: 0,
pivotY: 0, visible: true, opacity: 1, id: randomId()
};
var i = 0;
this.line.push(line1);
for (i = 0; i < this.line.length; i++) {
this.diagram.diagramRenderer.drawLine(svg, this.line.pop());
}
};
//To create Horizontal spacing lines
Snapping.prototype.createHSpacingLines = function (diagram, g, shape, objectsAtLeft, objectsAtRight, horizontalSnap, verticalSnap, ended, delta, snapObjDistance) {
var top = 0;
this.sortByDistance(objectsAtLeft, 'distance', true);
this.sortByDistance(objectsAtRight, 'distance', true);
var equallySpaced = [];
var bounds;
if (diagram.selectedObject.helperObject) {
bounds = getBounds(diagram.selectedObject.helperObject.wrapper);
}
else {
bounds = getBounds(shape.wrapper);
}
var nearestleft;
var nearestright;
var targetBounds;
var equaldistance;
if (objectsAtLeft.length > 0) {
equallySpaced[equallySpaced.length] = objectsAtLeft[0];
nearestleft = ((objectsAtLeft[0].obj).bounds);
top = nearestleft.y;
if (objectsAtLeft.length > 1) {
targetBounds = ((objectsAtLeft[1].obj).bounds);
equaldistance = nearestleft.x - targetBounds.x - targetBounds.width;
if (Math.abs(equaldistance - objectsAtLeft[0].distance) <= snapObjDistance) {
top = this.findEquallySpacedNodesAtLeft(objectsAtLeft, equaldistance, top, equallySpaced);
}
else {
equaldistance = objectsAtLeft[0].distance;
}
}
else {
equaldistance = objectsAtLeft[0].distance;
}
}
this.sortByDistance(equallySpaced, 'distance');
equallySpaced[equallySpaced.length] = { obj: shape, distance: 0 };
top = bounds.y < top || !top ? bounds.y : top;
if (objectsAtRight.length > 0) {
var dist = void 0;
nearestright = ((objectsAtRight[0].obj).bounds);
top = nearestright.y < top ? nearestright.y : top;
if (objectsAtRight.length > 1) {
targetBounds = ((objectsAtRight[1].obj).bounds);
dist = targetBounds.x - nearestright.x - nearestright.width;
}
if (objectsAtLeft.length > 0) {
if (Math.abs(objectsAtRight[0].distance - objectsAtLeft[0].distance) <= snapObjDistance) {
var adjustablevalue = Math.abs(objectsAtRight[0].distance - objectsAtLeft[0].distance) / 2;
(objectsAtRight[0].distance < objectsAtLeft[0].distance) ?
equaldistance -= adjustablevalue : equaldistance += adjustablevalue;
equallySpaced[equallySpaced.length] = objectsAtRight[0];
}
else if (objectsAtLeft.length === 1) {
nearestleft = undefined;
equallySpaced.splice(0, 1);
equallySpaced[equallySpaced.length] = objectsAtRight[0];
equaldistance = dist;
}
}
else {
equaldistance = dist;
equallySpaced[equallySpaced.length] = objectsAtRight[0];
}
if (objectsAtRight.length > 1 && nearestright.x + nearestright.width < targetBounds.x) {
top = this.findEquallySpacedNodesAtRight(objectsAtRight, dist, top, equallySpaced, snapObjDistance);
}
}
if (equallySpaced.length > 2) {
this.addHSpacingLines(diagram, g, equallySpaced, ended, top);
var deltaHorizontal = 0;
if (ended) {
deltaHorizontal = delta.x;
}
if (nearestleft) {
horizontalSnap.offset = equaldistance - Math.abs(bounds.x + deltaHorizontal - nearestleft.x - nearestleft.width)
+ deltaHorizontal;
}
else if (nearestright) {
horizontalSnap.offset = Math.abs(bounds.x + bounds.width + deltaHorizontal - nearestright.x)
- equaldistance + deltaHorizontal;
}
horizontalSnap.snapped = true;
}
};
//To create vertical spacing lines
Snapping.prototype.createVSpacingLines = function (diagram, g, shape, objectsAtTop, objectsAtBottom, horizontalSnap, verticalSnap, ended, delta, snapObjDistance) {
var right = 0;
this.sortByDistance(objectsAtTop, 'distance', true);
this.sortByDistance(objectsAtBottom, 'distance', true);
var equallySpaced = [];
var wrapper = this.getWrapperObject(shape, diagram.nameTable);
var bounds = getBounds(wrapper);
var nearesttop;
var nearestbottom;
var targetBounds;
var equaldistance;
if (objectsAtTop.length > 0) {
equallySpaced[equallySpaced.length] = objectsAtTop[0];
nearesttop = ((objectsAtTop[0].obj).bounds);
right = nearesttop.x + nearesttop.width;
if (objectsAtTop.length > 1) {
targetBounds = ((objectsAtTop[1].obj).bounds);
equaldistance = nearesttop.y - targetBounds.y - targetBounds.height;
if (Math.abs(equaldistance - objectsAtTop[0].distance) <= snapObjDistance) {
right = this.findEquallySpacedNodesAtTop(objectsAtTop, equaldistance, right, equallySpaced);
}
else {
equaldistance = objectsAtTop[0].distance;
}
}
else {
equaldistance = objectsAtTop[0].distance;
}
}
this.sortByDistance(equallySpaced, 'distance');
equallySpaced[equallySpaced.length] = { obj: shape, distance: 0 };
right = bounds.x + bounds.width > right || !right ? bounds.x + bounds.width : right;
var dist;
if (objectsAtBottom.length > 0) {
nearestbottom = ((objectsAtBottom[0].obj).bounds);
right = nearestbottom.x + nearestbottom.width > right ? nearestbottom.x + nearestbottom.width : right;
if (objectsAtBottom.length > 1) {
targetBounds = ((objectsAtBottom[1].obj).bounds);
dist = targetBounds.y - nearestbottom.y - nearestbottom.height;
}
if (objectsAtTop.length > 0) {
if (Math.abs(objectsAtBottom[0].distance - objectsAtTop[0].distance) <= snapObjDistance) {
var adjustablevalue = Math.abs(objectsAtBottom[0].distance - objectsAtTop[0].distance) / 2;
(objectsAtBottom[0].distance < objectsAtTop[0].distance) ?
equaldistance -= adjustablevalue : equaldistance += adjustablevalue;
equallySpaced[equallySpaced.length] = objectsAtBottom[0];
}
else if (objectsAtTop.length === 1) {
nearesttop = undefined;
equallySpaced.splice(0, 1);
equallySpaced[equallySpaced.length] = objectsAtBottom[0];
equaldistance = dist;
}
}
else {
equaldistance = dist;
equallySpaced[equallySpaced.length] = objectsAtBottom[0];
}
if (objectsAtBottom.length > 1 && targetBounds.y > nearestbottom.y + nearestbottom.height) {
right = this.findEquallySpacedNodesAtBottom(objectsAtBottom, dist, right, equallySpaced, snapObjDistance);
}
}
if (equallySpaced.length > 2) {
this.addVSpacingLines(diagram, g, equallySpaced, ended, right);
var deltaVertical = 0;
if (ended) {
deltaVertical = delta.y;
}
if (nearesttop) {
verticalSnap.offset = equaldistance - Math.abs(bounds.y + deltaVertical - nearesttop.y - nearesttop.height) + deltaVertical;
}
else if (nearestbottom) {
verticalSnap.offset = Math.abs(bounds.y + bounds.height + deltaVertical - nearestbottom.y) - equaldistance + deltaVertical;
}
verticalSnap.snapped = true;
}
};
//Add the Horizontal spacing lines
Snapping.prototype.addHSpacingLines = function (diagram, g, equallySpaced, ended, top) {
var i;
var start;
var end;
if (!ended) {
for (i = 0; i < equallySpaced.length - 1; i++) {
var crnt = equallySpaced[parseInt(i.toString(), 10)].obj instanceof Selector ?
getBounds((equallySpaced[parseInt(i.toString(), 10)].obj).wrapper)
: ((equallySpaced[parseInt(i.toString(), 10)].obj).bounds);
var next = equallySpaced[i + 1].obj instanceof Selector ?
getBounds((equallySpaced[i + 1].obj).wrapper) : ((equallySpaced[i + 1].obj).bounds);
start = { x: crnt.x + crnt.width, y: top - 15 };
end = { x: next.x, y: top - 15 };
this.renderSpacingLines(start, end, g, this.getAdornerLayerSvg(), diagram.scroller.transform);
}
}
};
//Add the vertical spacing lines
Snapping.prototype.addVSpacingLines = function (diagram, g, equallySpacedObjects, ended, right) {
var start;
var end;
if (!ended) {
for (var i = 0; i < equallySpacedObjects.length - 1; i++) {
var crnt = equallySpacedObjects[parseInt(i.toString(), 10)].obj instanceof Selector ?
getBounds((equallySpacedObjects[parseInt(i.toString(), 10)].obj).wrapper)
: ((equallySpacedObjects[parseInt(i.toString(), 10)].obj).bounds);
var next = equallySpacedObjects[i + 1].obj instanceof Selector ?
getBounds((equallySpacedObjects[i + 1].obj).wrapper) :
((equallySpacedObjects[i + 1].obj).bounds);
start = { x: right + 15, y: crnt.y + crnt.height };
end = { x: right + 15, y: next.y };
this.renderSpacingLines(start, end, g, this.getAdornerLayerSvg(), diagram.scroller.transform);
}
}
};
//To add same width lines
Snapping.prototype.addSameWidthLines = function (diagram, snapLine, sameWidths, horizontalSnap, ended, shape) {
this.sortByDistance(sameWidths, 'offset');
var bounds = getBounds(shape.wrapper);
var target = sameWidths[0];
var startPt;
var endPt;
var targetBounds = (target.source).bounds;
var sameSizes = [];
sameSizes.push(sameWidths[0]);
var i;
var crntbounds;
for (i = 1; i < sameWidths.length; i++) {
crntbounds = (sameWidths[parseInt(i.toString(), 10)].source).bounds;
if (crntbounds.width === targetBounds.width) {
sameSizes.push(sameWidths[parseInt(i.toString(), 10)]);
}
}
if (!ended) {
startPt = { x: bounds.x + target.offset, y: bounds.y - 15 };
endPt = { x: bounds.x + bounds.width + target.offset, y: bounds.y - 15 };
this.renderSpacingLines(startPt, endPt, snapLine, this.getAdornerLayerSvg(), diagram.scroller.transform);
for (i = 0; i < sameSizes.length; i++) {
bounds = (sameSizes[parseInt(i.toString(), 10)].source).bounds;
startPt = { x: bounds.x, y: bounds.y - 15 };
endPt = { x: bounds.x + bounds.width, y: bounds.y - 15 };
this.renderSpacingLines(startPt, endPt, snapLine, this.getAdornerLayerSvg(), diagram.scroller.transform);
}
}
horizontalSnap.offset = target.offset;
horizontalSnap.snapped = true;
};
//To add same height lines
Snapping.prototype.addSameHeightLines = function (diagram, snapLine, sameHeights, verticalSnap, ended, shape) {
this.sortByDistance(sameHeights, 'offset');
var bounds = getBounds(shape.wrapper);
var target = sameHeights[0];
var targetBounds = (target.source).bounds;
var start;
var end;
var sameSizes = [];
sameSizes.push(sameHeights[0]);
var i;
var crntbounds;
for (i = 0; i < sameHeights.length; i++) {
crntbounds = (sameHeights[parseInt(i.toString(), 10)].source).bounds;
if (crntbounds.height === targetBounds.height) {
sameSizes.push(sameHeights[parseInt(i.toString(), 10)]);
}
}
if (!ended) {
start = { x: bounds.x + bounds.width + 15, y: bounds.y + target.offset };
end = { x: bounds.x + bounds.width + 15, y: bounds.y + target.offset + bounds.height };
this.renderSpacingLines(start, end, snapLine, this.getAdornerLayerSvg(), diagram.scroller.transform);
for (i = 0; i < sameSizes.length; i++) {
bounds = (sameSizes[parseInt(i.toString(), 10)].source).bounds;
start = { x: bounds.x + bounds.width + 15, y: bounds.y };
end = { x: bounds.x + bounds.width + 15, y: bounds.y + bounds.height };
this.renderSpacingLines(start, end, snapLine, this.getAdornerLayerSvg(), diagram.scroller.transform);
}
}
verticalSnap.offset = target.offset;
verticalSnap.snapped = true;
};
//Render spacing lines
Snapping.prototype.renderSpacingLines = function (start, end, snapLine, svg, transform) {
var d;
var d1;
var line1;
var element = new PathElement();
var options = {};
start = {
x: (start.x + transform.tx) * transform.scale,
y: (start.y + transform.ty) * transform.scale
};
end = {
x: (end.x + transform.tx) * transform.scale,
y: (end.y + transform.ty) * transform.scale
};
if (start.x === end.x) {
d = 'M' + (start.x - 5) + ' ' + (start.y + 5) + 'L' + start.x + ' ' + start.y +
'L' + (start.x + 5) + ' ' + (start.y + 5) + 'z' + 'M' + (end.x - 5) + ' ' +
(end.y - 5) + ' L' + end.x + ' ' + end.y + ' L' +
(end.x + 5) + ' ' + (end.y - 5) + 'z';
line1 = {
startPoint: { x: start.x - 8, y: start.y - 1 },
endPoint: { x: start.x + 8, y: start.y - 1 },
stroke: this.setSnapLineColor(),
strokeWidth: 1, fill: this.setSnapLineColor(), dashArray: '', width: 1, x: 0, y: 0, height: 0, angle: 0, pivotX: 0,
pivotY: 0, visible: true, opacity: 1, id: randomId()
};
element.data = d;
options.data = element.data;
options.angle = 0;
options.pivotX = 0;
options.pivotY = 0;
options.x = 0;
options.y = 0;
options.height = 0;
options.width = 1;
options.id = randomId();
this.diagram.diagramRenderer.drawPath(snapLine, options);
this.line.push(line1);
this.diagram.diagramRenderer.drawLine(snapLine, this.line.pop());
line1 = {
startPoint: { x: end.x - 8, y: end.y + 1 },
endPoint: { x: end.x + 8, y: end.y + 1 },
stroke: this.setSnapLineColor(),
strokeWidth: 1, fill: this.setSnapLineColor(), dashArray: '', width: 1, x: 0, y: 0, height: 0, angle: 0, pivotX: 0,
pivotY: 0, visible: true, opacity: 1, id: this.getAdornerLayerSvg().id + 'spacing'
};
this.line.push(line1);
this.diagram.diagramRenderer.drawLine(snapLine, this.line.pop());
}
else {
d = 'M' + (start.x + 5) + ' ' + (start.y + 5) + ' L' + start.x + ' ' + start.y +
' L' + (start.x + 5) + ' ' + (start.y - 5) + 'z' + 'M' + (end.x - 5) + ' ' +
(end.y - 5) + ' L' + end.x + ' ' + end.y +
' L' + (end.x - 5) + ' ' + (end.y + 5) + 'z';
element.data = d;
options.data = d;
options.angle = 0;
options.pivotX = 0;
options.pivotY = 0;
options.x = 0;
options.y = 0;
options.height = 0;
options.width = 1;
options.id = randomId();
this.diagram.diagramRenderer.drawPath(snapLine, options);
line1 = {
visible: true, opacity: 1, id: randomId(),
startPoint: { x: start.x - 1, y: start.y - 8 },
endPoint: { x: start.x - 1, y: start.y + 8 },
stroke: this.setSnapLineColor(),
strokeWidth: 1, fill: this.setSnapLineColor(), dashArray: '0', width: 1, x: 0, y: 0, height: 0, angle: 0, pivotX: 0,
pivotY: 0
};
this.line.push(line1);
this.diagram.diagramRenderer.drawLine(snapLine, this.line.pop());
line1 = {
width: 1, x: 0, y: 0, height: 0, angle: 0, pivotX: 0,
pivotY: 0, visible: true, opacity: 1, id: randomId(),
startPoint: { x: end.x + 1, y: end.y - 8 },
endPoint: { x: end.x + 1, y: end.y + 8 },
stroke: this.setSnapLineColor(),
strokeWidth: 1, fill: this.setSnapLineColor(), dashArray: '0'
};
this.line.push(line1);
this.diagram.diagramRenderer.drawLine(snapLine, this.line.pop());
}
line1 = {
startPoint: { x: start.x, y: start.y },
endPoint: { x: end.x, y: end.y }, stroke: this.setSnapLineColor(), strokeWidth: 1, fill: this.setSnapLineColor(),
dashArray: '0', width: 1, x: