UNPKG

@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.

638 lines (637 loc) 30.3 kB
import { isBlazor } from '@syncfusion/ej2-base'; import { Node, Lane } from '../objects/node'; import { Diagram } from '../diagram'; import { Selector } from '../objects/node'; import { Size } from '../primitives/size'; import { cloneObject } from './../utility/base-util'; import { getObjectType } from './../utility/diagram-util'; import { Rect } from '../primitives/rect'; import { getAdornerLayerSvg } from '../utility/dom-util'; import { swimLaneMeasureAndArrange, checkLaneSize, checkPhaseOffset, canLaneInterchange } from '../utility/swim-lane-util'; import { updatePhaseMaxWidth, updateHeaderMaxWidth, updateConnectorsProperties } from '../utility/swim-lane-util'; import { considerSwimLanePadding } from '../utility/swim-lane-util'; import { DiagramAction, DiagramConstraints, NodeConstraints } from '../enum/enum'; import { getDiagramElement } from '../utility/dom-util'; /** * Interaction for Container */ //#region canvas Container interaction /** * updateCanvasBounds method\ * * @returns { void } updateCanvasBounds method .\ * @param {Diagram} diagram - provide the diagram value. * @param {NodeModel | ConnectorModel} obj - provide the isVertical value. * @param {PointModel} position - provide the position value. * @param {boolean} isBoundsUpdate - provide the isBoundsUpdate value. * @private */ export function updateCanvasBounds(diagram, obj, position, isBoundsUpdate) { var container; var connectorList = []; var groupAction = false; if (checkParentAsContainer(diagram, obj, true)) { diagram.protectPropertyChange(true); container = diagram.nameTable[obj.parentId]; var wrapper = container.wrapper; if (diagram.selectedItems.nodes.length > 1) { diagram.multiselect = true; } else { diagram.multiselect = false; } if (container && container.container.type === 'Canvas') { if ((isBoundsUpdate || (wrapper.bounds.x <= position.x && wrapper.bounds.right >= position.x && (wrapper.bounds.y <= position.y && wrapper.bounds.bottom >= position.y) && !diagram.multiselect))) { var parentWrapper = void 0; var y = wrapper.bounds.y; var x = wrapper.bounds.x; var parent_1 = diagram.nameTable[container.parentId] || container; var shape = parent_1.shape; if (shape.type === 'SwimLane') { groupAction = updateLaneBoundsAfterAddChild(container, parent_1, obj, diagram, true); } else { var parent_2 = diagram.nameTable[container.parentId] || container; var shape_1 = parent_2.shape; parentWrapper = parent_2.wrapper; if (wrapper.actualSize.width < wrapper.outerBounds.width && (!(wrapper.bounds.x > wrapper.outerBounds.x))) { if (container.rowIndex !== undefined) { //const columnIndex:number = parent.columns.length - 1; parentWrapper.updateColumnWidth(container.columnIndex, wrapper.outerBounds.width, true); if (shape_1.orientation === 'Horizontal' && shape_1.phaseSize) { updatePhaseMaxWidth(parent_2, diagram, wrapper, container.columnIndex); } updateHeaderMaxWidth(diagram, parent_2); diagram.drag(parent_2, x - wrapper.bounds.x, y - wrapper.bounds.y); } else { diagram.scale(container, (1 + ((wrapper.outerBounds.width - wrapper.actualSize.width) / wrapper.actualSize.width)), 1, ((wrapper.outerBounds.x < wrapper.bounds.x) ? { x: 1, y: 0.5 } : { x: 0, y: 0.5 })); } } if (wrapper.actualSize.height < wrapper.outerBounds.height && (!(wrapper.bounds.y > wrapper.outerBounds.y))) { if (container.rowIndex !== undefined) { parentWrapper.updateRowHeight(container.rowIndex, wrapper.outerBounds.height, true); diagram.drag(parent_2, x - wrapper.bounds.x, y - wrapper.bounds.y); } else { diagram.scale(container, 1, (1 + ((wrapper.outerBounds.height - wrapper.actualSize.height) / wrapper.actualSize.height)), ((wrapper.outerBounds.y < wrapper.bounds.y) ? { x: 0.5, y: 1 } : { x: 0.5, y: 0 })); } } } } diagram.select([obj]); updateConnectorsProperties(connectorList, diagram); } diagram.protectPropertyChange(false); } return groupAction; } /** * removeChildInContainer method\ * * @returns { void } removeChildInContainer method .\ * @param {Diagram} diagram - provide the diagram value. * @param {NodeModel | ConnectorModel} obj - provide the isVertical value. * @param {PointModel} position - provide the position value. * @param {boolean} isBoundsUpdate - provide the isBoundsUpdate value. * @private */ export function removeChildInContainer(diagram, obj, position, isBoundsUpdate) { var container; //let connectorList: string[] = []; if (checkParentAsContainer(diagram, obj, true) && !(diagram.cancelPositionChange)) { var isProtectedOnChange = 'isProtectedOnChange'; var propertyChangeValue = diagram["" + isProtectedOnChange]; diagram.protectPropertyChange(true); container = diagram.nameTable[obj.parentId]; var wrapper = container.wrapper; if (container && container.container.type === 'Canvas') { if ((!isBoundsUpdate && (!(wrapper.bounds.x <= position.x && wrapper.bounds.right >= position.x && (wrapper.bounds.y <= position.y && wrapper.bounds.bottom >= position.y))))) { if (!(obj.constraints & NodeConstraints.AllowMovingOutsideLane)) { var undoObj = cloneObject(obj); diagram.clearSelection(); removeChildrenInLane(diagram, obj); obj.parentId = ''; //EJ2-65676 - Exception throws on updating node annotation after drag and drop from swimlane to diagram canvas. obj.parentObj = diagram; obj.propName = 'nodes'; var entry = { type: 'ChildCollectionChanged', category: 'Internal', undoObject: undoObj, redoObject: cloneObject(obj) }; diagram.addHistoryEntry(entry); if (diagram.commandHandler.isContainer) { diagram.commandHandler.isContainer = false; diagram.endGroupAction(); } moveSwinLaneChild(obj, diagram); } } } diagram.protectPropertyChange(propertyChangeValue); } } /** * findBounds method\ * * @returns { NodeModel | ConnectorModel } findBounds method .\ * @param {NodeModel} obj - provide the diagram value. * @param {number} columnIndex - provide the isVertical value. * @param {boolean} isHeader - provide the isVertical value. * @private */ export function findBounds(obj, columnIndex, isHeader) { var rect = new Rect(); var rows = (obj.shape.type === 'SwimLane') ? obj.wrapper.children[0].rows : obj.wrapper.rows; for (var i = ((isHeader) ? 1 : 0); i < rows.length; i++) { rect.uniteRect(rows[parseInt(i.toString(), 10)].cells[parseInt(columnIndex.toString(), 10)].bounds); } return rect; } /** * createHelper method\ * * @returns { NodeModel | ConnectorModel } createHelper method .\ * @param {Diagram} diagram - provide the diagram value. * @param {NodeModel | ConnectorModel} obj - provide the isVertical value. * @private */ export function createHelper(diagram, obj) { var newObj; var cloneObject = {}; for (var _i = 0, _a = Object.keys(obj); _i < _a.length; _i++) { var prop = _a[_i]; cloneObject["" + prop] = obj["" + prop]; } if (getObjectType(obj) === Node) { newObj = new Node(diagram, 'nodes', cloneObject, true); newObj.id = obj.id; diagram.initObject(newObj); } diagram.updateDiagramObject(newObj); return newObj; } /** * renderContainerHelper method\ * * @returns { NodeModel | ConnectorModel } renderContainerHelper method .\ * @param {Diagram} diagram - provide the diagram value. * @param {NodeModel | ConnectorModel} obj - provide the isVertical value. * @private */ export function renderContainerHelper(diagram, obj) { diagram.enableServerDataBinding(false); var object; var container; var nodes; if (!isBlazor()) { if (diagram.selectedObject.helperObject) { nodes = diagram.selectedObject.helperObject; } else if (diagram.selectedItems.nodes.length > 0 || diagram.selectedItems.connectors.length > 0) { if (obj instanceof Selector && obj.nodes.length + obj.connectors.length === 1) { object = (obj.nodes.length > 0) ? obj.nodes[0] : obj.connectors[0]; container = diagram.selectedItems.wrapper.children[0]; } else { object = obj; //Removed isBlazor code container = diagram.selectedItems.wrapper; } diagram.selectedObject.actualObject = object; // Added below code to render helper object for multiselected nodes inside swimlane to avoid interaction related issues. var dragObject = object instanceof Selector ? (object.nodes.length > 0 ? object.nodes[0] : object) : object; diagram.selectedObject.actualObject = object; if ((!diagram.currentSymbol) && (((dragObject.isLane && canLaneInterchange(dragObject, diagram) && checkParentAsContainer(diagram, dragObject)) || ((!dragObject.isLane) && checkParentAsContainer(diagram, dragObject))) || ((diagram.constraints & DiagramConstraints.LineRouting) && diagram.selectedItems.nodes.length > 0))) { var node = { id: 'helper', rotateAngle: container.rotateAngle, offsetX: container.offsetX, offsetY: container.offsetY, minWidth: container.minWidth, minHeight: container.minHeight, maxWidth: container.maxWidth, maxHeight: container.maxHeight, width: container.actualSize.width, height: container.actualSize.height, pivot: container.pivot, style: { strokeDashArray: '2 2', fill: 'transparent', strokeColor: '#7D7D7D', strokeWidth: 2 } }; nodes = createHelper(diagram, node); diagram.selectedObject.helperObject = nodes; } } } diagram.enableServerDataBinding(true); return nodes; } /** * checkParentAsContainer method\ * * @returns { void } checkParentAsContainer method .\ * @param {Diagram} diagram - provide the diagram value. * @param {NodeModel | ConnectorModel} obj - provide the isVertical value. * @param {boolean} isChild - provide the isChild value. * @private */ export function checkParentAsContainer(diagram, obj, isChild) { var parentNode = (isChild) ? diagram.nameTable[obj.parentId] : (diagram.nameTable[obj.parentId] || obj); if (parentNode && parentNode.container) { return true; } return false; } /** * checkChildNodeInContainer method\ * * @returns { void } checkChildNodeInContainer method .\ * @param {Diagram} diagram - provide the diagram value. * @param {NodeModel} obj - provide the isVertical value. * @private */ export function checkChildNodeInContainer(diagram, obj) { var parentNode = diagram.nameTable[obj.parentId]; obj.laneMargin = { left: obj.margin.left, right: obj.margin.right, top: obj.margin.top, bottom: obj.margin.bottom }; //To handle the resize of bpmn node which has text annotation inside swimlane if (obj.hasTextAnnotation) { for (var i = 0; i < obj.outEdges.length; i++) { var connector = diagram.nameTable[obj.outEdges[parseInt(i.toString(), 10)]]; if (connector.isBpmnAnnotationConnector) { var textNode = diagram.nameTable[connector.targetID]; var oldObject = { width: obj.wrapper.actualSize.width, height: obj.wrapper.actualSize.height, offsetX: obj.wrapper.offsetX, offsetY: obj.wrapper.offsetY }; var oldX = obj.wrapper.offsetX; var oldY = obj.wrapper.offsetY; var offset = diagram.getTextAnnotationOffset(obj, textNode, oldObject, oldX, oldY); var difX = offset.x - oldX; var difY = offset.y - oldY; if (difX || difY || obj.width !== obj.wrapper.actualSize.width || obj.height !== obj.wrapper.actualSize.height) { obj.isResized = true; if (!obj.resizeDif) { obj.resizeDif = []; } obj.resizeDif[textNode.id] = { x: difX, y: difY }; } } } } if (parentNode && parentNode.container.type === 'Canvas') { obj.margin.left = (obj.offsetX - parentNode.wrapper.bounds.x - (obj.width / 2)); obj.margin.top = (obj.offsetY - parentNode.wrapper.bounds.y - (obj.height / 2)); } diagram.nodePropertyChange(obj, {}, { width: obj.width, height: obj.height, offsetX: obj.offsetX, offsetY: obj.offsetY, margin: { left: obj.margin.left, right: obj.margin.right, top: obj.margin.top, bottom: obj.margin.bottom }, rotateAngle: obj.rotateAngle }); //EJ2-913789 - Lane size gets varied upon undo redo the node drop if (diagram.undoRedoModule && parentNode && parentNode.isLane && diagram.undoRedoModule.checkRedo && (obj.margin.left < 0 || obj.margin.top < 0)) { removeChildrenInLane(diagram, obj); } if (parentNode && !parentNode.isLane) { parentNode.wrapper.measure(new Size()); parentNode.wrapper.arrange(parentNode.wrapper.desiredSize); } } function removeChildrenInLane(diagram, node) { if (node.parentId && node.parentId !== '') { var prevParentNode = diagram.nameTable[node.parentId]; if (prevParentNode.isLane && prevParentNode.parentId) { var swimlane = diagram.nameTable[prevParentNode.parentId]; var canvasId = (prevParentNode.id.slice(swimlane.id.length)); var prevParentId = canvasId.substring(0, canvasId.length - 1); var lanes = swimlane.shape.lanes; var lane = void 0; for (var i = 0; i < lanes.length; i++) { lane = lanes[parseInt(i.toString(), 10)]; if (prevParentId === lane.id) { for (var j = 0; j < lane.children.length; j++) { if (lane.children[parseInt(j.toString(), 10)].id === node.id) { lane.children.splice(j, 1); j--; } } } } } diagram.deleteChild(node); } } /** * * @param { NodeModel | ConnectorModel} obj - Provide the obj value. * @param { NodeModel } swimlane - Provide the swimlane value. * @param { Diagram } diagram - Provide the diagram value. * @returns { void } updateZindex method .\ * @private */ export function updateZindex(obj, swimlane, diagram) { var objLayer = diagram.commandHandler.getObjectLayer(obj.id); var zIndexTable = objLayer.zIndexTable; var targetZIndex = swimlane.zIndex + 1; // Find a unique zIndex while (zIndexTable[parseInt(targetZIndex.toString(), 10)] !== undefined) { targetZIndex++; } // Assign the unique zIndex to the node delete objLayer.zIndexTable[obj.zIndex]; obj.zIndex = targetZIndex; objLayer.zIndexTable[parseInt(targetZIndex.toString(), 10)] = obj.id; } /** * addChildToContainer method\ * * @returns { void } addChildToContainer method .\ * @param {DiagramElement} diagram - provide the element value. * @param {boolean} parent - provide the isVertical value. * @param {PointModel} node - provide the node value. * @param {Diagram} isUndo - provide the isUndo value. * @param {boolean} historyAction - provide the historyAction value. * @param {boolean} canUpdateZindex - provide the canUpdateZindex value. * @private */ export function addChildToContainer(diagram, parent, node, isUndo, historyAction, canUpdateZindex) { if (!diagram.currentSymbol) { diagram.protectPropertyChange(true); var swimlane = diagram.nameTable[parent.parentId]; node = diagram.getObject(node.id) || node; //Bug 909155: Issue in connecting nodes with ports. //When we add child nodes at runtime and perform undo redo, the child node is not selectable as the zIndex of swimlane is higher than child node. //Added below code to update the zIndex of the child node. if (swimlane && swimlane.zIndex > node.zIndex && canUpdateZindex) { updateZindex(node, swimlane, diagram); } var child = (diagram.nodes.indexOf(node) !== -1) ? node.id : node; if (parent.container.type === 'Canvas' && !historyAction) { var left = (node.wrapper.offsetX - node.wrapper.actualSize.width * node.pivot.x) - (parent.wrapper.offsetX - parent.wrapper.actualSize.width * parent.wrapper.pivot.x); var top_1 = (node.wrapper.offsetY - node.wrapper.actualSize.height * node.pivot.y) - (parent.wrapper.offsetY - parent.wrapper.actualSize.height * parent.wrapper.pivot.y); node.margin.left = left; node.margin.top = top_1; } else if (swimlane) { var swimLaneBounds = swimlane.wrapper.bounds; var parentBounds = parent.wrapper.bounds; if (swimlane.shape.orientation === 'Horizontal') { node.margin.left -= parentBounds.x - swimLaneBounds.x; } else { var laneHeaderId = parent.parentId + swimlane.shape.lanes[0].id + '_0_header'; node.margin.top -= parentBounds.y - swimLaneBounds.y - diagram.nameTable["" + laneHeaderId].wrapper.bounds.height; } } var container = diagram.nameTable[parent.id]; if (!container.children) { container.children = []; } if (container.children.indexOf(node.id) === -1) { removeChildrenInLane(diagram, node); if (diagram.getObject(node.id)) { diagram.removeElements(node); } var undoObj = cloneObject(node); diagram.addChild(container, child); node = diagram.getObject(node.id); if (container.isLane && container.parentId) { swimlane = diagram.nameTable[container.parentId]; var lanes = swimlane.shape.lanes; var canvasId = (container.id.slice(swimlane.id.length)); var currentParentId = canvasId.substring(0, canvasId.length - 1); for (var i = 0; i < lanes.length; i++) { if (container.isLane && currentParentId === lanes[parseInt(i.toString(), 10)].id) { // eslint-disable-next-line if (node.parentObj instanceof Diagram || (node.parentObj instanceof Lane)) { // eslint-disable-next-line node.parentObj = lanes[parseInt(i.toString(), 10)]; node.propName = 'children'; } // 878719: Resolve ESLint errors // eslint-disable-next-line no-prototype-builtins if (!diagram.nameTable.hasOwnProperty(node.id)) { lanes[parseInt(i.toString(), 10)].children.push(node); } } } } diagram.updateDiagramObject(node); moveSwinLaneChild(node, diagram); if (!container.parentId) { diagram.updateDiagramObject(container); } else if (!isUndo) { if (!diagram.multiselect) { updateLaneBoundsAfterAddChild(container, swimlane, node, diagram); } else { considerSwimLanePadding(diagram, node, 20); diagram.updateDiagramElementQuad(); } } if (!(diagram.diagramActions & DiagramAction.UndoRedo)) { var entry = { type: 'ChildCollectionChanged', category: 'Internal', undoObject: undoObj, redoObject: cloneObject(node), historyAction: historyAction ? 'AddNodeToLane' : undefined }; diagram.addHistoryEntry(entry); } } else if (!isUndo && diagram.multiselect) { considerSwimLanePadding(diagram, node, 20); diagram.updateDiagramElementQuad(); } diagram.protectPropertyChange(false); } } function moveSwinLaneChild(node, diagram) { var sourceNode = getDiagramElement(node.id + '_groupElement', diagram.element.id); var targetId = (node.parentId) ? node.parentId + '_groupElement' : diagram.element.id + '_diagramLayer'; var targetNode = getDiagramElement(targetId, diagram.element.id); if (sourceNode && targetNode) { targetNode.appendChild(sourceNode); } } export function updateLaneBoundsWithSelector(container, selector, diagram, isBoundsUpdate) { var swimLane = diagram.nameTable[container.parentId]; var isSelector = true; updateLaneBoundsAfterAddChild(container, swimLane, selector, diagram, isBoundsUpdate, isSelector); } export function updateLaneBoundsAfterAddChild(container, swimLane, node, diagram, isBoundsUpdate, isSelector) { var undoObject = cloneObject(container); var isUpdateRow; var isUpdateColumn; var isGroupAction = false; var padding = swimLane.shape.padding; var containerBounds = container.wrapper.bounds; var containerOuterBounds = container.wrapper.outerBounds; var nodeBounds = node.wrapper.bounds; if (swimLane && swimLane.shape.type === 'SwimLane' && (containerBounds.right < nodeBounds.right + padding || containerBounds.bottom < nodeBounds.bottom + padding || (isSelector && containerBounds.top > nodeBounds.top + padding))) { var grid = swimLane.wrapper.children[0]; var x = grid.bounds.x; var y = grid.bounds.y; var size = void 0; var headerSize = void 0; // EJ2-913788 Drag and drop a node with more size than lane height and width var isHeader = container.wrapper.children.find(function (child) { return child.id.includes('header'); }); var isHorizontal = (swimLane.shape.orientation === 'Horizontal'); if (containerBounds.right < nodeBounds.right + padding && containerOuterBounds.x <= containerBounds.x) { if (isHorizontal && isHeader) { headerSize = isHeader ? isHeader.width : 0; size = (nodeBounds.right - containerBounds.right) + (containerBounds.left - nodeBounds.left) + headerSize + padding * 2; } else { size = (nodeBounds.right - containerBounds.right) + (containerBounds.left - nodeBounds.left) + padding * 2; } // size = nodeBounds.right - containerBounds.right; isUpdateColumn = true; grid.updateColumnWidth(container.columnIndex, containerBounds.width + size, true, padding); } if (containerBounds.bottom < nodeBounds.bottom + padding && containerOuterBounds.y <= containerBounds.y) { if (!isHorizontal && isHeader) { headerSize = isHeader ? isHeader.height : 0; size = (nodeBounds.bottom - containerBounds.bottom) + (containerBounds.top - nodeBounds.top) + headerSize + padding * 2; } else { size = (nodeBounds.bottom - containerBounds.bottom) + (containerBounds.top - nodeBounds.top) + padding * 2; } // size = nodeBounds.bottom - containerBounds.bottom; isUpdateRow = true; grid.updateRowHeight(container.rowIndex, containerBounds.height + size, true, padding); } if (isSelector && containerBounds.top > nodeBounds.top - padding && containerOuterBounds.y <= containerBounds.y) { if (!isHorizontal && isHeader) { headerSize = isHeader ? isHeader.height : 0; size = (containerBounds.top - nodeBounds.top) + (nodeBounds.bottom - containerBounds.bottom) + headerSize + padding * 2; } else { size = (containerBounds.top - nodeBounds.top) + (nodeBounds.bottom - containerBounds.bottom) + padding * 2; } // Adjust the size based on the top boundary difference if (size > 0) { isUpdateRow = true; grid.updateRowHeight(container.rowIndex, containerBounds.height + size, true, padding); } } diagram.isRowHeightUpdate = isUpdateRow; if (!(diagram.diagramActions & DiagramAction.UndoRedo)) { if (isBoundsUpdate) { diagram.startGroupAction(); isGroupAction = true; } if (isUpdateRow) { var entry = { category: 'Internal', type: 'RowHeightChanged', undoObject: undoObject, redoObject: cloneObject(container) }; diagram.addHistoryEntry(entry); } if (isUpdateColumn) { var entry = { category: 'Internal', type: 'ColumnWidthChanged', undoObject: undoObject, redoObject: cloneObject(container) }; diagram.addHistoryEntry(entry); } } swimLane.width = swimLane.wrapper.width = grid.width; swimLane.height = swimLane.wrapper.height = grid.height; swimLaneMeasureAndArrange(swimLane); if (swimLane.shape.orientation === 'Horizontal') { updatePhaseMaxWidth(swimLane, diagram, container.wrapper, container.columnIndex); } updateHeaderMaxWidth(diagram, swimLane); diagram.drag(swimLane, x - grid.bounds.x, y - grid.bounds.y); checkPhaseOffset(swimLane, diagram); checkLaneSize(swimLane); } if (!isSelector) { considerSwimLanePadding(diagram, node, padding); } diagram.updateDiagramElementQuad(); return isGroupAction; } //#endregion //# reginon stack panel interaction /** * renderStackHighlighter method\ * * @returns { void } renderStackHighlighter method .\ * @param {DiagramElement} element - provide the element value. * @param {boolean} isVertical - provide the isVertical value. * @param {PointModel} position - provide the position value. * @param {Diagram} diagram - provide the diagram value. * @param {boolean} isUml - provide the isUml value. * @param {boolean} isSwimlane - provide the isSwimlane value. * @private */ export function renderStackHighlighter(element, isVertical, position, diagram, isUml, isSwimlane) { var adornerSvg = getAdornerLayerSvg(diagram.element.id); diagram.diagramRenderer.renderStackHighlighter(element, adornerSvg, diagram.scroller.transform, isVertical, position, isUml, isSwimlane); } /** * moveChildInStack method\ * * @returns { void } moveChildInStack method .\ * @param {Node} sourceNode - provide the sourceNode value. * @param {Node} target - provide the target value. * @param {Diagram} diagram - provide the diagram value. * @param {Actions} action - provide the action value. * @private */ export function moveChildInStack(sourceNode, target, diagram, action) { var obj = sourceNode; var parent = diagram.nameTable[obj.parentId]; var sourceParent = diagram.nameTable[obj.parentId]; if (target && sourceParent && sourceParent.container && sourceParent.container.type === 'Stack' && target.container && target.container.type === 'Stack' && (sourceParent.id !== target.parentId)) { var value = sourceParent.wrapper.children.indexOf(obj.wrapper); if (value > -1) { diagram.nameTable[obj.id].parentId = target.id; sourceParent.wrapper.children.splice(value, 1); } } if (target && target.parentId && obj.parentId && action === 'Drag' && sourceParent.container && sourceParent.container.type === 'Stack') { var targetIndex = parent.wrapper.children.indexOf(target.wrapper); var sourceIndex = parent.wrapper.children.indexOf(obj.wrapper); var undoElement = { targetIndex: targetIndex, target: target, sourceIndex: sourceIndex, source: sourceNode }; parent.wrapper.children.splice(sourceIndex, 1); parent.wrapper.children.splice(targetIndex, 0, obj.wrapper); var redoElement = { targetIndex: sourceIndex, target: target, sourceIndex: targetIndex, source: sourceNode }; var entry = { type: 'StackChildPositionChanged', redoObject: redoElement, undoObject: undoElement, category: 'Internal' }; diagram.commandHandler.addHistoryEntry(entry); } } //#end region //# region Swimlane rendering //#end region