UNPKG

@maxgraph/core

Version:

maxGraph is a fully client side JavaScript diagramming library that uses SVG and HTML for rendering.

179 lines (175 loc) 6.6 kB
"use strict"; /* Copyright 2022-present The maxGraph project Contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.cloneCells = exports.cloneCell = exports.getParents = exports.getTopmostCells = exports.getOpposites = void 0; const ObjectIdentity_js_1 = __importDefault(require("./ObjectIdentity.js")); /** * Returns all opposite vertices terminal for the given edges, only returning sources and/or targets as specified. * The result is returned as an array of {@link Cell}. * * @param edges Array of {Cell} that contain the edges to be examined. * @param {Cell} terminal that specifies the known end of the edges. * @param includeSources Boolean that specifies if source terminals should be included in the result. Default is `true`. * @param includeTargets Boolean that specifies if target terminals should be included in the result. Default is `true`. */ const getOpposites = (edges, terminal, includeSources = true, includeTargets = true) => { return edges.reduce((terminals, edge) => { const source = edge.getTerminal(true); const target = edge.getTerminal(false); // Checks if the terminal is the source of the edge and if the target should be stored in the result if (source === terminal && target != null && target !== terminal && includeTargets) { terminals.push(target); } // Checks if the terminal is the target of the edge and if the source should be stored in the result else if (target === terminal && source != null && source !== terminal && includeSources) { terminals.push(source); } return terminals; }, []); }; exports.getOpposites = getOpposites; /** * Returns the topmost cells of the hierarchy in an array that contains no * descendants for each {@link Cell} that it contains. Duplicates should be * removed in the cells array to improve performance. */ const getTopmostCells = (cells) => { const coveredEntries = new Map(); const tmp = []; for (let i = 0; i < cells.length; i += 1) { coveredEntries.set(cells[i], true); } for (let i = 0; i < cells.length; i += 1) { const cell = cells[i]; let topmost = true; let parent = cell.getParent(); while (parent != null) { if (coveredEntries.get(parent)) { topmost = false; break; } parent = parent.getParent(); } if (topmost) { tmp.push(cell); } } return tmp; }; exports.getTopmostCells = getTopmostCells; /** * Returns an array that represents the set (no duplicates) of all parents * for the given array of cells. */ const getParents = (cells) => { const parents = []; const coveredParents = new Map(); for (const cell of cells) { const parent = cell.getParent(); if (parent && !coveredParents.get(parent)) { coveredParents.set(parent, true); parents.push(parent); } } return parents; }; exports.getParents = getParents; /** * Returns a deep clone of the given {@link Cell}` (including the children) which is created using {@link cloneCells}`. * * @param cell {@link Cell} to be cloned. Default is `null`. * @param includeChildren Boolean indicating if the cells should be cloned with all descendants. Default is `true`. */ const cloneCell = (cell = null, includeChildren = true) => { if (!cell) { return null; } return (0, exports.cloneCells)([cell], includeChildren)[0]; }; exports.cloneCell = cloneCell; /** * Returns an array of clones for the given array of {@link Cell}`. * Depending on the value of includeChildren, a deep clone is created for * each cell. Connections are restored based if the corresponding * cell is contained in the provided in array. * * @param cells The cells to clone * @param includeChildren Boolean indicating if the cells should be cloned with all descendants. * @param mapping Optional mapping for existing clones. */ const cloneCells = (cells, includeChildren = true, mapping = {}) => { const clones = []; for (const cell of cells) { clones.push(cloneCellImpl(cell, mapping, includeChildren)); } for (let i = 0; i < clones.length; i += 1) { if (clones[i] != null) { restoreClone(clones[i], cells[i], mapping); } } return clones; }; exports.cloneCells = cloneCells; /** * Inner helper method for cloning cells recursively. * * @private */ const cloneCellImpl = (cell, mapping = {}, includeChildren = false) => { const identity = ObjectIdentity_js_1.default.get(cell); let clone = mapping ? mapping[identity] : null; if (clone == null) { clone = cell.clone(); mapping[identity] = clone; if (includeChildren) { const childCount = cell.getChildCount(); for (let i = 0; i < childCount; i += 1) { const cloneChild = cloneCellImpl(cell.getChildAt(i), mapping, true); clone.insert(cloneChild); } } } return clone; }; /** * Inner helper method for restoring the connections in a network of cloned cells. * * @private */ const restoreClone = (clone, cell, mapping) => { const source = cell.getTerminal(true); if (source != null) { const tmp = mapping[ObjectIdentity_js_1.default.get(source)]; if (tmp != null) { tmp.insertEdge(clone, true); } } const target = cell.getTerminal(false); if (target != null) { const tmp = mapping[ObjectIdentity_js_1.default.get(target)]; if (tmp != null) { tmp.insertEdge(clone, false); } } const childCount = clone.getChildCount(); for (let i = 0; i < childCount; i += 1) { restoreClone(clone.getChildAt(i), cell.getChildAt(i), mapping); } };