UNPKG

pareto-anywhere

Version:

Open source IoT middleware suite that makes the data from just about anything usable. We believe in an open Internet of Things.

1,916 lines (1,566 loc) 148 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["layoutBase"] = factory(); else root["layoutBase"] = factory(); })(this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // identity function for calling harmony imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 28); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; function LayoutConstants() {} /** * Layout Quality: 0:draft, 1:default, 2:proof */ LayoutConstants.QUALITY = 1; /** * Default parameters */ LayoutConstants.DEFAULT_CREATE_BENDS_AS_NEEDED = false; LayoutConstants.DEFAULT_INCREMENTAL = false; LayoutConstants.DEFAULT_ANIMATION_ON_LAYOUT = true; LayoutConstants.DEFAULT_ANIMATION_DURING_LAYOUT = false; LayoutConstants.DEFAULT_ANIMATION_PERIOD = 50; LayoutConstants.DEFAULT_UNIFORM_LEAF_NODE_SIZES = false; // ----------------------------------------------------------------------------- // Section: General other constants // ----------------------------------------------------------------------------- /* * Margins of a graph to be applied on bouding rectangle of its contents. We * assume margins on all four sides to be uniform. */ LayoutConstants.DEFAULT_GRAPH_MARGIN = 15; /* * Whether to consider labels in node dimensions or not */ LayoutConstants.NODE_DIMENSIONS_INCLUDE_LABELS = false; /* * Default dimension of a non-compound node. */ LayoutConstants.SIMPLE_NODE_SIZE = 40; /* * Default dimension of a non-compound node. */ LayoutConstants.SIMPLE_NODE_HALF_SIZE = LayoutConstants.SIMPLE_NODE_SIZE / 2; /* * Empty compound node size. When a compound node is empty, its both * dimensions should be of this value. */ LayoutConstants.EMPTY_COMPOUND_NODE_SIZE = 40; /* * Minimum length that an edge should take during layout */ LayoutConstants.MIN_EDGE_LENGTH = 1; /* * World boundaries that layout operates on */ LayoutConstants.WORLD_BOUNDARY = 1000000; /* * World boundaries that random positioning can be performed with */ LayoutConstants.INITIAL_WORLD_BOUNDARY = LayoutConstants.WORLD_BOUNDARY / 1000; /* * Coordinates of the world center */ LayoutConstants.WORLD_CENTER_X = 1200; LayoutConstants.WORLD_CENTER_Y = 900; module.exports = LayoutConstants; /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var LGraphObject = __webpack_require__(2); var IGeometry = __webpack_require__(8); var IMath = __webpack_require__(9); function LEdge(source, target, vEdge) { LGraphObject.call(this, vEdge); this.isOverlapingSourceAndTarget = false; this.vGraphObject = vEdge; this.bendpoints = []; this.source = source; this.target = target; } LEdge.prototype = Object.create(LGraphObject.prototype); for (var prop in LGraphObject) { LEdge[prop] = LGraphObject[prop]; } LEdge.prototype.getSource = function () { return this.source; }; LEdge.prototype.getTarget = function () { return this.target; }; LEdge.prototype.isInterGraph = function () { return this.isInterGraph; }; LEdge.prototype.getLength = function () { return this.length; }; LEdge.prototype.isOverlapingSourceAndTarget = function () { return this.isOverlapingSourceAndTarget; }; LEdge.prototype.getBendpoints = function () { return this.bendpoints; }; LEdge.prototype.getLca = function () { return this.lca; }; LEdge.prototype.getSourceInLca = function () { return this.sourceInLca; }; LEdge.prototype.getTargetInLca = function () { return this.targetInLca; }; LEdge.prototype.getOtherEnd = function (node) { if (this.source === node) { return this.target; } else if (this.target === node) { return this.source; } else { throw "Node is not incident with this edge"; } }; LEdge.prototype.getOtherEndInGraph = function (node, graph) { var otherEnd = this.getOtherEnd(node); var root = graph.getGraphManager().getRoot(); while (true) { if (otherEnd.getOwner() == graph) { return otherEnd; } if (otherEnd.getOwner() == root) { break; } otherEnd = otherEnd.getOwner().getParent(); } return null; }; LEdge.prototype.updateLength = function () { var clipPointCoordinates = new Array(4); this.isOverlapingSourceAndTarget = IGeometry.getIntersection(this.target.getRect(), this.source.getRect(), clipPointCoordinates); if (!this.isOverlapingSourceAndTarget) { this.lengthX = clipPointCoordinates[0] - clipPointCoordinates[2]; this.lengthY = clipPointCoordinates[1] - clipPointCoordinates[3]; if (Math.abs(this.lengthX) < 1.0) { this.lengthX = IMath.sign(this.lengthX); } if (Math.abs(this.lengthY) < 1.0) { this.lengthY = IMath.sign(this.lengthY); } this.length = Math.sqrt(this.lengthX * this.lengthX + this.lengthY * this.lengthY); } }; LEdge.prototype.updateLengthSimple = function () { this.lengthX = this.target.getCenterX() - this.source.getCenterX(); this.lengthY = this.target.getCenterY() - this.source.getCenterY(); if (Math.abs(this.lengthX) < 1.0) { this.lengthX = IMath.sign(this.lengthX); } if (Math.abs(this.lengthY) < 1.0) { this.lengthY = IMath.sign(this.lengthY); } this.length = Math.sqrt(this.lengthX * this.lengthX + this.lengthY * this.lengthY); }; module.exports = LEdge; /***/ }), /* 2 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; function LGraphObject(vGraphObject) { this.vGraphObject = vGraphObject; } module.exports = LGraphObject; /***/ }), /* 3 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var LGraphObject = __webpack_require__(2); var Integer = __webpack_require__(10); var RectangleD = __webpack_require__(13); var LayoutConstants = __webpack_require__(0); var RandomSeed = __webpack_require__(16); var PointD = __webpack_require__(5); function LNode(gm, loc, size, vNode) { //Alternative constructor 1 : LNode(LGraphManager gm, Point loc, Dimension size, Object vNode) if (size == null && vNode == null) { vNode = loc; } LGraphObject.call(this, vNode); //Alternative constructor 2 : LNode(Layout layout, Object vNode) if (gm.graphManager != null) gm = gm.graphManager; this.estimatedSize = Integer.MIN_VALUE; this.inclusionTreeDepth = Integer.MAX_VALUE; this.vGraphObject = vNode; this.edges = []; this.graphManager = gm; if (size != null && loc != null) this.rect = new RectangleD(loc.x, loc.y, size.width, size.height);else this.rect = new RectangleD(); } LNode.prototype = Object.create(LGraphObject.prototype); for (var prop in LGraphObject) { LNode[prop] = LGraphObject[prop]; } LNode.prototype.getEdges = function () { return this.edges; }; LNode.prototype.getChild = function () { return this.child; }; LNode.prototype.getOwner = function () { // if (this.owner != null) { // if (!(this.owner == null || this.owner.getNodes().indexOf(this) > -1)) { // throw "assert failed"; // } // } return this.owner; }; LNode.prototype.getWidth = function () { return this.rect.width; }; LNode.prototype.setWidth = function (width) { this.rect.width = width; }; LNode.prototype.getHeight = function () { return this.rect.height; }; LNode.prototype.setHeight = function (height) { this.rect.height = height; }; LNode.prototype.getCenterX = function () { return this.rect.x + this.rect.width / 2; }; LNode.prototype.getCenterY = function () { return this.rect.y + this.rect.height / 2; }; LNode.prototype.getCenter = function () { return new PointD(this.rect.x + this.rect.width / 2, this.rect.y + this.rect.height / 2); }; LNode.prototype.getLocation = function () { return new PointD(this.rect.x, this.rect.y); }; LNode.prototype.getRect = function () { return this.rect; }; LNode.prototype.getDiagonal = function () { return Math.sqrt(this.rect.width * this.rect.width + this.rect.height * this.rect.height); }; /** * This method returns half the diagonal length of this node. */ LNode.prototype.getHalfTheDiagonal = function () { return Math.sqrt(this.rect.height * this.rect.height + this.rect.width * this.rect.width) / 2; }; LNode.prototype.setRect = function (upperLeft, dimension) { this.rect.x = upperLeft.x; this.rect.y = upperLeft.y; this.rect.width = dimension.width; this.rect.height = dimension.height; }; LNode.prototype.setCenter = function (cx, cy) { this.rect.x = cx - this.rect.width / 2; this.rect.y = cy - this.rect.height / 2; }; LNode.prototype.setLocation = function (x, y) { this.rect.x = x; this.rect.y = y; }; LNode.prototype.moveBy = function (dx, dy) { this.rect.x += dx; this.rect.y += dy; }; LNode.prototype.getEdgeListToNode = function (to) { var edgeList = []; var edge; var self = this; self.edges.forEach(function (edge) { if (edge.target == to) { if (edge.source != self) throw "Incorrect edge source!"; edgeList.push(edge); } }); return edgeList; }; LNode.prototype.getEdgesBetween = function (other) { var edgeList = []; var edge; var self = this; self.edges.forEach(function (edge) { if (!(edge.source == self || edge.target == self)) throw "Incorrect edge source and/or target"; if (edge.target == other || edge.source == other) { edgeList.push(edge); } }); return edgeList; }; LNode.prototype.getNeighborsList = function () { var neighbors = new Set(); var self = this; self.edges.forEach(function (edge) { if (edge.source == self) { neighbors.add(edge.target); } else { if (edge.target != self) { throw "Incorrect incidency!"; } neighbors.add(edge.source); } }); return neighbors; }; LNode.prototype.withChildren = function () { var withNeighborsList = new Set(); var childNode; var children; withNeighborsList.add(this); if (this.child != null) { var nodes = this.child.getNodes(); for (var i = 0; i < nodes.length; i++) { childNode = nodes[i]; children = childNode.withChildren(); children.forEach(function (node) { withNeighborsList.add(node); }); } } return withNeighborsList; }; LNode.prototype.getNoOfChildren = function () { var noOfChildren = 0; var childNode; if (this.child == null) { noOfChildren = 1; } else { var nodes = this.child.getNodes(); for (var i = 0; i < nodes.length; i++) { childNode = nodes[i]; noOfChildren += childNode.getNoOfChildren(); } } if (noOfChildren == 0) { noOfChildren = 1; } return noOfChildren; }; LNode.prototype.getEstimatedSize = function () { if (this.estimatedSize == Integer.MIN_VALUE) { throw "assert failed"; } return this.estimatedSize; }; LNode.prototype.calcEstimatedSize = function () { if (this.child == null) { return this.estimatedSize = (this.rect.width + this.rect.height) / 2; } else { this.estimatedSize = this.child.calcEstimatedSize(); this.rect.width = this.estimatedSize; this.rect.height = this.estimatedSize; return this.estimatedSize; } }; LNode.prototype.scatter = function () { var randomCenterX; var randomCenterY; var minX = -LayoutConstants.INITIAL_WORLD_BOUNDARY; var maxX = LayoutConstants.INITIAL_WORLD_BOUNDARY; randomCenterX = LayoutConstants.WORLD_CENTER_X + RandomSeed.nextDouble() * (maxX - minX) + minX; var minY = -LayoutConstants.INITIAL_WORLD_BOUNDARY; var maxY = LayoutConstants.INITIAL_WORLD_BOUNDARY; randomCenterY = LayoutConstants.WORLD_CENTER_Y + RandomSeed.nextDouble() * (maxY - minY) + minY; this.rect.x = randomCenterX; this.rect.y = randomCenterY; }; LNode.prototype.updateBounds = function () { if (this.getChild() == null) { throw "assert failed"; } if (this.getChild().getNodes().length != 0) { // wrap the children nodes by re-arranging the boundaries var childGraph = this.getChild(); childGraph.updateBounds(true); this.rect.x = childGraph.getLeft(); this.rect.y = childGraph.getTop(); this.setWidth(childGraph.getRight() - childGraph.getLeft()); this.setHeight(childGraph.getBottom() - childGraph.getTop()); // Update compound bounds considering its label properties if (LayoutConstants.NODE_DIMENSIONS_INCLUDE_LABELS) { var width = childGraph.getRight() - childGraph.getLeft(); var height = childGraph.getBottom() - childGraph.getTop(); if (this.labelWidth) { if (this.labelPosHorizontal == "left") { this.rect.x -= this.labelWidth; this.setWidth(width + this.labelWidth); } else if (this.labelPosHorizontal == "center" && this.labelWidth > width) { this.rect.x -= (this.labelWidth - width) / 2; this.setWidth(this.labelWidth); } else if (this.labelPosHorizontal == "right") { this.setWidth(width + this.labelWidth); } } if (this.labelHeight) { if (this.labelPosVertical == "top") { this.rect.y -= this.labelHeight; this.setHeight(height + this.labelHeight); } else if (this.labelPosVertical == "center" && this.labelHeight > height) { this.rect.y -= (this.labelHeight - height) / 2; this.setHeight(this.labelHeight); } else if (this.labelPosVertical == "bottom") { this.setHeight(height + this.labelHeight); } } } } }; LNode.prototype.getInclusionTreeDepth = function () { if (this.inclusionTreeDepth == Integer.MAX_VALUE) { throw "assert failed"; } return this.inclusionTreeDepth; }; LNode.prototype.transform = function (trans) { var left = this.rect.x; if (left > LayoutConstants.WORLD_BOUNDARY) { left = LayoutConstants.WORLD_BOUNDARY; } else if (left < -LayoutConstants.WORLD_BOUNDARY) { left = -LayoutConstants.WORLD_BOUNDARY; } var top = this.rect.y; if (top > LayoutConstants.WORLD_BOUNDARY) { top = LayoutConstants.WORLD_BOUNDARY; } else if (top < -LayoutConstants.WORLD_BOUNDARY) { top = -LayoutConstants.WORLD_BOUNDARY; } var leftTop = new PointD(left, top); var vLeftTop = trans.inverseTransformPoint(leftTop); this.setLocation(vLeftTop.x, vLeftTop.y); }; LNode.prototype.getLeft = function () { return this.rect.x; }; LNode.prototype.getRight = function () { return this.rect.x + this.rect.width; }; LNode.prototype.getTop = function () { return this.rect.y; }; LNode.prototype.getBottom = function () { return this.rect.y + this.rect.height; }; LNode.prototype.getParent = function () { if (this.owner == null) { return null; } return this.owner.getParent(); }; module.exports = LNode; /***/ }), /* 4 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var LayoutConstants = __webpack_require__(0); function FDLayoutConstants() {} //FDLayoutConstants inherits static props in LayoutConstants for (var prop in LayoutConstants) { FDLayoutConstants[prop] = LayoutConstants[prop]; } FDLayoutConstants.MAX_ITERATIONS = 2500; FDLayoutConstants.DEFAULT_EDGE_LENGTH = 50; FDLayoutConstants.DEFAULT_SPRING_STRENGTH = 0.45; FDLayoutConstants.DEFAULT_REPULSION_STRENGTH = 4500.0; FDLayoutConstants.DEFAULT_GRAVITY_STRENGTH = 0.4; FDLayoutConstants.DEFAULT_COMPOUND_GRAVITY_STRENGTH = 1.0; FDLayoutConstants.DEFAULT_GRAVITY_RANGE_FACTOR = 3.8; FDLayoutConstants.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR = 1.5; FDLayoutConstants.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION = true; FDLayoutConstants.DEFAULT_USE_SMART_REPULSION_RANGE_CALCULATION = true; FDLayoutConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL = 0.3; FDLayoutConstants.COOLING_ADAPTATION_FACTOR = 0.33; FDLayoutConstants.ADAPTATION_LOWER_NODE_LIMIT = 1000; FDLayoutConstants.ADAPTATION_UPPER_NODE_LIMIT = 5000; FDLayoutConstants.MAX_NODE_DISPLACEMENT_INCREMENTAL = 100.0; FDLayoutConstants.MAX_NODE_DISPLACEMENT = FDLayoutConstants.MAX_NODE_DISPLACEMENT_INCREMENTAL * 3; FDLayoutConstants.MIN_REPULSION_DIST = FDLayoutConstants.DEFAULT_EDGE_LENGTH / 10.0; FDLayoutConstants.CONVERGENCE_CHECK_PERIOD = 100; FDLayoutConstants.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR = 0.1; FDLayoutConstants.MIN_EDGE_LENGTH = 1; FDLayoutConstants.GRID_CALCULATION_CHECK_PERIOD = 10; module.exports = FDLayoutConstants; /***/ }), /* 5 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; function PointD(x, y) { if (x == null && y == null) { this.x = 0; this.y = 0; } else { this.x = x; this.y = y; } } PointD.prototype.getX = function () { return this.x; }; PointD.prototype.getY = function () { return this.y; }; PointD.prototype.setX = function (x) { this.x = x; }; PointD.prototype.setY = function (y) { this.y = y; }; PointD.prototype.getDifference = function (pt) { return new DimensionD(this.x - pt.x, this.y - pt.y); }; PointD.prototype.getCopy = function () { return new PointD(this.x, this.y); }; PointD.prototype.translate = function (dim) { this.x += dim.width; this.y += dim.height; return this; }; module.exports = PointD; /***/ }), /* 6 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var LGraphObject = __webpack_require__(2); var Integer = __webpack_require__(10); var LayoutConstants = __webpack_require__(0); var LGraphManager = __webpack_require__(7); var LNode = __webpack_require__(3); var LEdge = __webpack_require__(1); var RectangleD = __webpack_require__(13); var Point = __webpack_require__(12); var LinkedList = __webpack_require__(11); function LGraph(parent, obj2, vGraph) { LGraphObject.call(this, vGraph); this.estimatedSize = Integer.MIN_VALUE; this.margin = LayoutConstants.DEFAULT_GRAPH_MARGIN; this.edges = []; this.nodes = []; this.isConnected = false; this.parent = parent; if (obj2 != null && obj2 instanceof LGraphManager) { this.graphManager = obj2; } else if (obj2 != null && obj2 instanceof Layout) { this.graphManager = obj2.graphManager; } } LGraph.prototype = Object.create(LGraphObject.prototype); for (var prop in LGraphObject) { LGraph[prop] = LGraphObject[prop]; } LGraph.prototype.getNodes = function () { return this.nodes; }; LGraph.prototype.getEdges = function () { return this.edges; }; LGraph.prototype.getGraphManager = function () { return this.graphManager; }; LGraph.prototype.getParent = function () { return this.parent; }; LGraph.prototype.getLeft = function () { return this.left; }; LGraph.prototype.getRight = function () { return this.right; }; LGraph.prototype.getTop = function () { return this.top; }; LGraph.prototype.getBottom = function () { return this.bottom; }; LGraph.prototype.isConnected = function () { return this.isConnected; }; LGraph.prototype.add = function (obj1, sourceNode, targetNode) { if (sourceNode == null && targetNode == null) { var newNode = obj1; if (this.graphManager == null) { throw "Graph has no graph mgr!"; } if (this.getNodes().indexOf(newNode) > -1) { throw "Node already in graph!"; } newNode.owner = this; this.getNodes().push(newNode); return newNode; } else { var newEdge = obj1; if (!(this.getNodes().indexOf(sourceNode) > -1 && this.getNodes().indexOf(targetNode) > -1)) { throw "Source or target not in graph!"; } if (!(sourceNode.owner == targetNode.owner && sourceNode.owner == this)) { throw "Both owners must be this graph!"; } if (sourceNode.owner != targetNode.owner) { return null; } // set source and target newEdge.source = sourceNode; newEdge.target = targetNode; // set as intra-graph edge newEdge.isInterGraph = false; // add to graph edge list this.getEdges().push(newEdge); // add to incidency lists sourceNode.edges.push(newEdge); if (targetNode != sourceNode) { targetNode.edges.push(newEdge); } return newEdge; } }; LGraph.prototype.remove = function (obj) { var node = obj; if (obj instanceof LNode) { if (node == null) { throw "Node is null!"; } if (!(node.owner != null && node.owner == this)) { throw "Owner graph is invalid!"; } if (this.graphManager == null) { throw "Owner graph manager is invalid!"; } // remove incident edges first (make a copy to do it safely) var edgesToBeRemoved = node.edges.slice(); var edge; var s = edgesToBeRemoved.length; for (var i = 0; i < s; i++) { edge = edgesToBeRemoved[i]; if (edge.isInterGraph) { this.graphManager.remove(edge); } else { edge.source.owner.remove(edge); } } // now the node itself var index = this.nodes.indexOf(node); if (index == -1) { throw "Node not in owner node list!"; } this.nodes.splice(index, 1); } else if (obj instanceof LEdge) { var edge = obj; if (edge == null) { throw "Edge is null!"; } if (!(edge.source != null && edge.target != null)) { throw "Source and/or target is null!"; } if (!(edge.source.owner != null && edge.target.owner != null && edge.source.owner == this && edge.target.owner == this)) { throw "Source and/or target owner is invalid!"; } var sourceIndex = edge.source.edges.indexOf(edge); var targetIndex = edge.target.edges.indexOf(edge); if (!(sourceIndex > -1 && targetIndex > -1)) { throw "Source and/or target doesn't know this edge!"; } edge.source.edges.splice(sourceIndex, 1); if (edge.target != edge.source) { edge.target.edges.splice(targetIndex, 1); } var index = edge.source.owner.getEdges().indexOf(edge); if (index == -1) { throw "Not in owner's edge list!"; } edge.source.owner.getEdges().splice(index, 1); } }; LGraph.prototype.updateLeftTop = function () { var top = Integer.MAX_VALUE; var left = Integer.MAX_VALUE; var nodeTop; var nodeLeft; var margin; var nodes = this.getNodes(); var s = nodes.length; for (var i = 0; i < s; i++) { var lNode = nodes[i]; nodeTop = lNode.getTop(); nodeLeft = lNode.getLeft(); if (top > nodeTop) { top = nodeTop; } if (left > nodeLeft) { left = nodeLeft; } } // Do we have any nodes in this graph? if (top == Integer.MAX_VALUE) { return null; } if (nodes[0].getParent().paddingLeft != undefined) { margin = nodes[0].getParent().paddingLeft; } else { margin = this.margin; } this.left = left - margin; this.top = top - margin; // Apply the margins and return the result return new Point(this.left, this.top); }; LGraph.prototype.updateBounds = function (recursive) { // calculate bounds var left = Integer.MAX_VALUE; var right = -Integer.MAX_VALUE; var top = Integer.MAX_VALUE; var bottom = -Integer.MAX_VALUE; var nodeLeft; var nodeRight; var nodeTop; var nodeBottom; var margin; var nodes = this.nodes; var s = nodes.length; for (var i = 0; i < s; i++) { var lNode = nodes[i]; if (recursive && lNode.child != null) { lNode.updateBounds(); } nodeLeft = lNode.getLeft(); nodeRight = lNode.getRight(); nodeTop = lNode.getTop(); nodeBottom = lNode.getBottom(); if (left > nodeLeft) { left = nodeLeft; } if (right < nodeRight) { right = nodeRight; } if (top > nodeTop) { top = nodeTop; } if (bottom < nodeBottom) { bottom = nodeBottom; } } var boundingRect = new RectangleD(left, top, right - left, bottom - top); if (left == Integer.MAX_VALUE) { this.left = this.parent.getLeft(); this.right = this.parent.getRight(); this.top = this.parent.getTop(); this.bottom = this.parent.getBottom(); } if (nodes[0].getParent().paddingLeft != undefined) { margin = nodes[0].getParent().paddingLeft; } else { margin = this.margin; } this.left = boundingRect.x - margin; this.right = boundingRect.x + boundingRect.width + margin; this.top = boundingRect.y - margin; this.bottom = boundingRect.y + boundingRect.height + margin; }; LGraph.calculateBounds = function (nodes) { var left = Integer.MAX_VALUE; var right = -Integer.MAX_VALUE; var top = Integer.MAX_VALUE; var bottom = -Integer.MAX_VALUE; var nodeLeft; var nodeRight; var nodeTop; var nodeBottom; var s = nodes.length; for (var i = 0; i < s; i++) { var lNode = nodes[i]; nodeLeft = lNode.getLeft(); nodeRight = lNode.getRight(); nodeTop = lNode.getTop(); nodeBottom = lNode.getBottom(); if (left > nodeLeft) { left = nodeLeft; } if (right < nodeRight) { right = nodeRight; } if (top > nodeTop) { top = nodeTop; } if (bottom < nodeBottom) { bottom = nodeBottom; } } var boundingRect = new RectangleD(left, top, right - left, bottom - top); return boundingRect; }; LGraph.prototype.getInclusionTreeDepth = function () { if (this == this.graphManager.getRoot()) { return 1; } else { return this.parent.getInclusionTreeDepth(); } }; LGraph.prototype.getEstimatedSize = function () { if (this.estimatedSize == Integer.MIN_VALUE) { throw "assert failed"; } return this.estimatedSize; }; LGraph.prototype.calcEstimatedSize = function () { var size = 0; var nodes = this.nodes; var s = nodes.length; for (var i = 0; i < s; i++) { var lNode = nodes[i]; size += lNode.calcEstimatedSize(); } if (size == 0) { this.estimatedSize = LayoutConstants.EMPTY_COMPOUND_NODE_SIZE; } else { this.estimatedSize = size / Math.sqrt(this.nodes.length); } return this.estimatedSize; }; LGraph.prototype.updateConnected = function () { var self = this; if (this.nodes.length == 0) { this.isConnected = true; return; } var queue = new LinkedList(); var visited = new Set(); var currentNode = this.nodes[0]; var neighborEdges; var currentNeighbor; var childrenOfNode = currentNode.withChildren(); childrenOfNode.forEach(function (node) { queue.push(node); visited.add(node); }); while (queue.length !== 0) { currentNode = queue.shift(); // Traverse all neighbors of this node neighborEdges = currentNode.getEdges(); var size = neighborEdges.length; for (var i = 0; i < size; i++) { var neighborEdge = neighborEdges[i]; currentNeighbor = neighborEdge.getOtherEndInGraph(currentNode, this); // Add unvisited neighbors to the list to visit if (currentNeighbor != null && !visited.has(currentNeighbor)) { var childrenOfNeighbor = currentNeighbor.withChildren(); childrenOfNeighbor.forEach(function (node) { queue.push(node); visited.add(node); }); } } } this.isConnected = false; if (visited.size >= this.nodes.length) { var noOfVisitedInThisGraph = 0; visited.forEach(function (visitedNode) { if (visitedNode.owner == self) { noOfVisitedInThisGraph++; } }); if (noOfVisitedInThisGraph == this.nodes.length) { this.isConnected = true; } } }; module.exports = LGraph; /***/ }), /* 7 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var LGraph; var LEdge = __webpack_require__(1); function LGraphManager(layout) { LGraph = __webpack_require__(6); // It may be better to initilize this out of this function but it gives an error (Right-hand side of 'instanceof' is not callable) now. this.layout = layout; this.graphs = []; this.edges = []; } LGraphManager.prototype.addRoot = function () { var ngraph = this.layout.newGraph(); var nnode = this.layout.newNode(null); var root = this.add(ngraph, nnode); this.setRootGraph(root); return this.rootGraph; }; LGraphManager.prototype.add = function (newGraph, parentNode, newEdge, sourceNode, targetNode) { //there are just 2 parameters are passed then it adds an LGraph else it adds an LEdge if (newEdge == null && sourceNode == null && targetNode == null) { if (newGraph == null) { throw "Graph is null!"; } if (parentNode == null) { throw "Parent node is null!"; } if (this.graphs.indexOf(newGraph) > -1) { throw "Graph already in this graph mgr!"; } this.graphs.push(newGraph); if (newGraph.parent != null) { throw "Already has a parent!"; } if (parentNode.child != null) { throw "Already has a child!"; } newGraph.parent = parentNode; parentNode.child = newGraph; return newGraph; } else { //change the order of the parameters targetNode = newEdge; sourceNode = parentNode; newEdge = newGraph; var sourceGraph = sourceNode.getOwner(); var targetGraph = targetNode.getOwner(); if (!(sourceGraph != null && sourceGraph.getGraphManager() == this)) { throw "Source not in this graph mgr!"; } if (!(targetGraph != null && targetGraph.getGraphManager() == this)) { throw "Target not in this graph mgr!"; } if (sourceGraph == targetGraph) { newEdge.isInterGraph = false; return sourceGraph.add(newEdge, sourceNode, targetNode); } else { newEdge.isInterGraph = true; // set source and target newEdge.source = sourceNode; newEdge.target = targetNode; // add edge to inter-graph edge list if (this.edges.indexOf(newEdge) > -1) { throw "Edge already in inter-graph edge list!"; } this.edges.push(newEdge); // add edge to source and target incidency lists if (!(newEdge.source != null && newEdge.target != null)) { throw "Edge source and/or target is null!"; } if (!(newEdge.source.edges.indexOf(newEdge) == -1 && newEdge.target.edges.indexOf(newEdge) == -1)) { throw "Edge already in source and/or target incidency list!"; } newEdge.source.edges.push(newEdge); newEdge.target.edges.push(newEdge); return newEdge; } } }; LGraphManager.prototype.remove = function (lObj) { if (lObj instanceof LGraph) { var graph = lObj; if (graph.getGraphManager() != this) { throw "Graph not in this graph mgr"; } if (!(graph == this.rootGraph || graph.parent != null && graph.parent.graphManager == this)) { throw "Invalid parent node!"; } // first the edges (make a copy to do it safely) var edgesToBeRemoved = []; edgesToBeRemoved = edgesToBeRemoved.concat(graph.getEdges()); var edge; var s = edgesToBeRemoved.length; for (var i = 0; i < s; i++) { edge = edgesToBeRemoved[i]; graph.remove(edge); } // then the nodes (make a copy to do it safely) var nodesToBeRemoved = []; nodesToBeRemoved = nodesToBeRemoved.concat(graph.getNodes()); var node; s = nodesToBeRemoved.length; for (var i = 0; i < s; i++) { node = nodesToBeRemoved[i]; graph.remove(node); } // check if graph is the root if (graph == this.rootGraph) { this.setRootGraph(null); } // now remove the graph itself var index = this.graphs.indexOf(graph); this.graphs.splice(index, 1); // also reset the parent of the graph graph.parent = null; } else if (lObj instanceof LEdge) { edge = lObj; if (edge == null) { throw "Edge is null!"; } if (!edge.isInterGraph) { throw "Not an inter-graph edge!"; } if (!(edge.source != null && edge.target != null)) { throw "Source and/or target is null!"; } // remove edge from source and target nodes' incidency lists if (!(edge.source.edges.indexOf(edge) != -1 && edge.target.edges.indexOf(edge) != -1)) { throw "Source and/or target doesn't know this edge!"; } var index = edge.source.edges.indexOf(edge); edge.source.edges.splice(index, 1); index = edge.target.edges.indexOf(edge); edge.target.edges.splice(index, 1); // remove edge from owner graph manager's inter-graph edge list if (!(edge.source.owner != null && edge.source.owner.getGraphManager() != null)) { throw "Edge owner graph or owner graph manager is null!"; } if (edge.source.owner.getGraphManager().edges.indexOf(edge) == -1) { throw "Not in owner graph manager's edge list!"; } var index = edge.source.owner.getGraphManager().edges.indexOf(edge); edge.source.owner.getGraphManager().edges.splice(index, 1); } }; LGraphManager.prototype.updateBounds = function () { this.rootGraph.updateBounds(true); }; LGraphManager.prototype.getGraphs = function () { return this.graphs; }; LGraphManager.prototype.getAllNodes = function () { if (this.allNodes == null) { var nodeList = []; var graphs = this.getGraphs(); var s = graphs.length; for (var i = 0; i < s; i++) { nodeList = nodeList.concat(graphs[i].getNodes()); } this.allNodes = nodeList; } return this.allNodes; }; LGraphManager.prototype.resetAllNodes = function () { this.allNodes = null; }; LGraphManager.prototype.resetAllEdges = function () { this.allEdges = null; }; LGraphManager.prototype.resetAllNodesToApplyGravitation = function () { this.allNodesToApplyGravitation = null; }; LGraphManager.prototype.getAllEdges = function () { if (this.allEdges == null) { var edgeList = []; var graphs = this.getGraphs(); var s = graphs.length; for (var i = 0; i < graphs.length; i++) { edgeList = edgeList.concat(graphs[i].getEdges()); } edgeList = edgeList.concat(this.edges); this.allEdges = edgeList; } return this.allEdges; }; LGraphManager.prototype.getAllNodesToApplyGravitation = function () { return this.allNodesToApplyGravitation; }; LGraphManager.prototype.setAllNodesToApplyGravitation = function (nodeList) { if (this.allNodesToApplyGravitation != null) { throw "assert failed"; } this.allNodesToApplyGravitation = nodeList; }; LGraphManager.prototype.getRoot = function () { return this.rootGraph; }; LGraphManager.prototype.setRootGraph = function (graph) { if (graph.getGraphManager() != this) { throw "Root not in this graph mgr!"; } this.rootGraph = graph; // root graph must have a root node associated with it for convenience if (graph.parent == null) { graph.parent = this.layout.newNode("Root node"); } }; LGraphManager.prototype.getLayout = function () { return this.layout; }; LGraphManager.prototype.isOneAncestorOfOther = function (firstNode, secondNode) { if (!(firstNode != null && secondNode != null)) { throw "assert failed"; } if (firstNode == secondNode) { return true; } // Is second node an ancestor of the first one? var ownerGraph = firstNode.getOwner(); var parentNode; do { parentNode = ownerGraph.getParent(); if (parentNode == null) { break; } if (parentNode == secondNode) { return true; } ownerGraph = parentNode.getOwner(); if (ownerGraph == null) { break; } } while (true); // Is first node an ancestor of the second one? ownerGraph = secondNode.getOwner(); do { parentNode = ownerGraph.getParent(); if (parentNode == null) { break; } if (parentNode == firstNode) { return true; } ownerGraph = parentNode.getOwner(); if (ownerGraph == null) { break; } } while (true); return false; }; LGraphManager.prototype.calcLowestCommonAncestors = function () { var edge; var sourceNode; var targetNode; var sourceAncestorGraph; var targetAncestorGraph; var edges = this.getAllEdges(); var s = edges.length; for (var i = 0; i < s; i++) { edge = edges[i]; sourceNode = edge.source; targetNode = edge.target; edge.lca = null; edge.sourceInLca = sourceNode; edge.targetInLca = targetNode; if (sourceNode == targetNode) { edge.lca = sourceNode.getOwner(); continue; } sourceAncestorGraph = sourceNode.getOwner(); while (edge.lca == null) { edge.targetInLca = targetNode; targetAncestorGraph = targetNode.getOwner(); while (edge.lca == null) { if (targetAncestorGraph == sourceAncestorGraph) { edge.lca = targetAncestorGraph; break; } if (targetAncestorGraph == this.rootGraph) { break; } if (edge.lca != null) { throw "assert failed"; } edge.targetInLca = targetAncestorGraph.getParent(); targetAncestorGraph = edge.targetInLca.getOwner(); } if (sourceAncestorGraph == this.rootGraph) { break; } if (edge.lca == null) { edge.sourceInLca = sourceAncestorGraph.getParent(); sourceAncestorGraph = edge.sourceInLca.getOwner(); } } if (edge.lca == null) { throw "assert failed"; } } }; LGraphManager.prototype.calcLowestCommonAncestor = function (firstNode, secondNode) { if (firstNode == secondNode) { return firstNode.getOwner(); } var firstOwnerGraph = firstNode.getOwner(); do { if (firstOwnerGraph == null) { break; } var secondOwnerGraph = secondNode.getOwner(); do { if (secondOwnerGraph == null) { break; } if (secondOwnerGraph == firstOwnerGraph) { return secondOwnerGraph; } secondOwnerGraph = secondOwnerGraph.getParent().getOwner(); } while (true); firstOwnerGraph = firstOwnerGraph.getParent().getOwner(); } while (true); return firstOwnerGraph; }; LGraphManager.prototype.calcInclusionTreeDepths = function (graph, depth) { if (graph == null && depth == null) { graph = this.rootGraph; depth = 1; } var node; var nodes = graph.getNodes(); var s = nodes.length; for (var i = 0; i < s; i++) { node = nodes[i]; node.inclusionTreeDepth = depth; if (node.child != null) { this.calcInclusionTreeDepths(node.child, depth + 1); } } }; LGraphManager.prototype.includesInvalidEdge = function () { var edge; var edgesToRemove = []; var s = this.edges.length; for (var i = 0; i < s; i++) { edge = this.edges[i]; if (this.isOneAncestorOfOther(edge.source, edge.target)) { edgesToRemove.push(edge); } } // Remove invalid edges from graph manager for (var i = 0; i < edgesToRemove.length; i++) { this.remove(edgesToRemove[i]); } // Invalid edges are cleared, so return false return false; }; module.exports = LGraphManager; /***/ }), /* 8 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /** * This class maintains a list of static geometry related utility methods. * * * Copyright: i-Vis Research Group, Bilkent University, 2007 - present */ var Point = __webpack_require__(12); function IGeometry() {} /** * This method calculates *half* the amount in x and y directions of the two * input rectangles needed to separate them keeping their respective * positioning, and returns the result in the input array. An input * separation buffer added to the amount in both directions. We assume that * the two rectangles do intersect. */ IGeometry.calcSeparationAmount = function (rectA, rectB, overlapAmount, separationBuffer) { if (!rectA.intersects(rectB)) { throw "assert failed"; } var directions = new Array(2); this.decideDirectionsForOverlappingNodes(rectA, rectB, directions); overlapAmount[0] = Math.min(rectA.getRight(), rectB.getRight()) - Math.max(rectA.x, rectB.x); overlapAmount[1] = Math.min(rectA.getBottom(), rectB.getBottom()) - Math.max(rectA.y, rectB.y); // update the overlapping amounts for the following cases: if (rectA.getX() <= rectB.getX() && rectA.getRight() >= rectB.getRight()) { /* Case x.1: * * rectA * | | * | _________ | * | | | | * |________|_______|______| * | | * | | * rectB */ overlapAmount[0] += Math.min(rectB.getX() - rectA.getX(), rectA.getRight() - rectB.getRight()); } else if (rectB.getX() <= rectA.getX() && rectB.getRight() >= rectA.getRight()) { /* Case x.2: * * rectB * | | * | _________ | * | | | | * |________|_______|______| * | | * | | * rectA */ overlapAmount[0] += Math.min(rectA.getX() - rectB.getX(), rectB.getRight() - rectA.getRight()); } if (rectA.getY() <= rectB.getY() && rectA.getBottom() >= rectB.getBottom()) { /* Case y.1: * ________ rectA * | * | * ______|____ rectB * | | * | | * ______|____| * | * | * |________ * */ overlapAmount[1] += Math.min(rectB.getY() - rectA.getY(), rectA.getBottom() - rectB.getBottom()); } else if (rectB.getY() <= rectA.getY() && rectB.getBottom() >= rectA.getBottom()) { /* Case y.2: * ________ rectB * | * | * ______|____ rectA * | | * | | * ______|____| * | * | * |________ * */ overlapAmount[1] += Math.min(rectA.getY() - rectB.getY(), rectB.getBottom() - rectA.getBottom()); } // find slope of the line passes two centers var slope = Math.abs((rectB.getCenterY() - rectA.getCenterY()) / (rectB.getCenterX() - rectA.getCenterX())); // if centers are overlapped if (rectB.getCenterY() === rectA.getCenterY() && rectB.getCenterX() === rectA.getCenterX()) { // assume the slope is 1 (45 degree) slope = 1.0; } var moveByY = slope * overlapAmount[0]; var moveByX = overlapAmount[1] / slope; if (overlapAmount[0] < moveByX) { moveByX = overlapAmount[0]; } else { moveByY = overlapAmount[1]; } // return half the amount so that if each rectangle is moved by these // amounts in opposite directions, overlap will be resolved overlapAmount[0] = -1 * directions[0] * (moveByX / 2 + separationBuffer); overlapAmount[1] = -1 * directions[1] * (moveByY / 2 + separationBuffer); }; /** * This method decides the separation direction of overlapping nodes * * if directions[0] = -1, then rectA goes left * if directions[0] = 1, then rectA goes right * if directions[1] = -1, then rectA goes up * if directions[1] = 1, then rectA goes down */ IGeometry.decideDirectionsForOverlappingNodes = function (rectA, rectB, directions) { if (rectA.getCenterX() < rectB.getCenterX()) { directions[0] = -1; } else { directions[0] = 1; } if (rectA.getCenterY() < rectB.getCenterY()) { directions[1] = -1; } else { directions[1] = 1; } }; /** * This method calculates the intersection (clipping) points of the two * input rectangles with line segment defined by the centers of these two * rectangles. The clipping points are saved in the input double array and * whether or not the two rectangles overlap is returned. */ IGeometry.getIntersection2 = function (rectA, rectB, result) { //result[0-1] will contain clipPoint of rectA, result[2-3] will contain clipPoint of rectB var p1x = rectA.getCenterX(); var p1y = rectA.getCenterY(); var p2x = rectB.getCenterX(); var p2y = rectB.getCenterY(); //if two rectangles intersect, then clipping points are centers if (rectA.intersects(rectB)) { result[0] = p1x; result[1] = p1y; result[2] = p2x; result[3] = p2y; return true; } //variables for rectA var topLeftAx = rectA.getX(); var topLeftAy = rectA.getY(); var topRightAx = rectA.getRight(); var bottomLeftAx = rectA.getX(); var bottomLeftAy = rectA.getBottom(); var bottomRightAx = rectA.getRight(); var halfWidthA = rectA.getWidthHalf(); var halfHeightA = rectA.getHeightHalf(); //variables for rectB var topLeftBx = rectB.getX(); var topLeftBy = rectB.getY(); var topRightBx = rectB.getRight(); var bottomLeftBx = rectB.getX(); var bottomLeftBy = rectB.getBottom(); var bottomRightBx = rectB.getRight(); var halfWidthB = rectB.getWidthHalf(); var halfHeightB = rectB.getHeightHalf(); //flag whether clipping points are found var clipPointAFound = false; var clipPointBFound = false; // line is vertical if (p1x === p2x) { if (p1y > p2y) { result[0] = p1x; result[1] = topLeftAy; result[2] = p2x; result[3] = bottomLeftBy; return false; } else if (p1y < p2y) { result[0] = p1x; result[1] = bottomLeftAy; result[2] = p2x; result[3] = topLeftBy; return false; } else { //not line, return null; } } // line is horizontal else if (p1y === p2y) { if (p1x > p2x) { result[0] = topLeftAx; result[1] = p1y; result[2] = topRightBx; result[3] = p2y; return false; } else if (p1x < p2x) { result[0] = topRightAx; result[1] = p1y; result[2] = topLeftBx; result[3] = p2y; return false; } else { //not valid line, return null; } } else { //slopes of rectA's and rectB's diagonals var slopeA = rectA.height / rectA.width; var slopeB = rectB.height / rectB.width; //slope of line between center of rectA and center of rectB var slopePrime = (p2y - p1y) / (p2x - p1x); var cardinalDirectionA = void 0; var cardinalDirectionB = void 0; var tempPointAx = void 0; var tempPointAy = void 0; var tempPointBx = void 0; var tempPointBy = void 0; //determine whether clipping point is the corner of nodeA if (-slopeA === slopePrime) { if (p1x > p2x) { result[0] = bottomLeftAx; result[1] = bottomLeftAy; clipPointAFound = true; } else { result[0] = topRightAx; result[1] = topLeftAy; clipPointAFound = true; } } else if (slopeA === slopePrime) { if (p1x > p2x) { result[0] = topLeftAx; result[1] = topLeftAy; clipPointAFound = true; } else { result[0] = bottomRightAx; result[1] = bottomLeftAy; clipPointAFound = true; } } //determine whether clipping point is the corner of nodeB if (-slopeB === slopePrime) { if (p2x > p1x) { result[2] = bottomLeftBx; result[3] = bottomLeftBy; clipPointBFound = true; } else { result[2] = topRightBx; result[3] = topLeftBy; clipPointBFound = true; } } else if (slopeB === slopePrime) { if (p2x > p1x) { result[2] = topLeftBx; result[3] = topLeftBy; clipPointBFound = true; } else { result[2] = bottomRightBx; result[3] = bottomLeftBy; clipPointBFound = true; } } //if both clipping points are corners if (clipPointAFound && clipPointBFound) { return false; } //determine Cardinal Direction of rectangles if (p1x > p2x) { if (p1y > p2y) { cardinalDirectionA = this.getCardinalDirection(slopeA, slopePrime, 4); cardinalDirectionB = this.getCardinalDirection(slopeB, slopePrime, 2); } else { cardinalDirectionA = this.getCardinalDirection(-slopeA, slopePrime, 3); cardinalDirectionB = this.get