(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["cytoscape"] = factory(); else root["cytoscape"] = factory(); })(typeof self !== 'undefined' ? self : 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; /******/ /******/ // 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 = 20); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /*global HTMLElement DocumentTouch */ var window = __webpack_require__(3); var navigator = window ? window.navigator : null; var document = window ? window.document : null; var typeofstr = _typeof(''); var typeofobj = _typeof({}); var typeoffn = _typeof(function () {}); var typeofhtmlele = typeof HTMLElement === 'undefined' ? 'undefined' : _typeof(HTMLElement); var instanceStr = function instanceStr(obj) { return obj && obj.instanceString && is.fn(obj.instanceString) ? obj.instanceString() : null; }; var is = { defined: function defined(obj) { return obj != null; // not undefined or null }, string: function string(obj) { return obj != null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) == typeofstr; }, fn: function fn(obj) { return obj != null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === typeoffn; }, array: function array(obj) { return Array.isArray ? Array.isArray(obj) : obj != null && obj instanceof Array; }, plainObject: function plainObject(obj) { return obj != null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === typeofobj && !is.array(obj) && obj.constructor === Object; }, object: function object(obj) { return obj != null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === typeofobj; }, number: function number(obj) { return obj != null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === _typeof(1) && !isNaN(obj); }, integer: function integer(obj) { return is.number(obj) && Math.floor(obj) === obj; }, bool: function bool(obj) { return obj != null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === _typeof(true); }, htmlElement: function htmlElement(obj) { if ('undefined' === typeofhtmlele) { return undefined; } else { return null != obj && obj instanceof HTMLElement; } }, elementOrCollection: function elementOrCollection(obj) { return is.element(obj) || is.collection(obj); }, element: function element(obj) { return instanceStr(obj) === 'collection' && obj._private.single; }, collection: function collection(obj) { return instanceStr(obj) === 'collection' && !obj._private.single; }, core: function core(obj) { return instanceStr(obj) === 'core'; }, style: function style(obj) { return instanceStr(obj) === 'style'; }, stylesheet: function stylesheet(obj) { return instanceStr(obj) === 'stylesheet'; }, event: function event(obj) { return instanceStr(obj) === 'event'; }, thread: function thread(obj) { return instanceStr(obj) === 'thread'; }, fabric: function fabric(obj) { return instanceStr(obj) === 'fabric'; }, emptyString: function emptyString(obj) { if (obj === undefined || obj === null) { // null is empty return true; } else if (obj === '' || obj.match(/^\s+$/)) { return true; // empty string is empty } return false; // otherwise, we don't know what we've got }, nonemptyString: function nonemptyString(obj) { if (obj && is.string(obj) && obj !== '' && !obj.match(/^\s+$/)) { return true; } return false; }, domElement: function domElement(obj) { if (typeof HTMLElement === 'undefined') { return false; // we're not in a browser so it doesn't matter } else { return obj instanceof HTMLElement; } }, boundingBox: function boundingBox(obj) { return is.plainObject(obj) && is.number(obj.x1) && is.number(obj.x2) && is.number(obj.y1) && is.number(obj.y2); }, promise: function promise(obj) { return is.object(obj) && is.fn(obj.then); }, touch: function touch() { return window && ('ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch); }, gecko: function gecko() { return window && (typeof InstallTrigger !== 'undefined' || 'MozAppearance' in document.documentElement.style); }, webkit: function webkit() { return window && (typeof webkitURL !== 'undefined' || 'WebkitAppearance' in document.documentElement.style); }, chromium: function chromium() { return window && typeof chrome !== 'undefined'; }, khtml: function khtml() { return navigator && navigator.vendor.match(/kde/i); // probably a better way to detect this... }, khtmlEtc: function khtmlEtc() { return is.khtml() || is.webkit() || is.chromium(); }, ms: function ms() { return navigator && navigator.userAgent.match(/msie|trident|edge/i); // probably a better way to detect this... }, windows: function windows() { return navigator && navigator.appVersion.match(/Win/i); }, mac: function mac() { return navigator && navigator.appVersion.match(/Mac/i); }, linux: function linux() { return navigator && navigator.appVersion.match(/Linux/i); }, unix: function unix() { return navigator && navigator.appVersion.match(/X11/i); } }; module.exports = is; /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*global console */ var is = __webpack_require__(0); var math = __webpack_require__(2); var util = { MAX_INT: Number.MAX_SAFE_INTEGER || 9007199254740991, trueify: function trueify() { return true; }, falsify: function falsify() { return false; }, zeroify: function zeroify() { return 0; }, noop: function noop() {}, error: function error(msg) { /* eslint-disable */ if (console.error) { console.error.apply(console, arguments); if (console.trace) { console.trace(); } } else { console.log.apply(console, arguments); if (console.trace) { console.trace(); } } /* eslint-enable */ }, clone: function clone(obj) { return this.extend({}, obj); }, // gets a shallow copy of the argument copy: function copy(obj) { if (obj == null) { return obj; }if (is.array(obj)) { return obj.slice(); } else if (is.plainObject(obj)) { return this.clone(obj); } else { return obj; } }, copyArray: function copyArray(arr) { return arr.slice(); }, clonePosition: function clonePosition(pos) { return { x: pos.x, y: pos.y }; }, uuid: function uuid(a, b // placeholders ) { for ( // loop :) b = a = ''; // b - result , a - numeric letiable a++ < 36; // b += a * 51 & 52 // if "a" is not 9 or 14 or 19 or 24 ? // return a random number or 4 (a ^ 15 // if "a" is not 15 ? // genetate a random number from 0 to 15 8 ^ Math.random() * (a ^ 20 ? 16 : 4) // unless "a" is 20, in which case a random number from 8 to 11 : 4 // otherwise 4 ).toString(16) : '-' // in other cases (if "a" is 9,14,19,24) insert "-" ) {} return b; } }; util.makeBoundingBox = math.makeBoundingBox.bind(math); util._staticEmptyObject = {}; util.staticEmptyObject = function () { return util._staticEmptyObject; }; util.extend = Object.assign != null ? Object.assign.bind(Object) : function (tgt) { var args = arguments; for (var i = 1; i < args.length; i++) { var obj = args[i]; if (obj == null) { continue; } var keys = Object.keys(obj); for (var j = 0; j < keys.length; j++) { var k = keys[j]; tgt[k] = obj[k]; } } return tgt; }; util.assign = util.extend; util.default = function (val, def) { if (val === undefined) { return def; } else { return val; } }; util.removeFromArray = function (arr, ele, manyCopies) { for (var i = arr.length; i >= 0; i--) { if (arr[i] === ele) { arr.splice(i, 1); if (!manyCopies) { break; } } } }; util.clearArray = function (arr) { arr.splice(0, arr.length); }; util.push = function (arr, otherArr) { for (var i = 0; i < otherArr.length; i++) { var el = otherArr[i]; arr.push(el); } }; util.getPrefixedProperty = function (obj, propName, prefix) { if (prefix) { propName = this.prependCamel(prefix, propName); // e.g. (labelWidth, source) => sourceLabelWidth } return obj[propName]; }; util.setPrefixedProperty = function (obj, propName, prefix, value) { if (prefix) { propName = this.prependCamel(prefix, propName); // e.g. (labelWidth, source) => sourceLabelWidth } obj[propName] = value; }; [__webpack_require__(21), __webpack_require__(22), { memoize: __webpack_require__(13) }, __webpack_require__(23), __webpack_require__(24), __webpack_require__(25), __webpack_require__(27)].forEach(function (req) { util.extend(util, req); }); module.exports = util; /***/ }), /* 2 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var math = {}; math.arePositionsSame = function (p1, p2) { return p1.x === p2.x && p1.y === p2.y; }; math.copyPosition = function (p) { return { x: p.x, y: p.y }; }; math.modelToRenderedPosition = function (p, zoom, pan) { return { x: p.x * zoom + pan.x, y: p.y * zoom + pan.y }; }; math.renderedToModelPosition = function (p, zoom, pan) { return { x: (p.x - pan.x) / zoom, y: (p.y - pan.y) / zoom }; }; math.array2point = function (arr) { return { x: arr[0], y: arr[1] }; }; math.deg2rad = function (deg) { return Math.PI * deg / 180; }; math.getAngleFromDisp = function (dispX, dispY) { return Math.atan2(dispY, dispX) - Math.PI / 2; }; math.log2 = Math.log2 || function (n) { return Math.log(n) / Math.log(2); }; math.signum = function (x) { if (x > 0) { return 1; } else if (x < 0) { return -1; } else { return 0; } }; math.dist = function (p1, p2) { return Math.sqrt(math.sqdist(p1, p2)); }; math.sqdist = function (p1, p2) { var dx = p2.x - p1.x; var dy = p2.y - p1.y; return dx * dx + dy * dy; }; // from http://en.wikipedia.org/wiki/Bézier_curve#Quadratic_curves math.qbezierAt = function (p0, p1, p2, t) { return (1 - t) * (1 - t) * p0 + 2 * (1 - t) * t * p1 + t * t * p2; }; math.qbezierPtAt = function (p0, p1, p2, t) { return { x: math.qbezierAt(p0.x, p1.x, p2.x, t), y: math.qbezierAt(p0.y, p1.y, p2.y, t) }; }; math.lineAt = function (p0, p1, t, d) { var vec = { x: p1.x - p0.x, y: p1.y - p0.y }; var vecDist = math.dist(p0, p1); var normVec = { x: vec.x / vecDist, y: vec.y / vecDist }; t = t == null ? 0 : t; d = d != null ? d : t * vecDist; return { x: p0.x + normVec.x * d, y: p0.y + normVec.y * d }; }; math.lineAtDist = function (p0, p1, d) { return math.lineAt(p0, p1, undefined, d); }; // get angle at A via cosine law math.triangleAngle = function (A, B, C) { var a = math.dist(B, C); var b = math.dist(A, C); var c = math.dist(A, B); return Math.acos((a * a + b * b - c * c) / (2 * a * b)); }; math.bound = function (min, val, max) { return Math.max(min, Math.min(max, val)); }; // makes a full bb (x1, y1, x2, y2, w, h) from implicit params math.makeBoundingBox = function (bb) { if (bb == null) { return { x1: Infinity, y1: Infinity, x2: -Infinity, y2: -Infinity, w: 0, h: 0 }; } else if (bb.x1 != null && bb.y1 != null) { if (bb.x2 != null && bb.y2 != null && bb.x2 >= bb.x1 && bb.y2 >= bb.y1) { return { x1: bb.x1, y1: bb.y1, x2: bb.x2, y2: bb.y2, w: bb.x2 - bb.x1, h: bb.y2 - bb.y1 }; } else if (bb.w != null && bb.h != null && bb.w >= 0 && bb.h >= 0) { return { x1: bb.x1, y1: bb.y1, x2: bb.x1 + bb.w, y2: bb.y1 + bb.h, w: bb.w, h: bb.h }; } } }; math.updateBoundingBox = function (bb1, bb2) { // update bb1 with bb2 bounds bb1.x1 = Math.min(bb1.x1, bb2.x1); bb1.x2 = Math.max(bb1.x2, bb2.x2); bb1.w = bb1.x2 - bb1.x1; bb1.y1 = Math.min(bb1.y1, bb2.y1); bb1.y2 = Math.max(bb1.y2, bb2.y2); bb1.h = bb1.y2 - bb1.y1; }; math.expandBoundingBoxByPoint = function (bb, x, y) { bb.x1 = Math.min(bb.x1, x); bb.x2 = Math.max(bb.x2, x); bb.w = bb.x2 - bb.x1; bb.y1 = Math.min(bb.y1, y); bb.y2 = Math.max(bb.y2, y); bb.h = bb.y2 - bb.y1; }; math.expandBoundingBox = function (bb, padding) { bb.x1 -= padding; bb.x2 += padding; bb.y1 -= padding; bb.y2 += padding; bb.w = bb.x2 - bb.x1; bb.h = bb.y2 - bb.y1; return bb; }; math.boundingBoxesIntersect = function (bb1, bb2) { // case: one bb to right of other if (bb1.x1 > bb2.x2) { return false; } if (bb2.x1 > bb1.x2) { return false; } // case: one bb to left of other if (bb1.x2 < bb2.x1) { return false; } if (bb2.x2 < bb1.x1) { return false; } // case: one bb above other if (bb1.y2 < bb2.y1) { return false; } if (bb2.y2 < bb1.y1) { return false; } // case: one bb below other if (bb1.y1 > bb2.y2) { return false; } if (bb2.y1 > bb1.y2) { return false; } // otherwise, must have some overlap return true; }; math.inBoundingBox = function (bb, x, y) { return bb.x1 <= x && x <= bb.x2 && bb.y1 <= y && y <= bb.y2; }; math.pointInBoundingBox = function (bb, pt) { return this.inBoundingBox(bb, pt.x, pt.y); }; math.boundingBoxInBoundingBox = function (bb1, bb2) { return math.inBoundingBox(bb1, bb2.x1, bb2.y1) && math.inBoundingBox(bb1, bb2.x2, bb2.y2); }; math.roundRectangleIntersectLine = function (x, y, nodeX, nodeY, width, height, padding) { var cornerRadius = this.getRoundRectangleRadius(width, height); var halfWidth = width / 2; var halfHeight = height / 2; // Check intersections with straight line segments var straightLineIntersections = void 0; // Top segment, left to right { var topStartX = nodeX - halfWidth + cornerRadius - padding; var topStartY = nodeY - halfHeight - padding; var topEndX = nodeX + halfWidth - cornerRadius + padding; var topEndY = topStartY; straightLineIntersections = this.finiteLinesIntersect(x, y, nodeX, nodeY, topStartX, topStartY, topEndX, topEndY, false); if (straightLineIntersections.length > 0) { return straightLineIntersections; } } // Right segment, top to bottom { var rightStartX = nodeX + halfWidth + padding; var rightStartY = nodeY - halfHeight + cornerRadius - padding; var rightEndX = rightStartX; var rightEndY = nodeY + halfHeight - cornerRadius + padding; straightLineIntersections = this.finiteLinesIntersect(x, y, nodeX, nodeY, rightStartX, rightStartY, rightEndX, rightEndY, false); if (straightLineIntersections.length > 0) { return straightLineIntersections; } } // Bottom segment, left to right { var bottomStartX = nodeX - halfWidth + cornerRadius - padding; var bottomStartY = nodeY + halfHeight + padding; var bottomEndX = nodeX + halfWidth - cornerRadius + padding; var bottomEndY = bottomStartY; straightLineIntersections = this.finiteLinesIntersect(x, y, nodeX, nodeY, bottomStartX, bottomStartY, bottomEndX, bottomEndY, false); if (straightLineIntersections.length > 0) { return straightLineIntersections; } } // Left segment, top to bottom { var leftStartX = nodeX - halfWidth - padding; var leftStartY = nodeY - halfHeight + cornerRadius - padding; var leftEndX = leftStartX; var leftEndY = nodeY + halfHeight - cornerRadius + padding; straightLineIntersections = this.finiteLinesIntersect(x, y, nodeX, nodeY, leftStartX, leftStartY, leftEndX, leftEndY, false); if (straightLineIntersections.length > 0) { return straightLineIntersections; } } // Check intersections with arc segments var arcIntersections = void 0; // Top Left { var topLeftCenterX = nodeX - halfWidth + cornerRadius; var topLeftCenterY = nodeY - halfHeight + cornerRadius; arcIntersections = this.intersectLineCircle(x, y, nodeX, nodeY, topLeftCenterX, topLeftCenterY, cornerRadius + padding); // Ensure the intersection is on the desired quarter of the circle if (arcIntersections.length > 0 && arcIntersections[0] <= topLeftCenterX && arcIntersections[1] <= topLeftCenterY) { return [arcIntersections[0], arcIntersections[1]]; } } // Top Right { var topRightCenterX = nodeX + halfWidth - cornerRadius; var topRightCenterY = nodeY - halfHeight + cornerRadius; arcIntersections = this.intersectLineCircle(x, y, nodeX, nodeY, topRightCenterX, topRightCenterY, cornerRadius + padding); // Ensure the intersection is on the desired quarter of the circle if (arcIntersections.length > 0 && arcIntersections[0] >= topRightCenterX && arcIntersections[1] <= topRightCenterY) { return [arcIntersections[0], arcIntersections[1]]; } } // Bottom Right { var bottomRightCenterX = nodeX + halfWidth - cornerRadius; var bottomRightCenterY = nodeY + halfHeight - cornerRadius; arcIntersections = this.intersectLineCircle(x, y, nodeX, nodeY, bottomRightCenterX, bottomRightCenterY, cornerRadius + padding); // Ensure the intersection is on the desired quarter of the circle if (arcIntersections.length > 0 && arcIntersections[0] >= bottomRightCenterX && arcIntersections[1] >= bottomRightCenterY) { return [arcIntersections[0], arcIntersections[1]]; } } // Bottom Left { var bottomLeftCenterX = nodeX - halfWidth + cornerRadius; var bottomLeftCenterY = nodeY + halfHeight - cornerRadius; arcIntersections = this.intersectLineCircle(x, y, nodeX, nodeY, bottomLeftCenterX, bottomLeftCenterY, cornerRadius + padding); // Ensure the intersection is on the desired quarter of the circle if (arcIntersections.length > 0 && arcIntersections[0] <= bottomLeftCenterX && arcIntersections[1] >= bottomLeftCenterY) { return [arcIntersections[0], arcIntersections[1]]; } } return []; // if nothing }; math.inLineVicinity = function (x, y, lx1, ly1, lx2, ly2, tolerance) { var t = tolerance; var x1 = Math.min(lx1, lx2); var x2 = Math.max(lx1, lx2); var y1 = Math.min(ly1, ly2); var y2 = Math.max(ly1, ly2); return x1 - t <= x && x <= x2 + t && y1 - t <= y && y <= y2 + t; }; math.inBezierVicinity = function (x, y, x1, y1, x2, y2, x3, y3, tolerance) { var bb = { x1: Math.min(x1, x3, x2) - tolerance, x2: Math.max(x1, x3, x2) + tolerance, y1: Math.min(y1, y3, y2) - tolerance, y2: Math.max(y1, y3, y2) + tolerance }; // if outside the rough bounding box for the bezier, then it can't be a hit if (x < bb.x1 || x > bb.x2 || y < bb.y1 || y > bb.y2) { // console.log('bezier out of rough bb') return false; } else { // console.log('do more expensive check'); return true; } }; math.solveQuadratic = function (a, b, c, val) { c -= val; var r = b * b - 4 * a * c; if (r < 0) { return []; } var sqrtR = Math.sqrt(r); var denom = 2 * a; var root1 = (-b + sqrtR) / denom; var root2 = (-b - sqrtR) / denom; return [root1, root2]; }; math.solveCubic = function (a, b, c, d, result) { // Solves a cubic function, returns root in form [r1, i1, r2, i2, r3, i3], where // r is the real component, i is the imaginary component // An implementation of the Cardano method from the year 1545 // http://en.wikipedia.org/wiki/Cubic_function#The_nature_of_the_roots b /= a; c /= a; d /= a; var discriminant = void 0, q = void 0, r = void 0, dum1 = void 0, s = void 0, t = void 0, term1 = void 0, r13 = void 0; q = (3.0 * c - b * b) / 9.0; r = -(27.0 * d) + b * (9.0 * c - 2.0 * (b * b)); r /= 54.0; discriminant = q * q * q + r * r; result[1] = 0; term1 = b / 3.0; if (discriminant > 0) { s = r + Math.sqrt(discriminant); s = s < 0 ? -Math.pow(-s, 1.0 / 3.0) : Math.pow(s, 1.0 / 3.0); t = r - Math.sqrt(discriminant); t = t < 0 ? -Math.pow(-t, 1.0 / 3.0) : Math.pow(t, 1.0 / 3.0); result[0] = -term1 + s + t; term1 += (s + t) / 2.0; result[4] = result[2] = -term1; term1 = Math.sqrt(3.0) * (-t + s) / 2; result[3] = term1; result[5] = -term1; return; } result[5] = result[3] = 0; if (discriminant === 0) { r13 = r < 0 ? -Math.pow(-r, 1.0 / 3.0) : Math.pow(r, 1.0 / 3.0); result[0] = -term1 + 2.0 * r13; result[4] = result[2] = -(r13 + term1); return; } q = -q; dum1 = q * q * q; dum1 = Math.acos(r / Math.sqrt(dum1)); r13 = 2.0 * Math.sqrt(q); result[0] = -term1 + r13 * Math.cos(dum1 / 3.0); result[2] = -term1 + r13 * Math.cos((dum1 + 2.0 * Math.PI) / 3.0); result[4] = -term1 + r13 * Math.cos((dum1 + 4.0 * Math.PI) / 3.0); return; }; math.sqdistToQuadraticBezier = function (x, y, x1, y1, x2, y2, x3, y3) { // Find minimum distance by using the minimum of the distance // function between the given point and the curve // This gives the coefficients of the resulting cubic equation // whose roots tell us where a possible minimum is // (Coefficients are divided by 4) var a = 1.0 * x1 * x1 - 4 * x1 * x2 + 2 * x1 * x3 + 4 * x2 * x2 - 4 * x2 * x3 + x3 * x3 + y1 * y1 - 4 * y1 * y2 + 2 * y1 * y3 + 4 * y2 * y2 - 4 * y2 * y3 + y3 * y3; var b = 1.0 * 9 * x1 * x2 - 3 * x1 * x1 - 3 * x1 * x3 - 6 * x2 * x2 + 3 * x2 * x3 + 9 * y1 * y2 - 3 * y1 * y1 - 3 * y1 * y3 - 6 * y2 * y2 + 3 * y2 * y3; var c = 1.0 * 3 * x1 * x1 - 6 * x1 * x2 + x1 * x3 - x1 * x + 2 * x2 * x2 + 2 * x2 * x - x3 * x + 3 * y1 * y1 - 6 * y1 * y2 + y1 * y3 - y1 * y + 2 * y2 * y2 + 2 * y2 * y - y3 * y; var d = 1.0 * x1 * x2 - x1 * x1 + x1 * x - x2 * x + y1 * y2 - y1 * y1 + y1 * y - y2 * y; // debug("coefficients: " + a / a + ", " + b / a + ", " + c / a + ", " + d / a); var roots = []; // Use the cubic solving algorithm this.solveCubic(a, b, c, d, roots); var zeroThreshold = 0.0000001; var params = []; for (var index = 0; index < 6; index += 2) { if (Math.abs(roots[index + 1]) < zeroThreshold && roots[index] >= 0 && roots[index] <= 1.0) { params.push(roots[index]); } } params.push(1.0); params.push(0.0); var minDistanceSquared = -1; var curX = void 0, curY = void 0, distSquared = void 0; for (var i = 0; i < params.length; i++) { curX = Math.pow(1.0 - params[i], 2.0) * x1 + 2.0 * (1 - params[i]) * params[i] * x2 + params[i] * params[i] * x3; curY = Math.pow(1 - params[i], 2.0) * y1 + 2 * (1.0 - params[i]) * params[i] * y2 + params[i] * params[i] * y3; distSquared = Math.pow(curX - x, 2) + Math.pow(curY - y, 2); // debug('distance for param ' + params[i] + ": " + Math.sqrt(distSquared)); if (minDistanceSquared >= 0) { if (distSquared < minDistanceSquared) { minDistanceSquared = distSquared; } } else { minDistanceSquared = distSquared; } } return minDistanceSquared; }; math.sqdistToFiniteLine = function (x, y, x1, y1, x2, y2) { var offset = [x - x1, y - y1]; var line = [x2 - x1, y2 - y1]; var lineSq = line[0] * line[0] + line[1] * line[1]; var hypSq = offset[0] * offset[0] + offset[1] * offset[1]; var dotProduct = offset[0] * line[0] + offset[1] * line[1]; var adjSq = dotProduct * dotProduct / lineSq; if (dotProduct < 0) { return hypSq; } if (adjSq > lineSq) { return (x - x2) * (x - x2) + (y - y2) * (y - y2); } return hypSq - adjSq; }; math.pointInsidePolygonPoints = function (x, y, points) { var x1 = void 0, y1 = void 0, x2 = void 0, y2 = void 0; var y3 = void 0; // Intersect with vertical line through (x, y) var up = 0; // let down = 0; for (var i = 0; i < points.length / 2; i++) { x1 = points[i * 2]; y1 = points[i * 2 + 1]; if (i + 1 < points.length / 2) { x2 = points[(i + 1) * 2]; y2 = points[(i + 1) * 2 + 1]; } else { x2 = points[(i + 1 - points.length / 2) * 2]; y2 = points[(i + 1 - points.length / 2) * 2 + 1]; } if (x1 == x && x2 == x) { // then ignore } else if (x1 >= x && x >= x2 || x1 <= x && x <= x2) { y3 = (x - x1) / (x2 - x1) * (y2 - y1) + y1; if (y3 > y) { up++; } // if( y3 < y ){ // down++; // } } else { continue; } } if (up % 2 === 0) { return false; } else { return true; } }; math.pointInsidePolygon = function (x, y, basePoints, centerX, centerY, width, height, direction, padding) { //let direction = arguments[6]; var transformedPoints = new Array(basePoints.length); // Gives negative angle var angle = void 0; if (direction[0] != null) { angle = Math.atan(direction[1] / direction[0]); if (direction[0] < 0) { angle = angle + Math.PI / 2; } else { angle = -angle - Math.PI / 2; } } else { angle = direction; } var cos = Math.cos(-angle); var sin = Math.sin(-angle); // console.log("base: " + basePoints); for (var i = 0; i < transformedPoints.length / 2; i++) { transformedPoints[i * 2] = width / 2 * (basePoints[i * 2] * cos - basePoints[i * 2 + 1] * sin); transformedPoints[i * 2 + 1] = height / 2 * (basePoints[i * 2 + 1] * cos + basePoints[i * 2] * sin); transformedPoints[i * 2] += centerX; transformedPoints[i * 2 + 1] += centerY; } var points = void 0; if (padding > 0) { var expandedLineSet = this.expandPolygon(transformedPoints, -padding); points = this.joinLines(expandedLineSet); } else { points = transformedPoints; } return math.pointInsidePolygonPoints(x, y, points); }; math.joinLines = function (lineSet) { var vertices = new Array(lineSet.length / 2); var currentLineStartX = void 0, currentLineStartY = void 0, currentLineEndX = void 0, currentLineEndY = void 0; var nextLineStartX = void 0, nextLineStartY = void 0, nextLineEndX = void 0, nextLineEndY = void 0; for (var i = 0; i < lineSet.length / 4; i++) { currentLineStartX = lineSet[i * 4]; currentLineStartY = lineSet[i * 4 + 1]; currentLineEndX = lineSet[i * 4 + 2]; currentLineEndY = lineSet[i * 4 + 3]; if (i < lineSet.length / 4 - 1) { nextLineStartX = lineSet[(i + 1) * 4]; nextLineStartY = lineSet[(i + 1) * 4 + 1]; nextLineEndX = lineSet[(i + 1) * 4 + 2]; nextLineEndY = lineSet[(i + 1) * 4 + 3]; } else { nextLineStartX = lineSet[0]; nextLineStartY = lineSet[1]; nextLineEndX = lineSet[2]; nextLineEndY = lineSet[3]; } var intersection = this.finiteLinesIntersect(currentLineStartX, currentLineStartY, currentLineEndX, currentLineEndY, nextLineStartX, nextLineStartY, nextLineEndX, nextLineEndY, true); vertices[i * 2] = intersection[0]; vertices[i * 2 + 1] = intersection[1]; } return vertices; }; math.expandPolygon = function (points, pad) { var expandedLineSet = new Array(points.length * 2); var currentPointX = void 0, currentPointY = void 0, nextPointX = void 0, nextPointY = void 0; for (var i = 0; i < points.length / 2; i++) { currentPointX = points[i * 2]; currentPointY = points[i * 2 + 1]; if (i < points.length / 2 - 1) { nextPointX = points[(i + 1) * 2]; nextPointY = points[(i + 1) * 2 + 1]; } else { nextPointX = points[0]; nextPointY = points[1]; } // Current line: [currentPointX, currentPointY] to [nextPointX, nextPointY] // Assume CCW polygon winding var offsetX = nextPointY - currentPointY; var offsetY = -(nextPointX - currentPointX); // Normalize var offsetLength = Math.sqrt(offsetX * offsetX + offsetY * offsetY); var normalizedOffsetX = offsetX / offsetLength; var normalizedOffsetY = offsetY / offsetLength; expandedLineSet[i * 4] = currentPointX + normalizedOffsetX * pad; expandedLineSet[i * 4 + 1] = currentPointY + normalizedOffsetY * pad; expandedLineSet[i * 4 + 2] = nextPointX + normalizedOffsetX * pad; expandedLineSet[i * 4 + 3] = nextPointY + normalizedOffsetY * pad; } return expandedLineSet; }; math.intersectLineEllipse = function (x, y, centerX, centerY, ellipseWradius, ellipseHradius) { var dispX = centerX - x; var dispY = centerY - y; dispX /= ellipseWradius; dispY /= ellipseHradius; var len = Math.sqrt(dispX * dispX + dispY * dispY); var newLength = len - 1; if (newLength < 0) { return []; } var lenProportion = newLength / len; return [(centerX - x) * lenProportion + x, (centerY - y) * lenProportion + y]; }; math.checkInEllipse = function (x, y, width, height, centerX, centerY, padding) { x -= centerX; y -= centerY; x /= width / 2 + padding; y /= height / 2 + padding; return x * x + y * y <= 1; }; // Returns intersections of increasing distance from line's start point math.intersectLineCircle = function (x1, y1, x2, y2, centerX, centerY, radius) { // Calculate d, direction vector of line var d = [x2 - x1, y2 - y1]; // Direction vector of line var f = [x1 - centerX, y1 - centerY]; var a = d[0] * d[0] + d[1] * d[1]; var b = 2 * (f[0] * d[0] + f[1] * d[1]); var c = f[0] * f[0] + f[1] * f[1] - radius * radius; var discriminant = b * b - 4 * a * c; if (discriminant < 0) { return []; } var t1 = (-b + Math.sqrt(discriminant)) / (2 * a); var t2 = (-b - Math.sqrt(discriminant)) / (2 * a); var tMin = Math.min(t1, t2); var tMax = Math.max(t1, t2); var inRangeParams = []; if (tMin >= 0 && tMin <= 1) { inRangeParams.push(tMin); } if (tMax >= 0 && tMax <= 1) { inRangeParams.push(tMax); } if (inRangeParams.length === 0) { return []; } var nearIntersectionX = inRangeParams[0] * d[0] + x1; var nearIntersectionY = inRangeParams[0] * d[1] + y1; if (inRangeParams.length > 1) { if (inRangeParams[0] == inRangeParams[1]) { return [nearIntersectionX, nearIntersectionY]; } else { var farIntersectionX = inRangeParams[1] * d[0] + x1; var farIntersectionY = inRangeParams[1] * d[1] + y1; return [nearIntersectionX, nearIntersectionY, farIntersectionX, farIntersectionY]; } } else { return [nearIntersectionX, nearIntersectionY]; } }; math.findCircleNearPoint = function (centerX, centerY, radius, farX, farY) { var displacementX = farX - centerX; var displacementY = farY - centerY; var distance = Math.sqrt(displacementX * displacementX + displacementY * displacementY); var unitDisplacementX = displacementX / distance; var unitDisplacementY = displacementY / distance; return [centerX + unitDisplacementX * radius, centerY + unitDisplacementY * radius]; }; math.findMaxSqDistanceToOrigin = function (points) { var maxSqDistance = 0.000001; var sqDistance = void 0; for (var i = 0; i < points.length / 2; i++) { sqDistance = points[i * 2] * points[i * 2] + points[i * 2 + 1] * points[i * 2 + 1]; if (sqDistance > maxSqDistance) { maxSqDistance = sqDistance; } } return maxSqDistance; }; math.midOfThree = function (a, b, c) { if (b <= a && a <= c || c <= a && a <= b) { return a; } else if (a <= b && b <= c || c <= b && b <= a) { return b; } else { return c; } }; // (x1,y1)=>(x2,y2) intersect with (x3,y3)=>(x4,y4) math.finiteLinesIntersect = function (x1, y1, x2, y2, x3, y3, x4, y4, infiniteLines) { var dx13 = x1 - x3; var dx21 = x2 - x1; var dx43 = x4 - x3; var dy13 = y1 - y3; var dy21 = y2 - y1; var dy43 = y4 - y3; var ua_t = dx43 * dy13 - dy43 * dx13; var ub_t = dx21 * dy13 - dy21 * dx13; var u_b = dy43 * dx21 - dx43 * dy21; if (u_b !== 0) { var ua = ua_t / u_b; var ub = ub_t / u_b; var flptThreshold = 0.001; var min = 0 - flptThreshold; var max = 1 + flptThreshold; if (min <= ua && ua <= max && min <= ub && ub <= max) { return [x1 + ua * dx21, y1 + ua * dy21]; } else { if (!infiniteLines) { return []; } else { return [x1 + ua * dx21, y1 + ua * dy21]; } } } else { if (ua_t === 0 || ub_t === 0) { // Parallel, coincident lines. Check if overlap // Check endpoint of second line if (this.midOfThree(x1, x2, x4) === x4) { return [x4, y4]; } // Check start point of second line if (this.midOfThree(x1, x2, x3) === x3) { return [x3, y3]; } // Endpoint of first line if (this.midOfThree(x3, x4, x2) === x2) { return [x2, y2]; } return []; } else { // Parallel, non-coincident return []; } } }; // math.polygonIntersectLine( x, y, basePoints, centerX, centerY, width, height, padding ) // intersect a node polygon (pts transformed) // // math.polygonIntersectLine( x, y, basePoints, centerX, centerY ) // intersect the points (no transform) math.polygonIntersectLine = function (x, y, basePoints, centerX, centerY, width, height, padding) { var intersections = []; var intersection = void 0; var transformedPoints = new Array(basePoints.length); var doTransform = true; if (arguments.length === 5) { doTransform = false; } var points = void 0; if (doTransform) { for (var i = 0; i < transformedPoints.length / 2; i++) { transformedPoints[i * 2] = basePoints[i * 2] * width + centerX; transformedPoints[i * 2 + 1] = basePoints[i * 2 + 1] * height + centerY; } if (padding > 0) { var expandedLineSet = math.expandPolygon(transformedPoints, -padding); points = math.joinLines(expandedLineSet); } else { points = transformedPoints; } } else { points = basePoints; } var currentX = void 0, currentY = void 0, nextX = void 0, nextY = void 0; for (var _i = 0; _i < points.length / 2; _i++) { currentX = points[_i * 2]; currentY = points[_i * 2 + 1]; if (_i < points.length / 2 - 1) { nextX = points[(_i + 1) * 2]; nextY = points[(_i + 1) * 2 + 1]; } else { nextX = points[0]; nextY = points[1]; } intersection = this.finiteLinesIntersect(x, y, centerX, centerY, currentX, currentY, nextX, nextY); if (intersection.length !== 0) { intersections.push(intersection[0], intersection[1]); } } return intersections; }; math.shortenIntersection = function (intersection, offset, amount) { var disp = [intersection[0] - offset[0], intersection[1] - offset[1]]; var length = Math.sqrt(disp[0] * disp[0] + disp[1] * disp[1]); var lenRatio = (length - amount) / length; if (lenRatio < 0) { lenRatio = 0.00001; } return [offset[0] + lenRatio * disp[0], offset[1] + lenRatio * disp[1]]; }; math.generateUnitNgonPointsFitToSquare = function (sides, rotationRadians) { var points = math.generateUnitNgonPoints(sides, rotationRadians); points = math.fitPolygonToSquare(points); return points; }; math.fitPolygonToSquare = function (points) { var x = void 0, y = void 0; var sides = points.length / 2; var minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; for (var i = 0; i < sides; i++) { x = points[2 * i]; y = points[2 * i + 1]; minX = Math.min(minX, x); maxX = Math.max(maxX, x); minY = Math.min(minY, y); maxY = Math.max(maxY, y); } // stretch factors var sx = 2 / (maxX - minX); var sy = 2 / (maxY - minY); for (var _i2 = 0; _i2 < sides; _i2++) { x = points[2 * _i2] = points[2 * _i2] * sx; y = points[2 * _i2 + 1] = points[2 * _i2 + 1] * sy; minX = Math.min(minX, x); maxX = Math.max(maxX, x); minY = Math.min(minY, y); maxY = Math.max(maxY, y); } if (minY < -1) { for (var _i3 = 0; _i3 < sides; _i3++) { y = points[2 * _i3 + 1] = points[2 * _i3 + 1] + (-1 - minY); } } return points; }; math.generateUnitNgonPoints = function (sides, rotationRadians) { var increment = 1.0 / sides * 2 * Math.PI; var startAngle = sides % 2 === 0 ? Math.PI / 2.0 + increment / 2.0 : Math.PI / 2.0; startAngle += rotationRadians; var points = new Array(sides * 2); var currentAngle = void 0; for (var i = 0; i < sides; i++) { currentAngle = i * increment + startAngle; points[2 * i] = Math.cos(currentAngle); // x points[2 * i + 1] = Math.sin(-currentAngle); // y } return points; }; math.getRoundRectangleRadius = function (width, height) { // Set the default radius, unless half of width or height is smaller than default return Math.min(width / 4, height / 4, 8); }; math.getCutRectangleCornerLength = function () { return 8; }; math.bezierPtsToQuadCoeff = function (p0, p1, p2) { return [p0 - 2 * p1 + p2, 2 * (p1 - p0), p0]; }; math.getBarrelCurveConstants = function (width, height) { // get curve width, height, and control point position offsets as a percentage of node height / width return { heightOffset: Math.min(15, 0.05 * height), widthOffset: Math.min(100, 0.25 * width), ctrlPtOffsetPct: 0.05 }; }; module.exports = math; /***/ }), /* 3 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; module.exports = typeof window === 'undefined' ? null : window; // eslint-disable-line no-undef /***/ }), /* 4 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; // use this module to cherry pick functions into your prototype // (useful for functions shared between the core and collections, for example) // e.g. // let foo = define.foo({ /* params... */ }) var util = __webpack_require__(1); var define = {}; [__webpack_require__(44), __webpack_require__(46), __webpack_require__(47)].forEach(function (m) { util.assign(define, m); }); module.exports = define; /***/ }), /* 5 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /*! Embeddable Minimum Strictly-Compliant Promises/A+ 1.1.1 Thenable Copyright (c) 2013-2014 Ralf S. Engelschall (http://engelschall.com) Licensed under The MIT License (http://opensource.org/licenses/MIT) */ /* promise states [Promises/A+ 2.1] */ var STATE_PENDING = 0; /* [Promises/A+ 2.1.1] */ var STATE_FULFILLED = 1; /* [Promises/A+ 2.1.2] */ var STATE_REJECTED = 2; /* [Promises/A+ 2.1.3] */ /* promise object constructor */ var api = function api(executor) { /* optionally support non-constructor/plain-function call */ if (!(this instanceof api)) return new api(executor); /* initialize object */ this.id = 'Thenable/1.0.7'; this.state = STATE_PENDING; /* initial state */ this.fulfillValue = undefined; /* initial value */ /* [Promises/A+ 1.3, 2.1.2.2] */ this.rejectReason = undefined; /* initial reason */ /* [Promises/A+ 1.5, 2.1.3.2] */ this.onFulfilled = []; /* initial handlers */ this.onRejected = []; /* initial handlers */ /* provide optional information-hiding proxy */ this.proxy = { then: this.then.bind(this) }; /* support optional executor function */ if (typeof executor === 'function') executor.call(this, this.fulfill.bind(this), this.reject.bind(this)); }; /* promise API methods */ api.prototype = { /* promise resolving methods */ fulfill: function fulfill(value) { return deliver(this, STATE_FULFILLED, 'fulfillValue', value); }, reject: function reject(value) { return deliver(this, STATE_REJECTED, 'rejectReason', value); }, /* "The then Method" [Promises/A+ 1.1, 1.2, 2.2] */ then: function then(onFulfilled, onRejected) { var curr = this; var next = new api(); /* [Promises/A+ 2.2.7] */ curr.onFulfilled.push(resolver(onFulfilled, next, 'fulfill')); /* [Promises/A+ 2.2.2/2.2.6] */ curr.onRejected.push(resolver(onRejected, next, 'reject')); /* [Promises/A+ 2.2.3/2.2.6] */ execute(curr); return next.proxy; /* [Promises/A+ 2.2.7, 3.3] */ } }; /* deliver an action */ var deliver = function deliver(curr, state, name, value) { if (curr.state === STATE_PENDING) { curr.state = state; /* [Promises/A+ 2.1.2.1, 2.1.3.1] */ curr[name] = value; /* [Promises/A+ 2.1.2.2, 2.1.3.2] */ execute(curr); } return curr; }; /* execute all handlers */ var execute = function execute(curr) { if (curr.state === STATE_FULFILLED) execute_handlers(curr, 'onFulfilled', curr.fulfillValue);else if (curr.state === STATE_REJECTED) execute_handlers(curr, 'onRejected', curr.rejectReason); }; /* execute particular set of handlers */ var execute_handlers = function execute_handlers(curr, name, value) { /* global setImmediate: true */ /* global setTimeout: true */ /* short-circuit processing */ if (curr[name].length === 0) return; /* iterate over all handlers, exactly once */ var handlers = curr[name]; curr[name] = []; /* [Promises/A+ 2.2.2.3, 2.2.3.3] */ var func = function func() { for (var i = 0; i < handlers.length; i++) { handlers[i](value); } /* [Promises/A+ 2.2.5] */ }; /* execute procedure asynchronously */ /* [Promises/A+ 2.2.4, 3.1] */ if (typeof setImmediate === 'function') setImmediate(func);else setTimeout(func, 0); }; /* generate a resolver function */ var resolver = function resolver(cb, next, method) { return function (value) { if (typeof cb !== 'function') /* [Promises/A+ 2.2.1, 2.2.7.3, 2.2.7.4] */ next[method].call(next, value); /* [Promises/A+ 2.2.7.3, 2.2.7.4] */ else { var result; try { result = cb(value); } /* [Promises/A+ 2.2.2.1, 2.2.3.1, 2.2.5, 3.2] */ catch (e) { next.reject(e); /* [Promises/A+ 2.2.7.2] */ return; } resolve(next, result); /* [Promises/A+ 2.2.7.1] */ } }; }; /* "Promise Resolution Procedure" */ /* [Promises/A+ 2.3] */ var resolve = function resolve(promise, x) { /* sanity check arguments */ /* [Promises/A+ 2.3.1] */ if (promise === x || promise.proxy === x) { promise.reject(new TypeError('cannot resolve promise with itself')); return; } /* surgically check for a "then" method (mainly to just call the "getter" of "then" only once) */ var then; if ((typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object' && x !== null || typeof x === 'function') { try { then = x.then; } /* [Promises/A+ 2.3.3.1, 3.5] */ catch (e) { promise.reject(e); /* [Promises/A+ 2.3.3.2] */ return; } } /* handle own Thenables [Promises/A+ 2.3.2] and similar "thenables" [Promises/A+ 2.3.3] */ if (typeof then === 'function') { var resolved = false; try { /* call retrieved "then" method */ /* [Promises/A+ 2.3.3.3] */ then.call(x, /* resolvePromise */ /* [Promises/A+ 2.3.3.3.1] */ function (y) { if (resolved) return;resolved = true; /* [Promises/A+ 2.3.3.3.3] */ if (y === x) /* [Promises/A+ 3.6] */ promise.reject(new TypeError('circular thenable chain'));else resolve(promise, y); }, /* rejectPromise */ /* [Promises/A+ 2.3.3.3.2] */ function (r) { if (resolved) return;resolved = true; /* [Promises/A+ 2.3.3.3.3] */ promise.reject(r); }); } catch (e) { if (!resolved) /* [Promises/A+ 2.3.3.3.3] */ promise.reject(e); /* [Promises/A+ 2.3.3.3.4] */ } return; } /* handle other values */ promise.fulfill(x); /* [Promises/A+ 2.3.4, 2.3.3.4] */ }; // so we always have Promise.all() api.all = function (ps) { return new api(function (resolveAll, rejectAll) { var vals = new Array(ps.length); var doneCount = 0; var fulfill = function fulfill(i, val) { vals[i] = val; doneCount++; if (doneCount === ps.length) { resolveAll(vals); } }; for (var i = 0; i < ps.length; i++) { (function (i) { var p = ps[i]; var isPromise = p != null && p.then != null; if (isPromise) { p.then(function (val) { fulfill(i, val); }, function (err) { rejectAll(err); }); } else { var val = p; fulfill(i, val); } })(i); } }); }; api.resolve = function (val) { return new api(function (resolve, reject) { resolve(val); }); }; api.reject = function (val) { return new api(function (resolve, reject) { reject(val); }); }; module.exports = typeof Promise !== 'undefined' ? Promise : api; // eslint-disable-line no-undef /***/ }), /* 6 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var util = __webpack_require__(1); var newQuery = __webpack_require__(10); var Selector = function Selector(selector) { var self = this; self._private = { selectorText: selector, invalid: true }; if (selector == null || is.string(selector) && selector.match(/^\s*$/)) { self.length = 0; } else if (selector === '*' || selector === 'edge' || selector === 'node') { // make single, group-only selectors cheap to make and cheap to filter self[0] = newQuery(); self[0].group = selector === '*' ? selector : selector + 's'; self[0].groupOnly = true; self[0].length = 1; self._private.invalid = false; self.length = 1; } else if (is.elementOrCollection(selector)) { var collection = selector.collection(); self[0] = newQuery(); self[0].collection = collection; self[0].length = 1; self.length = 1; } else if (is.fn(selector)) { self[0] = newQuery(); self[0].filter = selector; self[0].length = 1; self.length = 1; } else if (is.string(selector)) { if (!self.parse(selector)) { return; } } else { util.error('A selector must be created from a string; found ', selector); return; } self._private.invalid = false; }; var selfn = Selector.prototype; selfn.valid = function () { return !this._private.invalid; }; selfn.invalid = function () { return this._private.invalid; }; selfn.text = function () { return this._private.selectorText; }; selfn.size = function () { return this.length; }; selfn.eq = function (i) { return this[i]; }; selfn.sameText = function (otherSel) { return this.text() === otherSel.text(); }; selfn.toString = selfn.selector = function () { if (this._private.toStringCache != null) { return this._private.toStringCache; } var i = void 0; var str = ''; var clean = function clean(obj) { if (obj == null) { return ''; } else { return obj; } }; var cleanVal = function cleanVal(val) { if (is.string(val)) { return '"' + val + '"'; } else { return clean(val); } }; var space = function space(val) { return ' ' + val + ' '; }; var queryToString = function queryToString(query) { var str = ''; var j = void 0, sel = void 0; if (query.subject === query) { str += '$'; } var group = clean(query.group); str += group.substring(0, group.length - 1); for (j = 0; j < query.data.length; j++) { var data = query.data[j]; if (data.value) { str += '[' + data.field + space(clean(data.operator)) + cleanVal(data.value) + ']'; } else { str += '[' + clean(data.operator) + data.field + ']'; } } for (j = 0; j < query.meta.length; j++) { var meta = query.meta[j]; str += '[[' + meta.field + space(clean(meta.operator)) + cleanVal(meta.value) + ']]'; } for (j = 0; j < query.colonSelectors.length; j++) { sel = query.colonSelectors[i]; str += sel; } for (j = 0; j < query.ids.length; j++) { sel = '#' + query.ids[i]; str += sel; } for (j = 0; j < query.classes.length; j++) { sel = '.' + query.classes[j]; str += sel; } if (query.source != null && query.target != null) { str = queryToString(query.source) + ' -> ' + queryToString(query.target); } if (query.connectedNodes != null) { var n = query.connectedNodes; str = queryToString(n[0]) + ' <-> ' + queryToString(n[1]); } if (query.parent != null) { str = queryToString(query.parent) + ' > ' + str; } if (query.ancestor != null) { str = queryToString(query.ancestor) + ' ' + str; } if (query.child != null) { str += ' > ' + queryToString(query.child); } if (query.descendant != null) { str += ' ' + queryToString(query.descendant); } return str; }; for (i = 0; i < this.length; i++) { var query = this[i]; str += queryToString(query); if (this.length > 1 && i < this.length - 1) { str += ', '; } } this._private.toStringCache = str; return str; }; [__webpack_require__(50), __webpack_require__(53)].forEach(function (p) { return util.assign(selfn, p); }); module.exports = Selector; /***/ }), /* 7 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var is = __webpack_require__(0); var Map = __webpack_require__(28); var Set = __webpack_require__(8); var Element = __webpack_require__(14); // factory for generating edge ids when no id is specified for a new element var idFactory = { generate: function generate(cy, element, tryThisId) { var id = tryThisId != null ? tryThisId : util.uuid(); while (cy.hasElementWithId(id)) { id = util.uuid(); } return id; } }; // represents a set of nodes, edges, or both together var Collection = function Collection(cy, elements, options) { if (cy === undefined || !is.core(cy)) { util.error('A collection must have a reference to the core'); return; } var map = new Map(); var createdElements = false; if (!elements) { elements = []; } else if (elements.length > 0 && is.plainObject(elements[0]) && !is.element(elements[0])) { createdElements = true; // make elements from json and restore all at once later var eles = []; var elesIds = new Set(); for (var i = 0, l = elements.length; i < l; i++) { var json = elements[i]; if (json.data == null) { json.data = {}; } var data = json.data; // make sure newly created elements have valid ids if (data.id == null) { data.id = idFactory.generate(cy, json); } else if (cy.hasElementWithId(data.id) || elesIds.has(data.id)) { continue; // can't create element if prior id already exists } var ele = new Element(cy, json, false); eles.push(ele); elesIds.add(data.id); } elements = eles; } this.length = 0; for (var _i = 0, _l = elements.length; _i < _l; _i++) { var element = elements[_i]; if (element == null) { continue; } var id = element._private.data.id; if (options == null || options.unique && !map.has(id)) { map.set(id, { index: this.length, ele: element }); this[this.length] = element; this.length++; } } this._private = { cy: cy, map: map }; // restore the elements if we created them from json if (createdElements) { this.restore(); } }; // Functions //////////////////////////////////////////////////////////////////////////////////////////////////// // keep the prototypes in sync (an element has the same functions as a collection) // and use elefn and elesfn as shorthands to the prototypes var elesfn = Element.prototype = Collection.prototype; elesfn.instanceString = function () { return 'collection'; }; elesfn.spawn = function (cy, eles, opts) { if (!is.core(cy)) { // cy is optional opts = eles; eles = cy; cy = this.cy(); } return new Collection(cy, eles, opts); }; elesfn.spawnSelf = function () { return this.spawn(this); }; elesfn.cy = function () { return this._private.cy; }; elesfn.renderer = function () { return this._private.cy.renderer(); }; elesfn.element = function () { return this[0]; }; elesfn.collection = function () { if (is.collection(this)) { return this; } else { // an element return new Collection(this._private.cy, [this]); } }; elesfn.unique = function () { return new Collection(this._private.cy, this, { unique: true }); }; elesfn.hasElementWithId = function (id) { return this._private.map.has(id); }; elesfn.getElementById = function (id) { var cy = this._private.cy; var entry = this._private.map.get(id); return entry ? entry.ele : new Collection(cy); // get ele or empty collection }; elesfn.$id = elesfn.getElementById; elesfn.poolIndex = function () { var cy = this._private.cy; var eles = cy._private.elements; var id = this._private.data.id; return eles._private.map.get(id).index; }; elesfn.json = function (obj) { var ele = this.element(); var cy = this.cy(); if (ele == null && obj) { return this; } // can't set to no eles if (ele == null) { return undefined; } // can't get from no eles var p = ele._private; if (is.plainObject(obj)) { // set cy.startBatch(); if (obj.data) { ele.data(obj.data); var data = p.data; if (ele.isEdge()) { // source and target are immutable via data() var move = false; var spec = {}; var src = obj.data.source; var tgt = obj.data.target; if (src != null && src !== data.source) { spec.source = src; move = true; } if (tgt != null && tgt !== data.target) { spec.target = tgt; move = true; } if (move) { ele = ele.move(spec); } } else { // parent is immutable via data() var parent = obj.data.parent; if (parent != null && parent !== data.parent) { ele = ele.move({ parent: parent }); } } } if (obj.position) { ele.position(obj.position); } // ignore group -- immutable var checkSwitch = function checkSwitch(k, trueFnName, falseFnName) { var obj_k = obj[k]; if (obj_k != null && obj_k !== p[k]) { if (obj_k) { ele[trueFnName](); } else { ele[falseFnName](); } } }; checkSwitch('removed', 'remove', 'restore'); checkSwitch('selected', 'select', 'unselect'); checkSwitch('selectable', 'selectify', 'unselectify'); checkSwitch('locked', 'lock', 'unlock'); checkSwitch('grabbable', 'grabify', 'ungrabify'); if (obj.classes != null) { ele.classes(obj.classes); } cy.endBatch(); return this; } else if (obj === undefined) { // get var json = { data: util.copy(p.data), position: util.copy(p.position), group: p.group, removed: p.removed, selected: p.selected, selectable: p.selectable, locked: p.locked, grabbable: p.grabbable, classes: null }; json.classes = ''; var i = 0; p.classes.forEach(function (cls) { return json.classes += i++ === 0 ? cls : ' ' + cls; }); return json; } }; elesfn.jsons = function () { var jsons = []; for (var i = 0; i < this.length; i++) { var ele = this[i]; var json = ele.json(); jsons.push(json); } return jsons; }; elesfn.clone = function () { var cy = this.cy(); var elesArr = []; for (var i = 0; i < this.length; i++) { var ele = this[i]; var json = ele.json(); var clone = new Element(cy, json, false); // NB no restore elesArr.push(clone); } return new Collection(cy, elesArr); }; elesfn.copy = elesfn.clone; elesfn.restore = function (notifyRenderer) { var self = this; var cy = self.cy(); var cy_p = cy._private; if (notifyRenderer === undefined) { notifyRenderer = true; } // create arrays of nodes and edges, since we need to // restore the nodes first var nodes = []; var edges = []; var elements = void 0; for (var _i2 = 0, l = self.length; _i2 < l; _i2++) { var ele = self[_i2]; if (!ele.removed()) { // don't need to handle this ele continue; } // keep nodes first in the array and edges after if (ele.isNode()) { // put to front of array if node nodes.push(ele); } else { // put to end of array if edge edges.push(ele); } } elements = nodes.concat(edges); var i = void 0; var removeFromElements = function removeFromElements() { elements.splice(i, 1); i--; }; // now, restore each element for (i = 0; i < elements.length; i++) { var _ele = elements[i]; var _private = _ele._private; var data = _private.data; // the traversal cache should start fresh when ele is added _ele.clearTraversalCache(); // set id and validate if (data.id === undefined) { data.id = idFactory.generate(cy, _ele); } else if (is.number(data.id)) { data.id = '' + data.id; // now it's a string } else if (is.emptyString(data.id) || !is.string(data.id)) { util.error('Can not create element with invalid string ID `' + data.id + '`'); // can't create element if it has empty string as id or non-string id removeFromElements(); continue; } else if (cy.hasElementWithId(data.id)) { util.error('Can not create second element with ID `' + data.id + '`'); // can't create element if one already has that id removeFromElements(); continue; } var id = data.id; // id is finalised, now let's keep a ref if (_ele.isNode()) { // extra checks for nodes var pos = _private.position; // make sure the nodes have a defined position if (pos.x == null) { pos.x = 0; } if (pos.y == null) { pos.y = 0; } } if (_ele.isEdge()) { // extra checks for edges var edge = _ele; var fields = ['source', 'target']; var fieldsLength = fields.length; var badSourceOrTarget = false; for (var j = 0; j < fieldsLength; j++) { var field = fields[j]; var val = data[field]; if (is.number(val)) { val = data[field] = '' + data[field]; // now string } if (val == null || val === '') { // can't create if source or target is not defined properly util.error('Can not create edge `' + id + '` with unspecified ' + field); badSourceOrTarget = true; } else if (!cy.hasElementWithId(val)) { // can't create edge if one of its nodes doesn't exist util.error('Can not create edge `' + id + '` with nonexistant ' + field + ' `' + val + '`'); badSourceOrTarget = true; } } if (badSourceOrTarget) { removeFromElements();continue; } // can't create this var src = cy.getElementById(data.source); var tgt = cy.getElementById(data.target); src._private.edges.push(edge); tgt._private.edges.push(edge); edge._private.source = src; edge._private.target = tgt; } // if is edge // create mock ids / indexes maps for element so it can be used like collections _private.map = new Map(); _private.map.set(id, { ele: _ele, index: 0 }); _private.removed = false; cy.addToPool(_ele); } // for each element // do compound node sanity checks for (var _i3 = 0; _i3 < nodes.length; _i3++) { // each node var node = nodes[_i3]; var _data = node._private.data; if (is.number(_data.parent)) { // then automake string _data.parent = '' + _data.parent; } var parentId = _data.parent; var specifiedParent = parentId != null; if (specifiedParent) { var parent = cy.getElementById(parentId); if (parent.empty()) { // non-existant parent; just remove it _data.parent = undefined; } else { var selfAsParent = false; var ancestor = parent; while (!ancestor.empty()) { if (node.same(ancestor)) { // mark self as parent and remove from data selfAsParent = true; _data.parent = undefined; // remove parent reference // exit or we loop forever break; } ancestor = ancestor.parent(); } if (!selfAsParent) { // connect with children parent[0]._private.children.push(node); node._private.parent = parent[0]; // let the core know we have a compound graph cy_p.hasCompoundNodes = true; } } // else } // if specified parent } // for each node if (elements.length > 0) { var restored = new Collection(cy, elements); for (var _i4 = 0; _i4 < restored.length; _i4++) { var _ele2 = restored[_i4]; if (_ele2.isNode()) { continue; } // adding an edge invalidates the traversal caches for the parallel edges _ele2.parallelEdges().clearTraversalCache(); // adding an edge invalidates the traversal cache for the connected nodes _ele2.source().clearTraversalCache(); _ele2.target().clearTraversalCache(); } var toUpdateStyle = void 0; if (cy_p.hasCompoundNodes) { toUpdateStyle = cy.collection().merge(restored).merge(restored.connectedNodes()).merge(restored.parent()); } else { toUpdateStyle = restored; } toUpdateStyle.dirtyCompoundBoundsCache().updateStyle(notifyRenderer); if (notifyRenderer) { restored.emitAndNotify('add'); } else { restored.emit('add'); } } return self; // chainability }; elesfn.removed = function () { var ele = this[0]; return ele && ele._private.removed; }; elesfn.inside = function () { var ele = this[0]; return ele && !ele._private.removed; }; elesfn.remove = function (notifyRenderer) { var self = this; var removed = []; var elesToRemove = []; var elesToRemoveIds = {}; var cy = self._private.cy; if (notifyRenderer === undefined) { notifyRenderer = true; } // add connected edges function addConnectedEdges(node) { var edges = node._private.edges; for (var i = 0; i < edges.length; i++) { add(edges[i]); } } // add descendant nodes function addChildren(node) { var children = node._private.children; for (var i = 0; i < children.length; i++) { add(children[i]); } } function add(ele) { var alreadyAdded = elesToRemoveIds[ele.id()]; if (ele.removed() || alreadyAdded) { return; } else { elesToRemoveIds[ele.id()] = true; } if (ele.isNode()) { elesToRemove.push(ele); // nodes are removed last addConnectedEdges(ele); addChildren(ele); } else { elesToRemove.unshift(ele); // edges are removed first } } // make the list of elements to remove // (may be removing more than specified due to connected edges etc) for (var i = 0, l = self.length; i < l; i++) { var ele = self[i]; add(ele); } function removeEdgeRef(node, edge) { var connectedEdges = node._private.edges; util.removeFromArray(connectedEdges, edge); // removing an edges invalidates the traversal cache for its nodes node.clearTraversalCache(); } function removeParallelRefs(edge) { // removing an edge invalidates the traversal caches for the parallel edges edge.parallelEdges().clearTraversalCache(); } var alteredParents = []; alteredParents.ids = {}; function removeChildRef(parent, ele) { ele = ele[0]; parent = parent[0]; var children = parent._private.children; var pid = parent.id(); util.removeFromArray(children, ele); if (!alteredParents.ids[pid]) { alteredParents.ids[pid] = true; alteredParents.push(parent); } } self.dirtyCompoundBoundsCache(); cy.removeFromPool(elesToRemove); // remove from core pool for (var _i5 = 0; _i5 < elesToRemove.length; _i5++) { var _ele3 = elesToRemove[_i5]; // mark as removed _ele3._private.removed = true; // add to list of removed elements removed.push(_ele3); if (_ele3.isEdge()) { // remove references to this edge in its connected nodes var src = _ele3.source()[0]; var tgt = _ele3.target()[0]; removeEdgeRef(src, _ele3); removeEdgeRef(tgt, _ele3); removeParallelRefs(_ele3); } else { // remove reference to parent var parent = _ele3.parent(); if (parent.length !== 0) { removeChildRef(parent, _ele3); } } } // check to see if we have a compound graph or not var elesStillInside = cy._private.elements; cy._private.hasCompoundNodes = false; for (var _i6 = 0; _i6 < elesStillInside.length; _i6++) { var _ele4 = elesStillInside[_i6]; if (_ele4.isParent()) { cy._private.hasCompoundNodes = true; break; } } var removedElements = new Collection(this.cy(), removed); if (removedElements.size() > 0) { // must manually notify since trigger won't do this automatically once removed if (notifyRenderer) { this.cy().notify({ type: 'remove', eles: removedElements }); } removedElements.emit('remove'); } // the parents who were modified by the removal need their style updated for (var _i7 = 0; _i7 < alteredParents.length; _i7++) { var _ele5 = alteredParents[_i7]; if (!_ele5.removed()) { _ele5.updateStyle(); } } return new Collection(cy, removed); }; elesfn.move = function (struct) { var cy = this._private.cy; if (struct.source !== undefined || struct.target !== undefined) { var srcId = struct.source; var tgtId = struct.target; var srcExists = cy.hasElementWithId(srcId); var tgtExists = cy.hasElementWithId(tgtId); if (srcExists || tgtExists) { var jsons = this.jsons(); this.remove(); for (var i = 0; i < jsons.length; i++) { var json = jsons[i]; var ele = this[i]; if (json.group === 'edges') { if (srcExists) { json.data.source = srcId; } if (tgtExists) { json.data.target = tgtId; } json.scratch = ele._private.scratch; } } return cy.add(jsons); } } else if (struct.parent !== undefined) { // move node to new parent var parentId = struct.parent; var parentExists = parentId === null || cy.hasElementWithId(parentId); if (parentExists) { var _jsons = this.jsons(); var descs = this.descendants(); var descsEtcJsons = descs.union(descs.union(this).connectedEdges()).jsons(); this.remove(); // NB: also removes descendants and their connected edges for (var _i8 = 0; _i8 < _jsons.length; _i8++) { var _json = _jsons[_i8]; var _ele6 = this[_i8]; if (_json.group === 'nodes') { _json.data.parent = parentId === null ? undefined : parentId; _json.scratch = _ele6._private.scratch; } } return cy.add(_jsons.concat(descsEtcJsons)); } } return this; // if nothing done }; [__webpack_require__(29), __webpack_require__(43), __webpack_require__(48), __webpack_require__(49), __webpack_require__(54), __webpack_require__(55), __webpack_require__(56), __webpack_require__(57), __webpack_require__(62), __webpack_require__(63), __webpack_require__(64), __webpack_require__(7), __webpack_require__(65), __webpack_require__(66), __webpack_require__(67), __webpack_require__(68), __webpack_require__(69)].forEach(function (props) { util.extend(elesfn, props); }); module.exports = Collection; /***/ }), /* 8 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /* global Set */ var undef = true ? 'undefined' : _typeof(undefined); var ObjectSet = function () { function ObjectSet(arrayOrObjectSet) { _classCallCheck(this, ObjectSet); this._obj = Object.create(null); if (arrayOrObjectSet != null) { var arr = void 0; if (arrayOrObjectSet.instanceString != null && arrayOrObjectSet.instanceString() === this.instanceString()) { arr = arrayOrObjectSet.toArray(); } else { arr = arrayOrObjectSet; } for (var i = 0; i < arr.length; i++) { this.add(arr[i]); } } } _createClass(ObjectSet, [{ key: 'instanceString', value: function instanceString() { return 'set'; } }, { key: 'add', value: function add(val) { this._obj[val] = 1; } }, { key: 'delete', value: function _delete(val) { this._obj[val] = 0; } }, { key: 'clear', value: function clear() { this._obj = Object.create(null); } }, { key: 'has', value: function has(val) { return this._obj[val] === 1; } }, { key: 'toArray', value: function toArray() { var _this = this; return Object.keys(this._obj).filter(function (key) { return _this.has(key); }); } }, { key: 'forEach', value: function forEach(callback, thisArg) { return this.toArray().forEach(callback, thisArg); } }, { key: 'size', get: function get() { return this.toArray().length; } }]); return ObjectSet; }(); // TODO use the stdlib Set in future... // module.exports = typeof Set !== undef ? Set : ObjectSet; module.exports = ObjectSet; /***/ }), /* 9 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; module.exports = __webpack_require__(32); /***/ }), /* 10 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; // storage for parsed queries var newQuery = function newQuery() { return { classes: [], colonSelectors: [], data: [], group: null, ids: [], meta: [], // fake selectors collection: null, // a collection to match against filter: null, // filter function // these are defined in the upward direction rather than down (e.g. child) // because we need to go up in Selector.filter() parent: null, // parent query obj ancestor: null, // ancestor query obj subject: null, // defines subject in compound query (subject query obj; points to self if subject) // use these only when subject has been defined child: null, descendant: null }; }; module.exports = newQuery; /***/ }), /* 11 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var is = __webpack_require__(0); var Event = __webpack_require__(16); var eventRegex = /^([^.]+)(\.(?:[^.]+))?$/; // regex for matching event strings (e.g. "click.namespace") var universalNamespace = '.*'; // matches as if no namespace specified and prevents users from unbinding accidentally var defaults = { qualifierCompare: function qualifierCompare(q1, q2) { return q1 === q2; }, eventMatches: function eventMatches() /*context, listener, eventObj*/{ return true; }, eventFields: function eventFields() /*context*/{ return {}; }, callbackContext: function callbackContext(context /*, listener, eventObj*/) { return context; }, beforeEmit: function beforeEmit() /* context, listener, eventObj */{}, afterEmit: function afterEmit() /* context, listener, eventObj */{}, bubble: function bubble() /*context*/{ return false; }, parent: function parent() /*context*/{ return null; }, context: undefined }; function Emitter(opts) { util.assign(this, defaults, opts); this.listeners = []; this.emitting = 0; } var p = Emitter.prototype; var forEachEvent = function forEachEvent(self, handler, events, qualifier, callback, conf, confOverrides) { if (is.fn(qualifier)) { callback = qualifier; qualifier = null; } if (confOverrides) { if (conf == null) { conf = confOverrides; } else { conf = util.assign({}, conf, confOverrides); } } var eventList = events.split(/\s+/); for (var i = 0; i < eventList.length; i++) { var evt = eventList[i]; if (is.emptyString(evt)) { continue; } var match = evt.match(eventRegex); // type[.namespace] if (match) { var type = match[1]; var namespace = match[2] ? match[2] : null; var ret = handler(self, evt, type, namespace, qualifier, callback, conf); if (ret === false) { break; } // allow exiting early } } }; var makeEventObj = function makeEventObj(self, obj) { return new Event(obj.type, util.assign(obj, self.eventFields(self.context))); }; var forEachEventObj = function forEachEventObj(self, handler, events) { if (is.event(events)) { handler(self, events); return; } else if (is.plainObject(events)) { handler(self, makeEventObj(self, events)); return; } var eventList = events.split(/\s+/); for (var i = 0; i < eventList.length; i++) { var evt = eventList[i]; if (is.emptyString(evt)) { continue; } var match = evt.match(eventRegex); // type[.namespace] if (match) { var type = match[1]; var namespace = match[2] ? match[2] : null; var eventObj = makeEventObj(self, { type: type, namespace: namespace, target: self.context }); handler(self, eventObj); } } }; p.on = p.addListener = function (events, qualifier, callback, conf, confOverrides) { forEachEvent(this, function (self, event, type, namespace, qualifier, callback, conf) { if (is.fn(callback)) { self.listeners.push({ event: event, // full event string callback: callback, // callback to run type: type, // the event type (e.g. 'click') namespace: namespace, // the event namespace (e.g. ".foo") qualifier: qualifier, // a restriction on whether to match this emitter conf: conf // additional configuration }); } }, events, qualifier, callback, conf, confOverrides); return this; }; p.one = function (events, qualifier, callback, conf) { return this.on(events, qualifier, callback, conf, { one: true }); }; p.removeListener = p.off = function (events, qualifier, callback, conf) { var _this = this; if (this.emitting !== 0) { this.listeners = util.copyArray(this.listeners); } var listeners = this.listeners; var _loop = function _loop(i) { var listener = listeners[i]; forEachEvent(_this, function (self, event, type, namespace, qualifier, callback /*, conf*/) { if (listener.type === type && (!namespace || listener.namespace === namespace) && (!qualifier || self.qualifierCompare(listener.qualifier, qualifier)) && (!callback || listener.callback === callback)) { listeners.splice(i, 1); return false; } }, events, qualifier, callback, conf); }; for (var i = listeners.length - 1; i >= 0; i--) { _loop(i); } return this; }; p.emit = p.trigger = function (events, extraParams, manualCallback) { var listeners = this.listeners; var numListenersBeforeEmit = listeners.length; this.emitting++; if (!is.array(extraParams)) { extraParams = [extraParams]; } forEachEventObj(this, function (self, eventObj) { if (manualCallback != null) { listeners = [{ event: eventObj.event, type: eventObj.type, namespace: eventObj.namespace, callback: manualCallback }]; numListenersBeforeEmit = listeners.length; } var _loop2 = function _loop2(i) { var listener = listeners[i]; if (listener.type === eventObj.type && (!listener.namespace || listener.namespace === eventObj.namespace || listener.namespace === universalNamespace) && self.eventMatches(self.context, listener, eventObj)) { var args = [eventObj]; if (extraParams != null) { util.push(args, extraParams); } self.beforeEmit(self.context, listener, eventObj); if (listener.conf && listener.conf.one) { self.listeners = self.listeners.filter(function (l) { return l !== listener; }); } var context = self.callbackContext(self.context, listener, eventObj); var ret = listener.callback.apply(context, args); self.afterEmit(self.context, listener, eventObj); if (ret === false) { eventObj.stopPropagation(); eventObj.preventDefault(); } } // if listener matches }; for (var i = 0; i < numListenersBeforeEmit; i++) { _loop2(i); } // for listener if (self.bubble(self.context) && !eventObj.isPropagationStopped()) { self.parent(self.context).emit(eventObj, extraParams); } }, events); this.emitting--; return this; }; module.exports = Emitter; /***/ }), /* 12 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var window = __webpack_require__(3); var util = __webpack_require__(1); var Collection = __webpack_require__(7); var is = __webpack_require__(0); var Promise = __webpack_require__(5); var define = __webpack_require__(4); var Core = function Core(opts) { var cy = this; opts = util.extend({}, opts); var container = opts.container; // allow for passing a wrapped jquery object // e.g. cytoscape({ container: $('#cy') }) if (container && !is.htmlElement(container) && is.htmlElement(container[0])) { container = container[0]; } var reg = container ? container._cyreg : null; // e.g. already registered some info (e.g. readies) via jquery reg = reg || {}; if (reg && reg.cy) { reg.cy.destroy(); reg = {}; // old instance => replace reg completely } var readies = reg.readies = reg.readies || []; if (container) { container._cyreg = reg; } // make sure container assoc'd reg points to this cy reg.cy = cy; var head = window !== undefined && container !== undefined && !opts.headless; var options = opts; options.layout = util.extend({ name: head ? 'grid' : 'null' }, options.layout); options.renderer = util.extend({ name: head ? 'canvas' : 'null' }, options.renderer); var defVal = function defVal(def, val, altVal) { if (val !== undefined) { return val; } else if (altVal !== undefined) { return altVal; } else { return def; } }; var _p = this._private = { container: container, // html dom ele container ready: false, // whether ready has been triggered options: options, // cached options elements: new Collection(this), // elements in the graph listeners: [], // list of listeners aniEles: new Collection(this), // elements being animated scratch: {}, // scratch object for core layout: null, renderer: null, destroyed: false, // whether destroy was called notificationsEnabled: true, // whether notifications are sent to the renderer minZoom: 1e-50, maxZoom: 1e50, zoomingEnabled: defVal(true, options.zoomingEnabled), userZoomingEnabled: defVal(true, options.userZoomingEnabled), panningEnabled: defVal(true, options.panningEnabled), userPanningEnabled: defVal(true, options.userPanningEnabled), boxSelectionEnabled: defVal(true, options.boxSelectionEnabled), autolock: defVal(false, options.autolock, options.autolockNodes), autoungrabify: defVal(false, options.autoungrabify, options.autoungrabifyNodes), autounselectify: defVal(false, options.autounselectify), styleEnabled: options.styleEnabled === undefined ? head : options.styleEnabled, zoom: is.number(options.zoom) ? options.zoom : 1, pan: { x: is.plainObject(options.pan) && is.number(options.pan.x) ? options.pan.x : 0, y: is.plainObject(options.pan) && is.number(options.pan.y) ? options.pan.y : 0 }, animation: { // object for currently-running animations current: [], queue: [] }, hasCompoundNodes: false }; this.createEmitter(); // set selection type var selType = options.selectionType; if (selType === undefined || selType !== 'additive' && selType !== 'single') { // then set default _p.selectionType = 'single'; } else { _p.selectionType = selType; } // init zoom bounds if (is.number(options.minZoom) && is.number(options.maxZoom) && options.minZoom < options.maxZoom) { _p.minZoom = options.minZoom; _p.maxZoom = options.maxZoom; } else if (is.number(options.minZoom) && options.maxZoom === undefined) { _p.minZoom = options.minZoom; } else if (is.number(options.maxZoom) && options.minZoom === undefined) { _p.maxZoom = options.maxZoom; } var loadExtData = function loadExtData(extData, next) { var anyIsPromise = extData.some(is.promise); if (anyIsPromise) { return Promise.all(extData).then(next); // load all data asynchronously, then exec rest of init } else { next(extData); // exec synchronously for convenience } }; // start with the default stylesheet so we have something before loading an external stylesheet if (_p.styleEnabled) { cy.setStyle([]); } // create the renderer cy.initRenderer(util.extend({ hideEdgesOnViewport: options.hideEdgesOnViewport, textureOnViewport: options.textureOnViewport, wheelSensitivity: is.number(options.wheelSensitivity) && options.wheelSensitivity > 0 ? options.wheelSensitivity : 1, motionBlur: options.motionBlur === undefined ? false : options.motionBlur, // off by default motionBlurOpacity: options.motionBlurOpacity === undefined ? 0.05 : options.motionBlurOpacity, pixelRatio: is.number(options.pixelRatio) && options.pixelRatio > 0 ? options.pixelRatio : undefined, desktopTapThreshold: options.desktopTapThreshold === undefined ? 4 : options.desktopTapThreshold, touchTapThreshold: options.touchTapThreshold === undefined ? 8 : options.touchTapThreshold }, options.renderer)); var setElesAndLayout = function setElesAndLayout(elements, onload, ondone) { cy.notifications(false); // remove old elements var oldEles = cy.mutableElements(); if (oldEles.length > 0) { oldEles.remove(); } if (elements != null) { if (is.plainObject(elements) || is.array(elements)) { cy.add(elements); } } cy.one('layoutready', function (e) { cy.notifications(true); cy.emit(e); // we missed this event by turning notifications off, so pass it on cy.notify({ type: 'load', eles: cy.mutableElements() }); cy.one('load', onload); cy.emit('load'); }).one('layoutstop', function () { cy.one('done', ondone); cy.emit('done'); }); var layoutOpts = util.extend({}, cy._private.options.layout); layoutOpts.eles = cy.elements(); cy.layout(layoutOpts).run(); }; loadExtData([options.style, options.elements], function (thens) { var initStyle = thens[0]; var initEles = thens[1]; // init style if (_p.styleEnabled) { cy.style().append(initStyle); } // initial load setElesAndLayout(initEles, function () { // onready cy.startAnimationLoop(); _p.ready = true; // if a ready callback is specified as an option, the bind it if (is.fn(options.ready)) { cy.on('ready', options.ready); } // bind all the ready handlers registered before creating this instance for (var i = 0; i < readies.length; i++) { var fn = readies[i]; cy.on('ready', fn); } if (reg) { reg.readies = []; } // clear b/c we've bound them all and don't want to keep it around in case a new core uses the same div etc cy.emit('ready'); }, options.done); }); }; var corefn = Core.prototype; // short alias util.extend(corefn, { instanceString: function instanceString() { return 'core'; }, isReady: function isReady() { return this._private.ready; }, isDestroyed: function isDestroyed() { return this._private.destroyed; }, ready: function ready(fn) { if (this.isReady()) { this.emitter().emit('ready', [], fn); // just calls fn as though triggered via ready event } else { this.on('ready', fn); } return this; }, destroy: function destroy() { var cy = this; if (cy.isDestroyed()) return; cy.stopAnimationLoop(); cy.destroyRenderer(); this.emit('destroy'); cy._private.destroyed = true; return cy; }, hasElementWithId: function hasElementWithId(id) { return this._private.elements.hasElementWithId(id); }, getElementById: function getElementById(id) { return this._private.elements.getElementById(id); }, selectionType: function selectionType() { return this._private.selectionType; }, hasCompoundNodes: function hasCompoundNodes() { return this._private.hasCompoundNodes; }, headless: function headless() { return this._private.options.renderer.name === 'null'; }, styleEnabled: function styleEnabled() { return this._private.styleEnabled; }, addToPool: function addToPool(eles) { this._private.elements.merge(eles); return this; // chaining }, removeFromPool: function removeFromPool(eles) { this._private.elements.unmerge(eles); return this; }, container: function container() { return this._private.container; }, options: function options() { return util.copy(this._private.options); }, json: function json(obj) { var cy = this; var _p = cy._private; var eles = cy.mutableElements(); if (is.plainObject(obj)) { // set cy.startBatch(); if (obj.elements) { var idInJson = {}; var updateEles = function updateEles(jsons, gr) { var toAdd = []; for (var i = 0; i < jsons.length; i++) { var json = jsons[i]; var id = json.data.id; var ele = cy.getElementById(id); idInJson[id] = true; if (ele.length !== 0) { // existing element should be updated ele.json(json); } else { // otherwise should be added if (gr) { toAdd.push(util.extend({ group: gr }, json)); } else { toAdd.push(json); } } } cy.add(toAdd); }; if (is.array(obj.elements)) { // elements: [] updateEles(obj.elements); } else { // elements: { nodes: [], edges: [] } var grs = ['nodes', 'edges']; for (var i = 0; i < grs.length; i++) { var gr = grs[i]; var elements = obj.elements[gr]; if (is.array(elements)) { updateEles(elements, gr); } } } // elements not specified in json should be removed eles.stdFilter(function (ele) { return !idInJson[ele.id()]; }).remove(); } if (obj.style) { cy.style(obj.style); } if (obj.zoom != null && obj.zoom !== _p.zoom) { cy.zoom(obj.zoom); } if (obj.pan) { if (obj.pan.x !== _p.pan.x || obj.pan.y !== _p.pan.y) { cy.pan(obj.pan); } } var fields = ['minZoom', 'maxZoom', 'zoomingEnabled', 'userZoomingEnabled', 'panningEnabled', 'userPanningEnabled', 'boxSelectionEnabled', 'autolock', 'autoungrabify', 'autounselectify']; for (var _i = 0; _i < fields.length; _i++) { var f = fields[_i]; if (obj[f] != null) { cy[f](obj[f]); } } cy.endBatch(); return this; // chaining } else if (obj === undefined) { // get var json = {}; json.elements = {}; eles.forEach(function (ele) { var group = ele.group(); if (!json.elements[group]) { json.elements[group] = []; } json.elements[group].push(ele.json()); }); if (this._private.styleEnabled) { json.style = cy.style().json(); } json.zoomingEnabled = cy._private.zoomingEnabled; json.userZoomingEnabled = cy._private.userZoomingEnabled; json.zoom = cy._private.zoom; json.minZoom = cy._private.minZoom; json.maxZoom = cy._private.maxZoom; json.panningEnabled = cy._private.panningEnabled; json.userPanningEnabled = cy._private.userPanningEnabled; json.pan = util.copy(cy._private.pan); json.boxSelectionEnabled = cy._private.boxSelectionEnabled; json.renderer = util.copy(cy._private.options.renderer); json.hideEdgesOnViewport = cy._private.options.hideEdgesOnViewport; json.textureOnViewport = cy._private.options.textureOnViewport; json.wheelSensitivity = cy._private.options.wheelSensitivity; json.motionBlur = cy._private.options.motionBlur; return json; } }, scratch: define.data({ field: 'scratch', bindingEvent: 'scratch', allowBinding: true, allowSetting: true, settingEvent: 'scratch', settingTriggersEvent: true, triggerFnName: 'trigger', allowGetting: true }), removeScratch: define.removeData({ field: 'scratch', event: 'scratch', triggerFnName: 'trigger', triggerEvent: true }) }); corefn.$id = corefn.getElementById; [__webpack_require__(70), __webpack_require__(71), __webpack_require__(79), __webpack_require__(80), __webpack_require__(81), __webpack_require__(82), __webpack_require__(83), __webpack_require__(84), __webpack_require__(85), __webpack_require__(94)].forEach(function (props) { util.extend(corefn, props); }); module.exports = Core; /***/ }), /* 13 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; module.exports = function memoize(fn, keyFn) { if (!keyFn) { keyFn = function keyFn() { if (arguments.length === 1) { return arguments[0]; } else if (arguments.length === 0) { return 'undefined'; } var args = []; for (var i = 0; i < arguments.length; i++) { args.push(arguments[i]); } return args.join('$'); }; } var memoizedFn = function memoizedFn() { var self = this; var args = arguments; var ret = void 0; var k = keyFn.apply(self, args); var cache = memoizedFn.cache; if (!(ret = cache[k])) { ret = cache[k] = fn.apply(self, args); } return ret; }; memoizedFn.cache = {}; return memoizedFn; }; /***/ }), /* 14 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var is = __webpack_require__(0); var Set = __webpack_require__(8); // represents a node or an edge var Element = function Element(cy, params, restore) { restore = restore === undefined || restore ? true : false; if (cy === undefined || params === undefined || !is.core(cy)) { util.error('An element must have a core reference and parameters set'); return; } var group = params.group; // try to automatically infer the group if unspecified if (group == null) { if (params.data && params.data.source != null && params.data.target != null) { group = 'edges'; } else { group = 'nodes'; } } // validate group if (group !== 'nodes' && group !== 'edges') { util.error('An element must be of type `nodes` or `edges`; you specified `' + group + '`'); return; } // make the element array-like, just like a collection this.length = 1; this[0] = this; // NOTE: when something is added here, add also to ele.json() var _p = this._private = { cy: cy, single: true, // indicates this is an element data: params.data || {}, // data object position: params.position || {}, // (x, y) position pair autoWidth: undefined, // width and height of nodes calculated by the renderer when set to special 'auto' value autoHeight: undefined, autoPadding: undefined, compoundBoundsClean: false, // whether the compound dimensions need to be recalculated the next time dimensions are read listeners: [], // array of bound listeners group: group, // string; 'nodes' or 'edges' style: {}, // properties as set by the style rstyle: {}, // properties for style sent from the renderer to the core styleCxts: [], // applied style contexts from the styler removed: true, // whether it's inside the vis; true if removed (set true here since we call restore) selected: params.selected ? true : false, // whether it's selected selectable: params.selectable === undefined ? true : params.selectable ? true : false, // whether it's selectable locked: params.locked ? true : false, // whether the element is locked (cannot be moved) grabbed: false, // whether the element is grabbed by the mouse; renderer sets this privately grabbable: params.grabbable === undefined ? true : params.grabbable ? true : false, // whether the element can be grabbed active: false, // whether the element is active from user interaction classes: new Set(), // map ( className => true ) animation: { // object for currently-running animations current: [], queue: [] }, rscratch: {}, // object in which the renderer can store information scratch: params.scratch || {}, // scratch objects edges: [], // array of connected edges children: [], // array of children parent: null, // parent ref traversalCache: {}, // cache of output of traversal functions backgrounding: false // whether background images are loading }; // renderedPosition overrides if specified if (params.renderedPosition) { var rpos = params.renderedPosition; var pan = cy.pan(); var zoom = cy.zoom(); _p.position = { x: (rpos.x - pan.x) / zoom, y: (rpos.y - pan.y) / zoom }; } if (is.string(params.classes)) { var classes = params.classes.split(/\s+/); for (var i = 0, l = classes.length; i < l; i++) { var cls = classes[i]; if (!cls || cls === '') { continue; } _p.classes.add(cls); } } if (params.style || params.css) { cy.style().applyBypass(this, params.style || params.css); } this.createEmitter(); if (restore === undefined || restore) { this.restore(); } }; module.exports = Element; /***/ }), /* 15 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var stateSelectors = [{ selector: ':selected', matches: function matches(ele) { return ele.selected(); } }, { selector: ':unselected', matches: function matches(ele) { return !ele.selected(); } }, { selector: ':selectable', matches: function matches(ele) { return ele.selectable(); } }, { selector: ':unselectable', matches: function matches(ele) { return !ele.selectable(); } }, { selector: ':locked', matches: function matches(ele) { return ele.locked(); } }, { selector: ':unlocked', matches: function matches(ele) { return !ele.locked(); } }, { selector: ':visible', matches: function matches(ele) { return ele.visible(); } }, { selector: ':hidden', matches: function matches(ele) { return !ele.visible(); } }, { selector: ':transparent', matches: function matches(ele) { return ele.transparent(); } }, { selector: ':grabbed', matches: function matches(ele) { return ele.grabbed(); } }, { selector: ':free', matches: function matches(ele) { return !ele.grabbed(); } }, { selector: ':removed', matches: function matches(ele) { return ele.removed(); } }, { selector: ':inside', matches: function matches(ele) { return !ele.removed(); } }, { selector: ':grabbable', matches: function matches(ele) { return ele.grabbable(); } }, { selector: ':ungrabbable', matches: function matches(ele) { return !ele.grabbable(); } }, { selector: ':animated', matches: function matches(ele) { return ele.animated(); } }, { selector: ':unanimated', matches: function matches(ele) { return !ele.animated(); } }, { selector: ':parent', matches: function matches(ele) { return ele.isParent(); } }, { selector: ':childless', matches: function matches(ele) { return ele.isChildless(); } }, { selector: ':child', matches: function matches(ele) { return ele.isChild(); } }, { selector: ':orphan', matches: function matches(ele) { return ele.isOrphan(); } }, { selector: ':nonorphan', matches: function matches(ele) { return ele.isChild(); } }, { selector: ':loop', matches: function matches(ele) { return ele.isLoop(); } }, { selector: ':simple', matches: function matches(ele) { return ele.isSimple(); } }, { selector: ':active', matches: function matches(ele) { return ele.active(); } }, { selector: ':inactive', matches: function matches(ele) { return !ele.active(); } }, { selector: ':backgrounding', matches: function matches(ele) { return ele.backgrounding(); } }, { selector: ':nonbackgrounding', matches: function matches(ele) { return !ele.backgrounding(); } }].sort(function (a, b) { // n.b. selectors that are starting substrings of others must have the longer ones first return util.sort.descending(a.selector, b.selector); }); var stateSelectorMatches = function stateSelectorMatches(sel, ele) { var lookup = stateSelectorMatches.lookup = stateSelectorMatches.lookup || function () { var selToFn = {}; var s = void 0; for (var i = 0; i < stateSelectors.length; i++) { s = stateSelectors[i]; selToFn[s.selector] = s.matches; } return selToFn; }(); return lookup[sel](ele); }; var stateSelectorRegex = '(' + stateSelectors.map(function (s) { return s.selector; }).join('|') + ')'; module.exports = { stateSelectors: stateSelectors, stateSelectorMatches: stateSelectorMatches, stateSelectorRegex: stateSelectorRegex }; /***/ }), /* 16 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! Event object based on jQuery events, MIT license https://jquery.org/license/ https://tldrlegal.com/license/mit-license https://github.com/jquery/jquery/blob/master/src/event.js */ var Event = function Event(src, props) { this.recycle(src, props); }; function returnFalse() { return false; } function returnTrue() { return true; } // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html Event.prototype = { instanceString: function instanceString() { return 'event'; }, recycle: function recycle(src, props) { this.isImmediatePropagationStopped = this.isPropagationStopped = this.isDefaultPrevented = returnFalse; if (src != null && src.preventDefault) { // Browser Event object this.type = src.type; // Events bubbling up the document may have been marked as prevented // by a handler lower down the tree; reflect the correct value. this.isDefaultPrevented = src.defaultPrevented ? returnTrue : returnFalse; } else if (src != null && src.type) { // Plain object containing all event details props = src; } else { // Event string this.type = src; } // Put explicitly provided properties onto the event object if (props != null) { // more efficient to manually copy fields we use this.originalEvent = props.originalEvent; this.type = props.type != null ? props.type : this.type; this.cy = props.cy; this.target = props.target; this.position = props.position; this.renderedPosition = props.renderedPosition; this.namespace = props.namespace; this.layout = props.layout; } if (this.cy != null && this.position != null && this.renderedPosition == null) { // create a rendered position based on the passed position var pos = this.position; var zoom = this.cy.zoom(); var pan = this.cy.pan(); this.renderedPosition = { x: pos.x * zoom + pan.x, y: pos.y * zoom + pan.y }; } // Create a timestamp if incoming event doesn't have one this.timeStamp = src && src.timeStamp || Date.now(); }, preventDefault: function preventDefault() { this.isDefaultPrevented = returnTrue; var e = this.originalEvent; if (!e) { return; } // if preventDefault exists run it on the original event if (e.preventDefault) { e.preventDefault(); } }, stopPropagation: function stopPropagation() { this.isPropagationStopped = returnTrue; var e = this.originalEvent; if (!e) { return; } // if stopPropagation exists run it on the original event if (e.stopPropagation) { e.stopPropagation(); } }, stopImmediatePropagation: function stopImmediatePropagation() { this.isImmediatePropagationStopped = returnTrue; this.stopPropagation(); }, isDefaultPrevented: returnFalse, isPropagationStopped: returnFalse, isImmediatePropagationStopped: returnFalse }; module.exports = Event; /***/ }), /* 17 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /** * Elements are drawn in a specific order based on compound depth (low to high), the element type (nodes above edges), * and z-index (low to high). These styles affect how this applies: * * z-compound-depth: May be `bottom | orphan | auto | top`. The first drawn is `bottom`, then `orphan` which is the * same depth as the root of the compound graph, followed by the default value `auto` which draws in order from * root to leaves of the compound graph. The last drawn is `top`. * z-index-compare: May be `auto | manual`. The default value is `auto` which always draws edges under nodes. * `manual` ignores this convention and draws based on the `z-index` value setting. * z-index: An integer value that affects the relative draw order of elements. In general, an element with a higher * `z-index` will be drawn on top of an element with a lower `z-index`. */ var util = __webpack_require__(1); var zIndexSort = function zIndexSort(a, b) { var cy = a.cy(); var hasCompoundNodes = cy.hasCompoundNodes(); function getDepth(ele) { var style = ele.pstyle('z-compound-depth'); if (style.value === 'auto') { return hasCompoundNodes ? ele.zDepth() : 0; } else if (style.value === 'bottom') { return -1; } else if (style.value === 'top') { return util.MAX_INT; } // 'orphan' return 0; } var depthDiff = getDepth(a) - getDepth(b); if (depthDiff !== 0) { return depthDiff; } function getEleDepth(ele) { var style = ele.pstyle('z-index-compare'); if (style.value === 'auto') { return ele.isNode() ? 1 : 0; } // 'manual' return 0; } var eleDiff = getEleDepth(a) - getEleDepth(b); if (eleDiff !== 0) { return eleDiff; } var zDiff = a.pstyle('z-index').value - b.pstyle('z-index').value; if (zDiff !== 0) { return zDiff; } // compare indices in the core (order added to graph w/ last on top) return a.poolIndex() - b.poolIndex(); }; module.exports = zIndexSort; /***/ }), /* 18 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var util = __webpack_require__(1); var Selector = __webpack_require__(6); var Style = function Style(cy) { if (!(this instanceof Style)) { return new Style(cy); } if (!is.core(cy)) { util.error('A style must have a core reference'); return; } this._private = { cy: cy, coreStyle: {} }; this.length = 0; this.resetToDefault(); }; var styfn = Style.prototype; styfn.instanceString = function () { return 'style'; }; // remove all contexts styfn.clear = function () { for (var i = 0; i < this.length; i++) { this[i] = undefined; } this.length = 0; var _p = this._private; _p.newStyle = true; return this; // chaining }; styfn.resetToDefault = function () { this.clear(); this.addDefaultStylesheet(); return this; }; // builds a style object for the 'core' selector styfn.core = function () { return this._private.coreStyle; }; // create a new context from the specified selector string and switch to that context styfn.selector = function (selectorStr) { // 'core' is a special case and does not need a selector var selector = selectorStr === 'core' ? null : new Selector(selectorStr); var i = this.length++; // new context means new index this[i] = { selector: selector, properties: [], mappedProperties: [], index: i }; return this; // chaining }; // add one or many css rules to the current context styfn.css = function () { var self = this; var args = arguments; switch (args.length) { case 1: var map = args[0]; for (var i = 0; i < self.properties.length; i++) { var prop = self.properties[i]; var mapVal = map[prop.name]; if (mapVal === undefined) { mapVal = map[util.dash2camel(prop.name)]; } if (mapVal !== undefined) { this.cssRule(prop.name, mapVal); } } break; case 2: this.cssRule(args[0], args[1]); break; default: break; // do nothing if args are invalid } return this; // chaining }; styfn.style = styfn.css; // add a single css rule to the current context styfn.cssRule = function (name, value) { // name-value pair var property = this.parse(name, value); // add property to current context if valid if (property) { var i = this.length - 1; this[i].properties.push(property); this[i].properties[property.name] = property; // allow access by name as well if (property.name.match(/pie-(\d+)-background-size/) && property.value) { this._private.hasPie = true; } if (property.mapped) { this[i].mappedProperties.push(property); } // add to core style if necessary var currentSelectorIsCore = !this[i].selector; if (currentSelectorIsCore) { this._private.coreStyle[property.name] = property; } } return this; // chaining }; styfn.append = function (style) { if (is.stylesheet(style)) { style.appendToStyle(this); } else if (is.array(style)) { this.appendFromJson(style); } else if (is.string(style)) { this.appendFromString(style); } // you probably wouldn't want to append a Style, since you'd duplicate the default parts return this; }; // static function Style.fromJson = function (cy, json) { var style = new Style(cy); style.fromJson(json); return style; }; Style.fromString = function (cy, string) { return new Style(cy).fromString(string); }; [__webpack_require__(86), __webpack_require__(87), __webpack_require__(88), __webpack_require__(89), __webpack_require__(90), __webpack_require__(91), __webpack_require__(92), __webpack_require__(93)].forEach(function (props) { util.extend(styfn, props); }); Style.types = styfn.types; Style.properties = styfn.properties; module.exports = Style; /***/ }), /* 19 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var fullFpsTime = 1000 / 60; // assume 60 frames per second module.exports = { setupDequeueing: function setupDequeueing(opts) { return function setupDequeueingImpl() { var self = this; var r = this.renderer; if (self.dequeueingSetup) { return; } else { self.dequeueingSetup = true; } var queueRedraw = util.debounce(function () { r.redrawHint('eles', true); r.redrawHint('drag', true); r.redraw(); }, opts.deqRedrawThreshold); var dequeue = function dequeue(willDraw, frameStartTime) { var startTime = util.performanceNow(); var avgRenderTime = r.averageRedrawTime; var renderTime = r.lastRedrawTime; var deqd = []; var extent = r.cy.extent(); var pixelRatio = r.getPixelRatio(); while (true) { var now = util.performanceNow(); var duration = now - startTime; var frameDuration = now - frameStartTime; if (renderTime < fullFpsTime) { // if we're rendering faster than the ideal fps, then do dequeueing // during all of the remaining frame time var timeAvailable = fullFpsTime - (willDraw ? avgRenderTime : 0); if (frameDuration >= opts.deqFastCost * timeAvailable) { break; } } else { if (willDraw) { if (duration >= opts.deqCost * renderTime || duration >= opts.deqAvgCost * avgRenderTime) { break; } } else if (frameDuration >= opts.deqNoDrawCost * fullFpsTime) { break; } } var thisDeqd = opts.deq(self, pixelRatio, extent); if (thisDeqd.length > 0) { for (var i = 0; i < thisDeqd.length; i++) { deqd.push(thisDeqd[i]); } } else { break; } } // callbacks on dequeue if (deqd.length > 0) { opts.onDeqd(self, deqd); if (!willDraw && opts.shouldRedraw(self, deqd, pixelRatio, extent)) { queueRedraw(); } } }; var priority = opts.priority || util.noop; r.beforeRender(dequeue, priority(self)); }; } }; /***/ }), /* 20 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var Core = __webpack_require__(12); var extension = __webpack_require__(95); var Stylesheet = __webpack_require__(137); var cytoscape = function cytoscape(options) { // jshint ignore:line // if no options specified, use default if (options === undefined) { options = {}; } // create instance if (is.plainObject(options)) { return new Core(options); } // allow for registration of extensions else if (is.string(options)) { return extension.apply(extension, arguments); } }; // e.g. cytoscape.use( require('cytoscape-foo'), bar ) cytoscape.use = function (ext) { var args = Array.prototype.slice.call(arguments, 1); // args to pass to ext args.unshift(cytoscape); // cytoscape is first arg to ext ext.apply(null, args); return this; }; // replaced by build system cytoscape.version = __webpack_require__(138); // expose public apis (mostly for extensions) cytoscape.stylesheet = cytoscape.Stylesheet = Stylesheet; module.exports = cytoscape; /***/ }), /* 21 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); module.exports = { // get [r, g, b] from #abc or #aabbcc hex2tuple: function hex2tuple(hex) { if (!(hex.length === 4 || hex.length === 7) || hex[0] !== '#') { return; } var shortHex = hex.length === 4; var r = void 0, g = void 0, b = void 0; var base = 16; if (shortHex) { r = parseInt(hex[1] + hex[1], base); g = parseInt(hex[2] + hex[2], base); b = parseInt(hex[3] + hex[3], base); } else { r = parseInt(hex[1] + hex[2], base); g = parseInt(hex[3] + hex[4], base); b = parseInt(hex[5] + hex[6], base); } return [r, g, b]; }, // get [r, g, b, a] from hsl(0, 0, 0) or hsla(0, 0, 0, 0) hsl2tuple: function hsl2tuple(hsl) { var ret = void 0; var h = void 0, s = void 0, l = void 0, a = void 0, r = void 0, g = void 0, b = void 0; function hue2rgb(p, q, t) { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t; if (t < 1 / 2) return q; if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; return p; } var m = new RegExp('^' + this.regex.hsla + '$').exec(hsl); if (m) { // get hue h = parseInt(m[1]); if (h < 0) { h = (360 - -1 * h % 360) % 360; } else if (h > 360) { h = h % 360; } h /= 360; // normalise on [0, 1] s = parseFloat(m[2]); if (s < 0 || s > 100) { return; } // saturation is [0, 100] s = s / 100; // normalise on [0, 1] l = parseFloat(m[3]); if (l < 0 || l > 100) { return; } // lightness is [0, 100] l = l / 100; // normalise on [0, 1] a = m[4]; if (a !== undefined) { a = parseFloat(a); if (a < 0 || a > 1) { return; } // alpha is [0, 1] } // now, convert to rgb // code from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript if (s === 0) { r = g = b = Math.round(l * 255); // achromatic } else { var q = l < 0.5 ? l * (1 + s) : l + s - l * s; var p = 2 * l - q; r = Math.round(255 * hue2rgb(p, q, h + 1 / 3)); g = Math.round(255 * hue2rgb(p, q, h)); b = Math.round(255 * hue2rgb(p, q, h - 1 / 3)); } ret = [r, g, b, a]; } return ret; }, // get [r, g, b, a] from rgb(0, 0, 0) or rgba(0, 0, 0, 0) rgb2tuple: function rgb2tuple(rgb) { var ret = void 0; var m = new RegExp('^' + this.regex.rgba + '$').exec(rgb); if (m) { ret = []; var isPct = []; for (var i = 1; i <= 3; i++) { var channel = m[i]; if (channel[channel.length - 1] === '%') { isPct[i] = true; } channel = parseFloat(channel); if (isPct[i]) { channel = channel / 100 * 255; // normalise to [0, 255] } if (channel < 0 || channel > 255) { return; } // invalid channel value ret.push(Math.floor(channel)); } var atLeastOneIsPct = isPct[1] || isPct[2] || isPct[3]; var allArePct = isPct[1] && isPct[2] && isPct[3]; if (atLeastOneIsPct && !allArePct) { return; } // must all be percent values if one is var alpha = m[4]; if (alpha !== undefined) { alpha = parseFloat(alpha); if (alpha < 0 || alpha > 1) { return; } // invalid alpha value ret.push(alpha); } } return ret; }, colorname2tuple: function colorname2tuple(color) { return this.colors[color.toLowerCase()]; }, color2tuple: function color2tuple(color) { return (is.array(color) ? color : null) || this.colorname2tuple(color) || this.hex2tuple(color) || this.rgb2tuple(color) || this.hsl2tuple(color); }, colors: { // special colour names transparent: [0, 0, 0, 0], // NB alpha === 0 // regular colours aliceblue: [240, 248, 255], antiquewhite: [250, 235, 215], aqua: [0, 255, 255], aquamarine: [127, 255, 212], azure: [240, 255, 255], beige: [245, 245, 220], bisque: [255, 228, 196], black: [0, 0, 0], blanchedalmond: [255, 235, 205], blue: [0, 0, 255], blueviolet: [138, 43, 226], brown: [165, 42, 42], burlywood: [222, 184, 135], cadetblue: [95, 158, 160], chartreuse: [127, 255, 0], chocolate: [210, 105, 30], coral: [255, 127, 80], cornflowerblue: [100, 149, 237], cornsilk: [255, 248, 220], crimson: [220, 20, 60], cyan: [0, 255, 255], darkblue: [0, 0, 139], darkcyan: [0, 139, 139], darkgoldenrod: [184, 134, 11], darkgray: [169, 169, 169], darkgreen: [0, 100, 0], darkgrey: [169, 169, 169], darkkhaki: [189, 183, 107], darkmagenta: [139, 0, 139], darkolivegreen: [85, 107, 47], darkorange: [255, 140, 0], darkorchid: [153, 50, 204], darkred: [139, 0, 0], darksalmon: [233, 150, 122], darkseagreen: [143, 188, 143], darkslateblue: [72, 61, 139], darkslategray: [47, 79, 79], darkslategrey: [47, 79, 79], darkturquoise: [0, 206, 209], darkviolet: [148, 0, 211], deeppink: [255, 20, 147], deepskyblue: [0, 191, 255], dimgray: [105, 105, 105], dimgrey: [105, 105, 105], dodgerblue: [30, 144, 255], firebrick: [178, 34, 34], floralwhite: [255, 250, 240], forestgreen: [34, 139, 34], fuchsia: [255, 0, 255], gainsboro: [220, 220, 220], ghostwhite: [248, 248, 255], gold: [255, 215, 0], goldenrod: [218, 165, 32], gray: [128, 128, 128], grey: [128, 128, 128], green: [0, 128, 0], greenyellow: [173, 255, 47], honeydew: [240, 255, 240], hotpink: [255, 105, 180], indianred: [205, 92, 92], indigo: [75, 0, 130], ivory: [255, 255, 240], khaki: [240, 230, 140], lavender: [230, 230, 250], lavenderblush: [255, 240, 245], lawngreen: [124, 252, 0], lemonchiffon: [255, 250, 205], lightblue: [173, 216, 230], lightcoral: [240, 128, 128], lightcyan: [224, 255, 255], lightgoldenrodyellow: [250, 250, 210], lightgray: [211, 211, 211], lightgreen: [144, 238, 144], lightgrey: [211, 211, 211], lightpink: [255, 182, 193], lightsalmon: [255, 160, 122], lightseagreen: [32, 178, 170], lightskyblue: [135, 206, 250], lightslategray: [119, 136, 153], lightslategrey: [119, 136, 153], lightsteelblue: [176, 196, 222], lightyellow: [255, 255, 224], lime: [0, 255, 0], limegreen: [50, 205, 50], linen: [250, 240, 230], magenta: [255, 0, 255], maroon: [128, 0, 0], mediumaquamarine: [102, 205, 170], mediumblue: [0, 0, 205], mediumorchid: [186, 85, 211], mediumpurple: [147, 112, 219], mediumseagreen: [60, 179, 113], mediumslateblue: [123, 104, 238], mediumspringgreen: [0, 250, 154], mediumturquoise: [72, 209, 204], mediumvioletred: [199, 21, 133], midnightblue: [25, 25, 112], mintcream: [245, 255, 250], mistyrose: [255, 228, 225], moccasin: [255, 228, 181], navajowhite: [255, 222, 173], navy: [0, 0, 128], oldlace: [253, 245, 230], olive: [128, 128, 0], olivedrab: [107, 142, 35], orange: [255, 165, 0], orangered: [255, 69, 0], orchid: [218, 112, 214], palegoldenrod: [238, 232, 170], palegreen: [152, 251, 152], paleturquoise: [175, 238, 238], palevioletred: [219, 112, 147], papayawhip: [255, 239, 213], peachpuff: [255, 218, 185], peru: [205, 133, 63], pink: [255, 192, 203], plum: [221, 160, 221], powderblue: [176, 224, 230], purple: [128, 0, 128], red: [255, 0, 0], rosybrown: [188, 143, 143], royalblue: [65, 105, 225], saddlebrown: [139, 69, 19], salmon: [250, 128, 114], sandybrown: [244, 164, 96], seagreen: [46, 139, 87], seashell: [255, 245, 238], sienna: [160, 82, 45], silver: [192, 192, 192], skyblue: [135, 206, 235], slateblue: [106, 90, 205], slategray: [112, 128, 144], slategrey: [112, 128, 144], snow: [255, 250, 250], springgreen: [0, 255, 127], steelblue: [70, 130, 180], tan: [210, 180, 140], teal: [0, 128, 128], thistle: [216, 191, 216], tomato: [255, 99, 71], turquoise: [64, 224, 208], violet: [238, 130, 238], wheat: [245, 222, 179], white: [255, 255, 255], whitesmoke: [245, 245, 245], yellow: [255, 255, 0], yellowgreen: [154, 205, 50] } }; /***/ }), /* 22 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); module.exports = { // has anything been set in the map mapEmpty: function mapEmpty(map) { var empty = true; if (map != null) { return Object.keys(map).length === 0; } return empty; }, // pushes to the array at the end of a map (map may not be built) pushMap: function pushMap(options) { var array = this.getMap(options); if (array == null) { // if empty, put initial array this.setMap(this.extend({}, options, { value: [options.value] })); } else { array.push(options.value); } }, // sets the value in a map (map may not be built) setMap: function setMap(options) { var obj = options.map; var key = void 0; var keys = options.keys; var l = keys.length; for (var i = 0; i < l; i++) { var _key = keys[i]; if (is.plainObject(_key)) { this.error('Tried to set map with object key'); } if (i < keys.length - 1) { // extend the map if necessary if (obj[_key] == null) { obj[_key] = {}; } obj = obj[_key]; } else { // set the value obj[_key] = options.value; } } }, // gets the value in a map even if it's not built in places getMap: function getMap(options) { var obj = options.map; var keys = options.keys; var l = keys.length; for (var i = 0; i < l; i++) { var key = keys[i]; if (is.plainObject(key)) { this.error('Tried to get map with object key'); } obj = obj[key]; if (obj == null) { return obj; } } return obj; }, // deletes the entry in the map deleteMap: function deleteMap(options) { var obj = options.map; var keys = options.keys; var l = keys.length; var keepChildren = options.keepChildren; for (var i = 0; i < l; i++) { var key = keys[i]; if (is.plainObject(key)) { this.error('Tried to delete map with object key'); } var lastKey = i === options.keys.length - 1; if (lastKey) { if (keepChildren) { // then only delete child fields not in keepChildren var children = Object.keys(obj); for (var j = 0; j < children.length; j++) { var child = children[j]; if (!keepChildren[child]) { obj[child] = undefined; } } } else { obj[key] = undefined; } } else { obj = obj[key]; } } } }; /***/ }), /* 23 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var number = '(?:[-+]?(?:(?:\\d+|\\d*\\.\\d+)(?:[Ee][+-]?\\d+)?))'; var rgba = 'rgb[a]?\\((' + number + '[%]?)\\s*,\\s*(' + number + '[%]?)\\s*,\\s*(' + number + '[%]?)(?:\\s*,\\s*(' + number + '))?\\)'; var rgbaNoBackRefs = 'rgb[a]?\\((?:' + number + '[%]?)\\s*,\\s*(?:' + number + '[%]?)\\s*,\\s*(?:' + number + '[%]?)(?:\\s*,\\s*(?:' + number + '))?\\)'; var hsla = 'hsl[a]?\\((' + number + ')\\s*,\\s*(' + number + '[%])\\s*,\\s*(' + number + '[%])(?:\\s*,\\s*(' + number + '))?\\)'; var hslaNoBackRefs = 'hsl[a]?\\((?:' + number + ')\\s*,\\s*(?:' + number + '[%])\\s*,\\s*(?:' + number + '[%])(?:\\s*,\\s*(?:' + number + '))?\\)'; var hex3 = '\\#[0-9a-fA-F]{3}'; var hex6 = '\\#[0-9a-fA-F]{6}'; module.exports = { regex: { number: number, rgba: rgba, rgbaNoBackRefs: rgbaNoBackRefs, hsla: hsla, hslaNoBackRefs: hslaNoBackRefs, hex3: hex3, hex6: hex6 } }; /***/ }), /* 24 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var memoize = __webpack_require__(13); var is = __webpack_require__(0); module.exports = { camel2dash: memoize(function (str) { return str.replace(/([A-Z])/g, function (v) { return '-' + v.toLowerCase(); }); }), dash2camel: memoize(function (str) { return str.replace(/(-\w)/g, function (v) { return v[1].toUpperCase(); }); }), prependCamel: memoize(function (prefix, str) { return prefix + str[0].toUpperCase() + str.substring(1); }, function (prefix, str) { return prefix + '$' + str; }), capitalize: function capitalize(str) { if (is.emptyString(str)) { return str; } return str.charAt(0).toUpperCase() + str.substring(1); } }; /***/ }), /* 25 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var window = __webpack_require__(3); var performance = window ? window.performance : null; var util = {}; var pnow = performance && performance.now ? function () { return performance.now(); } : function () { return Date.now(); }; var raf = function () { if (window) { if (window.requestAnimationFrame) { return function (fn) { window.requestAnimationFrame(fn); }; } else if (window.mozRequestAnimationFrame) { return function (fn) { window.mozRequestAnimationFrame(fn); }; } else if (window.webkitRequestAnimationFrame) { return function (fn) { window.webkitRequestAnimationFrame(fn); }; } else if (window.msRequestAnimationFrame) { return function (fn) { window.msRequestAnimationFrame(fn); }; } } return function (fn) { if (fn) { setTimeout(function () { fn(pnow()); }, 1000 / 60); } }; }(); util.requestAnimationFrame = function (fn) { raf(fn); }; util.performanceNow = pnow; util.debounce = __webpack_require__(26); util.now = function () { return Date.now(); }; module.exports = util; /***/ }), /* 26 */ /***/ (function(module, exports) { /** * lodash (Custom Build) * Build: `lodash modularize exports="npm" -o ./` * Copyright jQuery Foundation and other contributors * Released under MIT license * Based on Underscore.js 1.8.3 * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors */ /** Used as the `TypeError` message for "Functions" methods. */ var FUNC_ERROR_TEXT = 'Expected a function'; /** Used as references for various `Number` constants. */ var NAN = 0 / 0; /** `Object#toString` result references. */ var symbolTag = '[object Symbol]'; /** Used to match leading and trailing whitespace. */ var reTrim = /^\s+|\s+$/g; /** Used to detect bad signed hexadecimal string values. */ var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; /** Used to detect binary string values. */ var reIsBinary = /^0b[01]+$/i; /** Used to detect octal string values. */ var reIsOctal = /^0o[0-7]+$/i; /** Built-in method references without a dependency on `root`. */ var freeParseInt = parseInt; /** Detect free variable `global` from Node.js. */ var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; /** Detect free variable `self`. */ var freeSelf = typeof self == 'object' && self && self.Object === Object && self; /** Used as a reference to the global object. */ var root = freeGlobal || freeSelf || Function('return this')(); /** Used for built-in method references. */ var objectProto = Object.prototype; /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var objectToString = objectProto.toString; /* Built-in method references for those with the same name as other `lodash` methods. */ var nativeMax = Math.max, nativeMin = Math.min; /** * Gets the timestamp of the number of milliseconds that have elapsed since * the Unix epoch (1 January 1970 00:00:00 UTC). * * @static * @memberOf _ * @since 2.4.0 * @category Date * @returns {number} Returns the timestamp. * @example * * _.defer(function(stamp) { * console.log(_.now() - stamp); * }, _.now()); * // => Logs the number of milliseconds it took for the deferred invocation. */ var now = function() { return root.Date.now(); }; /** * Creates a debounced function that delays invoking `func` until after `wait` * milliseconds have elapsed since the last time the debounced function was * invoked. The debounced function comes with a `cancel` method to cancel * delayed `func` invocations and a `flush` method to immediately invoke them. * Provide `options` to indicate whether `func` should be invoked on the * leading and/or trailing edge of the `wait` timeout. The `func` is invoked * with the last arguments provided to the debounced function. Subsequent * calls to the debounced function return the result of the last `func` * invocation. * * **Note:** If `leading` and `trailing` options are `true`, `func` is * invoked on the trailing edge of the timeout only if the debounced function * is invoked more than once during the `wait` timeout. * * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred * until to the next tick, similar to `setTimeout` with a timeout of `0`. * * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) * for details over the differences between `_.debounce` and `_.throttle`. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to debounce. * @param {number} [wait=0] The number of milliseconds to delay. * @param {Object} [options={}] The options object. * @param {boolean} [options.leading=false] * Specify invoking on the leading edge of the timeout. * @param {number} [options.maxWait] * The maximum time `func` is allowed to be delayed before it's invoked. * @param {boolean} [options.trailing=true] * Specify invoking on the trailing edge of the timeout. * @returns {Function} Returns the new debounced function. * @example * * // Avoid costly calculations while the window size is in flux. * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); * * // Invoke `sendMail` when clicked, debouncing subsequent calls. * jQuery(element).on('click', _.debounce(sendMail, 300, { * 'leading': true, * 'trailing': false * })); * * // Ensure `batchLog` is invoked once after 1 second of debounced calls. * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); * var source = new EventSource('/stream'); * jQuery(source).on('message', debounced); * * // Cancel the trailing debounced invocation. * jQuery(window).on('popstate', debounced.cancel); */ function debounce(func, wait, options) { var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } wait = toNumber(wait) || 0; if (isObject(options)) { leading = !!options.leading; maxing = 'maxWait' in options; maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; trailing = 'trailing' in options ? !!options.trailing : trailing; } function invokeFunc(time) { var args = lastArgs, thisArg = lastThis; lastArgs = lastThis = undefined; lastInvokeTime = time; result = func.apply(thisArg, args); return result; } function leadingEdge(time) { // Reset any `maxWait` timer. lastInvokeTime = time; // Start the timer for the trailing edge. timerId = setTimeout(timerExpired, wait); // Invoke the leading edge. return leading ? invokeFunc(time) : result; } function remainingWait(time) { var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime, result = wait - timeSinceLastCall; return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result; } function shouldInvoke(time) { var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the // trailing edge, the system time has gone backwards and we're treating // it as the trailing edge, or we've hit the `maxWait` limit. return (lastCallTime === undefined || (timeSinceLastCall >= wait) || (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); } function timerExpired() { var time = now(); if (shouldInvoke(time)) { return trailingEdge(time); } // Restart the timer. timerId = setTimeout(timerExpired, remainingWait(time)); } function trailingEdge(time) { timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been // debounced at least once. if (trailing && lastArgs) { return invokeFunc(time); } lastArgs = lastThis = undefined; return result; } function cancel() { if (timerId !== undefined) { clearTimeout(timerId); } lastInvokeTime = 0; lastArgs = lastCallTime = lastThis = timerId = undefined; } function flush() { return timerId === undefined ? result : trailingEdge(now()); } function debounced() { var time = now(), isInvoking = shouldInvoke(time); lastArgs = arguments; lastThis = this; lastCallTime = time; if (isInvoking) { if (timerId === undefined) { return leadingEdge(lastCallTime); } if (maxing) { // Handle invocations in a tight loop. timerId = setTimeout(timerExpired, wait); return invokeFunc(lastCallTime); } } if (timerId === undefined) { timerId = setTimeout(timerExpired, wait); } return result; } debounced.cancel = cancel; debounced.flush = flush; return debounced; } /** * Checks if `value` is the * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(_.noop); * // => true * * _.isObject(null); * // => false */ function isObject(value) { var type = typeof value; return !!value && (type == 'object' || type == 'function'); } /** * Checks if `value` is object-like. A value is object-like if it's not `null` * and has a `typeof` result of "object". * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is object-like, else `false`. * @example * * _.isObjectLike({}); * // => true * * _.isObjectLike([1, 2, 3]); * // => true * * _.isObjectLike(_.noop); * // => false * * _.isObjectLike(null); * // => false */ function isObjectLike(value) { return !!value && typeof value == 'object'; } /** * Checks if `value` is classified as a `Symbol` primitive or object. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. * @example * * _.isSymbol(Symbol.iterator); * // => true * * _.isSymbol('abc'); * // => false */ function isSymbol(value) { return typeof value == 'symbol' || (isObjectLike(value) && objectToString.call(value) == symbolTag); } /** * Converts `value` to a number. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to process. * @returns {number} Returns the number. * @example * * _.toNumber(3.2); * // => 3.2 * * _.toNumber(Number.MIN_VALUE); * // => 5e-324 * * _.toNumber(Infinity); * // => Infinity * * _.toNumber('3.2'); * // => 3.2 */ function toNumber(value) { if (typeof value == 'number') { return value; } if (isSymbol(value)) { return NAN; } if (isObject(value)) { var other = typeof value.valueOf == 'function' ? value.valueOf() : value; value = isObject(other) ? (other + '') : other; } if (typeof value != 'string') { return value === 0 ? value : +value; } value = value.replace(reTrim, ''); var isBinary = reIsBinary.test(value); return (isBinary || reIsOctal.test(value)) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : (reIsBadHex.test(value) ? NAN : +value); } module.exports = debounce; /***/ }), /* 27 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; function ascending(a, b) { if (a < b) { return -1; } else if (a > b) { return 1; } else { return 0; } } function descending(a, b) { return -1 * ascending(a, b); } module.exports = { sort: { ascending: ascending, descending: descending } }; /***/ }), /* 28 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; function ObjectMap() { this._obj = {}; } var p = ObjectMap.prototype; p.set = function (key, val) { this._obj[key] = val; }; p.delete = function (key) { this._obj[key] = null; }; p.has = function (key) { return this._obj[key] != null; }; p.get = function (key) { return this._obj[key]; }; // TODO use the stdlib Map in future... // module.exports = typeof Map !== 'undefined' ? Map : ObjectMap; module.exports = ObjectMap; /***/ }), /* 29 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var elesfn = {}; [__webpack_require__(30), __webpack_require__(31), __webpack_require__(34), __webpack_require__(35), __webpack_require__(36), __webpack_require__(37), __webpack_require__(38), __webpack_require__(39), __webpack_require__(40), __webpack_require__(41), __webpack_require__(42)].forEach(function (props) { util.extend(elesfn, props); }); module.exports = elesfn; /***/ }), /* 30 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var defineSearch = function defineSearch(params) { params = { bfs: params.bfs || !params.dfs, dfs: params.dfs || !params.bfs }; // from pseudocode on wikipedia return function searchFn(roots, fn, directed) { var options; if (is.plainObject(roots) && !is.elementOrCollection(roots)) { options = roots; roots = options.roots || options.root; fn = options.visit; directed = options.directed; } directed = arguments.length === 2 && !is.fn(fn) ? fn : directed; fn = is.fn(fn) ? fn : function () {}; var cy = this._private.cy; var v = roots = is.string(roots) ? this.filter(roots) : roots; var Q = []; var connectedNodes = []; var connectedBy = {}; var id2depth = {}; var V = {}; var j = 0; var found; var nodes = this.nodes(); var edges = this.edges(); // enqueue v for (var i = 0; i < v.length; i++) { if (v[i].isNode()) { Q.unshift(v[i]); if (params.bfs) { V[v[i].id()] = true; connectedNodes.push(v[i]); } id2depth[v[i].id()] = 0; } } while (Q.length !== 0) { var v = params.bfs ? Q.shift() : Q.pop(); if (params.dfs) { if (V[v.id()]) { continue; } V[v.id()] = true; connectedNodes.push(v); } var depth = id2depth[v.id()]; var prevEdge = connectedBy[v.id()]; var prevNode = prevEdge == null ? undefined : prevEdge.connectedNodes().not(v)[0]; var ret; ret = fn(v, prevEdge, prevNode, j++, depth); if (ret === true) { found = v; break; } if (ret === false) { break; } var vwEdges = v.connectedEdges(directed ? function (ele) { return ele.data('source') === v.id(); } : undefined).intersect(edges); for (var i = 0; i < vwEdges.length; i++) { var e = vwEdges[i]; var w = e.connectedNodes(function (n) { return n.id() !== v.id(); }).intersect(nodes); if (w.length !== 0 && !V[w.id()]) { w = w[0]; Q.push(w); if (params.bfs) { V[w.id()] = true; connectedNodes.push(w); } connectedBy[w.id()] = e; id2depth[w.id()] = id2depth[v.id()] + 1; } } } var connectedEles = []; for (var i = 0; i < connectedNodes.length; i++) { var node = connectedNodes[i]; var edge = connectedBy[node.id()]; if (edge) { connectedEles.push(edge); } connectedEles.push(node); } return { path: cy.collection(connectedEles, { unique: true }), found: cy.collection(found) }; }; }; // search, spanning trees, etc var elesfn = { breadthFirstSearch: defineSearch({ bfs: true }), depthFirstSearch: defineSearch({ dfs: true }) }; // nice, short mathemathical alias elesfn.bfs = elesfn.breadthFirstSearch; elesfn.dfs = elesfn.depthFirstSearch; module.exports = elesfn; /***/ }), /* 31 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var Heap = __webpack_require__(9); var elesfn = { dijkstra: function dijkstra(root, weightFn, directed) { var options; if (is.plainObject(root) && !is.elementOrCollection(root)) { options = root; root = options.root; weightFn = options.weight; directed = options.directed; } var cy = this._private.cy; weightFn = is.fn(weightFn) ? weightFn : function () { return 1; }; // if not specified, assume each edge has equal weight (1) var source = is.string(root) ? this.filter(root)[0] : root[0]; var dist = {}; var prev = {}; var knownDist = {}; var edges = this.edges().filter(function (ele) { return !ele.isLoop(); }); var nodes = this.nodes(); var getDist = function getDist(node) { return dist[node.id()]; }; var setDist = function setDist(node, d) { dist[node.id()] = d; Q.updateItem(node); }; var Q = new Heap(function (a, b) { return getDist(a) - getDist(b); }); for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; dist[node.id()] = node.same(source) ? 0 : Infinity; Q.push(node); } var distBetween = function distBetween(u, v) { var uvs = (directed ? u.edgesTo(v) : u.edgesWith(v)).intersect(edges); var smallestDistance = Infinity; var smallestEdge; for (var i = 0; i < uvs.length; i++) { var edge = uvs[i]; var weight = weightFn(edge); if (weight < smallestDistance || !smallestEdge) { smallestDistance = weight; smallestEdge = edge; } } return { edge: smallestEdge, dist: smallestDistance }; }; while (Q.size() > 0) { var u = Q.pop(); var smalletsDist = getDist(u); var uid = u.id(); knownDist[uid] = smalletsDist; if (smalletsDist === Infinity) { continue; } var neighbors = u.neighborhood().intersect(nodes); for (var i = 0; i < neighbors.length; i++) { var v = neighbors[i]; var vid = v.id(); var vDist = distBetween(u, v); var alt = smalletsDist + vDist.dist; if (alt < getDist(v)) { setDist(v, alt); prev[vid] = { node: u, edge: vDist.edge }; } } // for } // while return { distanceTo: function distanceTo(node) { var target = is.string(node) ? nodes.filter(node)[0] : node[0]; return knownDist[target.id()]; }, pathTo: function pathTo(node) { var target = is.string(node) ? nodes.filter(node)[0] : node[0]; var S = []; var u = target; if (target.length > 0) { S.unshift(target); while (prev[u.id()]) { var p = prev[u.id()]; S.unshift(p.edge); S.unshift(p.node); u = p.node; } } return cy.collection(S); } }; } }; module.exports = elesfn; /***/ }), /* 32 */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__(33); /***/ }), /* 33 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// Generated by CoffeeScript 1.8.0 (function() { var Heap, defaultCmp, floor, heapify, heappop, heappush, heappushpop, heapreplace, insort, min, nlargest, nsmallest, updateItem, _siftdown, _siftup; floor = Math.floor, min = Math.min; /* Default comparison function to be used */ defaultCmp = function(x, y) { if (x < y) { return -1; } if (x > y) { return 1; } return 0; }; /* Insert item x in list a, and keep it sorted assuming a is sorted. If x is already in a, insert it to the right of the rightmost x. Optional args lo (default 0) and hi (default a.length) bound the slice of a to be searched. */ insort = function(a, x, lo, hi, cmp) { var mid; if (lo == null) { lo = 0; } if (cmp == null) { cmp = defaultCmp; } if (lo < 0) { throw new Error('lo must be non-negative'); } if (hi == null) { hi = a.length; } while (lo < hi) { mid = floor((lo + hi) / 2); if (cmp(x, a[mid]) < 0) { hi = mid; } else { lo = mid + 1; } } return ([].splice.apply(a, [lo, lo - lo].concat(x)), x); }; /* Push item onto heap, maintaining the heap invariant. */ heappush = function(array, item, cmp) { if (cmp == null) { cmp = defaultCmp; } array.push(item); return _siftdown(array, 0, array.length - 1, cmp); }; /* Pop the smallest item off the heap, maintaining the heap invariant. */ heappop = function(array, cmp) { var lastelt, returnitem; if (cmp == null) { cmp = defaultCmp; } lastelt = array.pop(); if (array.length) { returnitem = array[0]; array[0] = lastelt; _siftup(array, 0, cmp); } else { returnitem = lastelt; } return returnitem; }; /* Pop and return the current smallest value, and add the new item. This is more efficient than heappop() followed by heappush(), and can be more appropriate when using a fixed size heap. Note that the value returned may be larger than item! That constrains reasonable use of this routine unless written as part of a conditional replacement: if item > array[0] item = heapreplace(array, item) */ heapreplace = function(array, item, cmp) { var returnitem; if (cmp == null) { cmp = defaultCmp; } returnitem = array[0]; array[0] = item; _siftup(array, 0, cmp); return returnitem; }; /* Fast version of a heappush followed by a heappop. */ heappushpop = function(array, item, cmp) { var _ref; if (cmp == null) { cmp = defaultCmp; } if (array.length && cmp(array[0], item) < 0) { _ref = [array[0], item], item = _ref[0], array[0] = _ref[1]; _siftup(array, 0, cmp); } return item; }; /* Transform list into a heap, in-place, in O(array.length) time. */ heapify = function(array, cmp) { var i, _i, _j, _len, _ref, _ref1, _results, _results1; if (cmp == null) { cmp = defaultCmp; } _ref1 = (function() { _results1 = []; for (var _j = 0, _ref = floor(array.length / 2); 0 <= _ref ? _j < _ref : _j > _ref; 0 <= _ref ? _j++ : _j--){ _results1.push(_j); } return _results1; }).apply(this).reverse(); _results = []; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { i = _ref1[_i]; _results.push(_siftup(array, i, cmp)); } return _results; }; /* Update the position of the given item in the heap. This function should be called every time the item is being modified. */ updateItem = function(array, item, cmp) { var pos; if (cmp == null) { cmp = defaultCmp; } pos = array.indexOf(item); if (pos === -1) { return; } _siftdown(array, 0, pos, cmp); return _siftup(array, pos, cmp); }; /* Find the n largest elements in a dataset. */ nlargest = function(array, n, cmp) { var elem, result, _i, _len, _ref; if (cmp == null) { cmp = defaultCmp; } result = array.slice(0, n); if (!result.length) { return result; } heapify(result, cmp); _ref = array.slice(n); for (_i = 0, _len = _ref.length; _i < _len; _i++) { elem = _ref[_i]; heappushpop(result, elem, cmp); } return result.sort(cmp).reverse(); }; /* Find the n smallest elements in a dataset. */ nsmallest = function(array, n, cmp) { var elem, i, los, result, _i, _j, _len, _ref, _ref1, _results; if (cmp == null) { cmp = defaultCmp; } if (n * 10 <= array.length) { result = array.slice(0, n).sort(cmp); if (!result.length) { return result; } los = result[result.length - 1]; _ref = array.slice(n); for (_i = 0, _len = _ref.length; _i < _len; _i++) { elem = _ref[_i]; if (cmp(elem, los) < 0) { insort(result, elem, 0, null, cmp); result.pop(); los = result[result.length - 1]; } } return result; } heapify(array, cmp); _results = []; for (i = _j = 0, _ref1 = min(n, array.length); 0 <= _ref1 ? _j < _ref1 : _j > _ref1; i = 0 <= _ref1 ? ++_j : --_j) { _results.push(heappop(array, cmp)); } return _results; }; _siftdown = function(array, startpos, pos, cmp) { var newitem, parent, parentpos; if (cmp == null) { cmp = defaultCmp; } newitem = array[pos]; while (pos > startpos) { parentpos = (pos - 1) >> 1; parent = array[parentpos]; if (cmp(newitem, parent) < 0) { array[pos] = parent; pos = parentpos; continue; } break; } return array[pos] = newitem; }; _siftup = function(array, pos, cmp) { var childpos, endpos, newitem, rightpos, startpos; if (cmp == null) { cmp = defaultCmp; } endpos = array.length; startpos = pos; newitem = array[pos]; childpos = 2 * pos + 1; while (childpos < endpos) { rightpos = childpos + 1; if (rightpos < endpos && !(cmp(array[childpos], array[rightpos]) < 0)) { childpos = rightpos; } array[pos] = array[childpos]; pos = childpos; childpos = 2 * pos + 1; } array[pos] = newitem; return _siftdown(array, startpos, pos, cmp); }; Heap = (function() { Heap.push = heappush; Heap.pop = heappop; Heap.replace = heapreplace; Heap.pushpop = heappushpop; Heap.heapify = heapify; Heap.updateItem = updateItem; Heap.nlargest = nlargest; Heap.nsmallest = nsmallest; function Heap(cmp) { this.cmp = cmp != null ? cmp : defaultCmp; this.nodes = []; } Heap.prototype.push = function(x) { return heappush(this.nodes, x, this.cmp); }; Heap.prototype.pop = function() { return heappop(this.nodes, this.cmp); }; Heap.prototype.peek = function() { return this.nodes[0]; }; Heap.prototype.contains = function(x) { return this.nodes.indexOf(x) !== -1; }; Heap.prototype.replace = function(x) { return heapreplace(this.nodes, x, this.cmp); }; Heap.prototype.pushpop = function(x) { return heappushpop(this.nodes, x, this.cmp); }; Heap.prototype.heapify = function() { return heapify(this.nodes, this.cmp); }; Heap.prototype.updateItem = function(x) { return updateItem(this.nodes, x, this.cmp); }; Heap.prototype.clear = function() { return this.nodes = []; }; Heap.prototype.empty = function() { return this.nodes.length === 0; }; Heap.prototype.size = function() { return this.nodes.length; }; Heap.prototype.clone = function() { var heap; heap = new Heap(); heap.nodes = this.nodes.slice(0); return heap; }; Heap.prototype.toArray = function() { return this.nodes.slice(0); }; Heap.prototype.insert = Heap.prototype.push; Heap.prototype.top = Heap.prototype.peek; Heap.prototype.front = Heap.prototype.peek; Heap.prototype.has = Heap.prototype.contains; Heap.prototype.copy = Heap.prototype.clone; return Heap; })(); (function(root, factory) { if (true) { return !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else if (typeof exports === 'object') { return module.exports = factory(); } else { return root.Heap = factory(); } })(this, function() { return Heap; }); }).call(this); /***/ }), /* 34 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); // search, spanning trees, etc var elesfn = { // kruskal's algorithm (finds min spanning tree, assuming undirected graph) // implemented from pseudocode from wikipedia kruskal: function kruskal(weightFn) { var cy = this.cy(); weightFn = is.fn(weightFn) ? weightFn : function () { return 1; }; // if not specified, assume each edge has equal weight (1) function findSet(ele) { for (var i = 0; i < forest.length; i++) { var eles = forest[i]; if (eles.anySame(ele)) { return { eles: eles, index: i }; } } } var A = cy.collection(cy, []); var forest = []; var nodes = this.nodes(); for (var i = 0; i < nodes.length; i++) { forest.push(nodes[i].collection()); } var edges = this.edges(); var S = edges.toArray().sort(function (a, b) { var weightA = weightFn(a); var weightB = weightFn(b); return weightA - weightB; }); for (var i = 0; i < S.length; i++) { var edge = S[i]; var u = edge.source()[0]; var v = edge.target()[0]; var setU = findSet(u); var setV = findSet(v); if (setU.index !== setV.index) { A = A.add(edge); // combine forests for u and v forest[setU.index] = setU.eles.add(setV.eles); forest.splice(setV.index, 1); } } return nodes.add(A); } }; module.exports = elesfn; /***/ }), /* 35 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var elesfn = { // Implemented from pseudocode from wikipedia aStar: function aStar(options) { var eles = this; options = options || {}; // Reconstructs the path from Start to End, acumulating the result in pathAcum var reconstructPath = function reconstructPath(start, end, cameFromMap, pathAcum) { // Base case if (start == end) { pathAcum.unshift(cy.getElementById(end)); return pathAcum; } if (end in cameFromMap) { // We know which node is before the last one var previous = cameFromMap[end]; var previousEdge = cameFromEdge[end]; pathAcum.unshift(cy.getElementById(previousEdge)); pathAcum.unshift(cy.getElementById(end)); return reconstructPath(start, previous, cameFromMap, pathAcum); } // We should not reach here! return undefined; }; // Returns the index of the element in openSet which has minimum fScore var findMin = function findMin(openSet, fScore) { if (openSet.length === 0) { // Should never be the case return undefined; } var minPos = 0; var tempScore = fScore[openSet[0]]; for (var i = 1; i < openSet.length; i++) { var s = fScore[openSet[i]]; if (s < tempScore) { tempScore = s; minPos = i; } } return minPos; }; var cy = this._private.cy; // root - mandatory! if (options != null && options.root != null) { var source = is.string(options.root) ? // use it as a selector, e.g. "#rootID this.filter(options.root)[0] : options.root[0]; } else { return undefined; } // goal - mandatory! if (options.goal != null) { var target = is.string(options.goal) ? // use it as a selector, e.g. "#goalID this.filter(options.goal)[0] : options.goal[0]; } else { return undefined; } // Heuristic function - optional if (options.heuristic != null && is.fn(options.heuristic)) { var heuristic = options.heuristic; } else { var heuristic = function heuristic() { return 0; }; // use constant if unspecified } // Weight function - optional if (options.weight != null && is.fn(options.weight)) { var weightFn = options.weight; } else { // If not specified, assume each edge has equal weight (1) var weightFn = function weightFn(e) { return 1; }; } // directed - optional if (options.directed != null) { var directed = options.directed; } else { var directed = false; } var sid = source.id(); var tid = target.id(); var closedSet = []; var openSet = [sid]; var cameFrom = {}; var cameFromEdge = {}; var gScore = {}; var fScore = {}; gScore[sid] = 0; fScore[sid] = heuristic(source); // Counter var steps = 0; // Main loop while (openSet.length > 0) { var minPos = findMin(openSet, fScore); var cMin = cy.getElementById(openSet[minPos]); var cMinId = cMin.id(); steps++; // If we've found our goal, then we are done if (cMinId == tid) { var rPath = reconstructPath(sid, tid, cameFrom, []); return { found: true, distance: gScore[cMinId], path: eles.spawn(rPath), steps: steps }; } // Add cMin to processed nodes closedSet.push(cMinId); // Remove cMin from boundary nodes openSet.splice(minPos, 1); // Update scores for neighbors of cMin // Take into account if graph is directed or not var vwEdges = cMin._private.edges; for (var i = 0; i < vwEdges.length; i++) { var e = vwEdges[i]; // edge must be in set of calling eles if (!this.hasElementWithId(e.id())) { continue; } // cMin must be the source of edge if directed if (directed && e.data('source') !== cMinId) { continue; } var wSrc = e.source(); var wTgt = e.target(); var w = wSrc.id() !== cMinId ? wSrc : wTgt; var wid = w.id(); // node must be in set of calling eles if (!this.hasElementWithId(wid)) { continue; } // if node is in closedSet, ignore it if (closedSet.indexOf(wid) != -1) { continue; } // New tentative score for node w var tempScore = gScore[cMinId] + weightFn(e); // Update gScore for node w if: // w not present in openSet // OR // tentative gScore is less than previous value // w not in openSet if (openSet.indexOf(wid) == -1) { gScore[wid] = tempScore; fScore[wid] = tempScore + heuristic(w); openSet.push(wid); // Add node to openSet cameFrom[wid] = cMinId; cameFromEdge[wid] = e.id(); continue; } // w already in openSet, but with greater gScore if (tempScore < gScore[wid]) { gScore[wid] = tempScore; fScore[wid] = tempScore + heuristic(w); cameFrom[wid] = cMinId; } } // End of neighbors update } // End of main loop // If we've reached here, then we've not reached our goal return { found: false, distance: undefined, path: undefined, steps: steps }; } }; // elesfn module.exports = elesfn; /***/ }), /* 36 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var elesfn = { // Implemented from pseudocode from wikipedia floydWarshall: function floydWarshall(options) { options = options || {}; var cy = this.cy(); // Weight function - optional if (options.weight != null && is.fn(options.weight)) { var weightFn = options.weight; } else { // If not specified, assume each edge has equal weight (1) var weightFn = function weightFn(e) { return 1; }; } // directed - optional if (options.directed != null) { var directed = options.directed; } else { var directed = false; } var edges = this.edges().stdFilter(function (e) { return !e.isLoop(); }); var nodes = this.nodes(); var numNodes = nodes.length; // mapping: node id -> position in nodes array var id2position = {}; for (var i = 0; i < numNodes; i++) { id2position[nodes[i].id()] = i; } // Initialize distance matrix var dist = []; for (var i = 0; i < numNodes; i++) { var newRow = new Array(numNodes); for (var j = 0; j < numNodes; j++) { if (i == j) { newRow[j] = 0; } else { newRow[j] = Infinity; } } dist.push(newRow); } // Initialize matrix used for path reconstruction // Initialize distance matrix var next = []; var edgeNext = []; var initMatrix = function initMatrix(next) { for (var i = 0; i < numNodes; i++) { var newRow = new Array(numNodes); for (var j = 0; j < numNodes; j++) { newRow[j] = undefined; } next.push(newRow); } }; initMatrix(next); initMatrix(edgeNext); // Process edges for (var i = 0; i < edges.length; i++) { var sourceIndex = id2position[edges[i].source().id()]; var targetIndex = id2position[edges[i].target().id()]; var weight = weightFn(edges[i]); // Check if already process another edge between same 2 nodes if (dist[sourceIndex][targetIndex] > weight) { dist[sourceIndex][targetIndex] = weight; next[sourceIndex][targetIndex] = targetIndex; edgeNext[sourceIndex][targetIndex] = edges[i]; } } // If undirected graph, process 'reversed' edges if (!directed) { for (var i = 0; i < edges.length; i++) { var sourceIndex = id2position[edges[i].target().id()]; var targetIndex = id2position[edges[i].source().id()]; var weight = weightFn(edges[i]); // Check if already process another edge between same 2 nodes if (dist[sourceIndex][targetIndex] > weight) { dist[sourceIndex][targetIndex] = weight; next[sourceIndex][targetIndex] = targetIndex; edgeNext[sourceIndex][targetIndex] = edges[i]; } } } // Main loop for (var k = 0; k < numNodes; k++) { for (var i = 0; i < numNodes; i++) { for (var j = 0; j < numNodes; j++) { if (dist[i][k] + dist[k][j] < dist[i][j]) { dist[i][j] = dist[i][k] + dist[k][j]; next[i][j] = next[i][k]; } } } } // Build result object var position2id = []; for (var i = 0; i < numNodes; i++) { position2id.push(nodes[i].id()); } var res = { distance: function distance(from, to) { if (is.string(from)) { // from is a selector string var fromId = cy.filter(from)[0].id(); } else { // from is a node var fromId = from.id(); } if (is.string(to)) { // to is a selector string var toId = cy.filter(to)[0].id(); } else { // to is a node var toId = to.id(); } return dist[id2position[fromId]][id2position[toId]]; }, path: function path(from, to) { var reconstructPathAux = function reconstructPathAux(from, to, next, position2id, edgeNext) { if (from === to) { return cy.getElementById(position2id[from]); } if (next[from][to] === undefined) { return undefined; } var path = [cy.getElementById(position2id[from])]; var prev = from; while (from !== to) { prev = from; from = next[from][to]; var edge = edgeNext[prev][from]; path.push(edge); path.push(cy.getElementById(position2id[from])); } return path; }; if (is.string(from)) { // from is a selector string var fromId = cy.filter(from)[0].id(); } else { // from is a node var fromId = from.id(); } if (is.string(to)) { // to is a selector string var toId = cy.filter(to)[0].id(); } else { // to is a node var toId = to.id(); } var pathArr = reconstructPathAux(id2position[fromId], id2position[toId], next, position2id, edgeNext); return cy.collection(pathArr); } }; return res; } // floydWarshall }; // elesfn module.exports = elesfn; /***/ }), /* 37 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var util = __webpack_require__(1); var elesfn = { // Implemented from pseudocode from wikipedia bellmanFord: function bellmanFord(options) { var eles = this; options = options || {}; // Weight function - optional if (options.weight != null && is.fn(options.weight)) { var weightFn = options.weight; } else { // If not specified, assume each edge has equal weight (1) var weightFn = function weightFn(e) { return 1; }; } // directed - optional if (options.directed != null) { var directed = options.directed; } else { var directed = false; } // root - mandatory! if (options.root != null) { if (is.string(options.root)) { // use it as a selector, e.g. "#rootID var source = this.filter(options.root)[0]; } else { var source = options.root[0]; } } else { return undefined; } var cy = this._private.cy; var edges = this.edges().stdFilter(function (e) { return !e.isLoop(); }); var nodes = this.nodes(); var numNodes = nodes.length; // mapping: node id -> position in nodes array var id2position = {}; for (var i = 0; i < numNodes; i++) { id2position[nodes[i].id()] = i; } // Initializations var cost = []; var predecessor = []; var predEdge = []; for (var i = 0; i < numNodes; i++) { if (nodes[i].id() === source.id()) { cost[i] = 0; } else { cost[i] = Infinity; } predecessor[i] = undefined; } // Edges relaxation var flag = false; for (var i = 1; i < numNodes; i++) { flag = false; for (var e = 0; e < edges.length; e++) { var sourceIndex = id2position[edges[e].source().id()]; var targetIndex = id2position[edges[e].target().id()]; var weight = weightFn(edges[e]); var temp = cost[sourceIndex] + weight; if (temp < cost[targetIndex]) { cost[targetIndex] = temp; predecessor[targetIndex] = sourceIndex; predEdge[targetIndex] = edges[e]; flag = true; } // If undirected graph, we need to take into account the 'reverse' edge if (!directed) { var temp = cost[targetIndex] + weight; if (temp < cost[sourceIndex]) { cost[sourceIndex] = temp; predecessor[sourceIndex] = targetIndex; predEdge[sourceIndex] = edges[e]; flag = true; } } } if (!flag) { break; } } if (flag) { // Check for negative weight cycles for (var e = 0; e < edges.length; e++) { var sourceIndex = id2position[edges[e].source().id()]; var targetIndex = id2position[edges[e].target().id()]; var weight = weightFn(edges[e]); if (cost[sourceIndex] + weight < cost[targetIndex]) { util.error('Graph contains a negative weight cycle for Bellman-Ford'); return { pathTo: undefined, distanceTo: undefined, hasNegativeWeightCycle: true }; } } } // Build result object var position2id = []; for (var i = 0; i < numNodes; i++) { position2id.push(nodes[i].id()); } var res = { distanceTo: function distanceTo(to) { if (is.string(to)) { // to is a selector string var toId = cy.filter(to)[0].id(); } else { // to is a node var toId = to.id(); } return cost[id2position[toId]]; }, pathTo: function pathTo(to) { var reconstructPathAux = function reconstructPathAux(predecessor, fromPos, toPos, position2id, acumPath, predEdge) { for (;;) { // Add toId to path acumPath.push(cy.getElementById(position2id[toPos])); acumPath.push(predEdge[toPos]); if (fromPos === toPos) { // reached starting node return acumPath; } // If no path exists, discart acumulated path and return undefined var predPos = predecessor[toPos]; if (typeof predPos === 'undefined') { return undefined; } toPos = predPos; } }; if (is.string(to)) { // to is a selector string var toId = cy.filter(to)[0].id(); } else { // to is a node var toId = to.id(); } var path = []; // This returns a reversed path var res = reconstructPathAux(predecessor, id2position[source.id()], id2position[toId], position2id, path, predEdge); // Get it in the correct order and return it if (res != null) { res.reverse(); } return eles.spawn(res); }, hasNegativeWeightCycle: false }; return res; } // bellmanFord }; // elesfn module.exports = elesfn; /***/ }), /* 38 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var elesfn = { // Computes the minimum cut of an undirected graph // Returns the correct answer with high probability kargerStein: function kargerStein(options) { var eles = this; options = options || {}; // Function which colapses 2 (meta) nodes into one // Updates the remaining edge lists // Receives as a paramater the edge which causes the collapse var colapse = function colapse(edgeIndex, nodeMap, remainingEdges) { var edgeInfo = remainingEdges[edgeIndex]; var sourceIn = edgeInfo[1]; var targetIn = edgeInfo[2]; var partition1 = nodeMap[sourceIn]; var partition2 = nodeMap[targetIn]; // Delete all edges between partition1 and partition2 var newEdges = remainingEdges.filter(function (edge) { if (nodeMap[edge[1]] === partition1 && nodeMap[edge[2]] === partition2) { return false; } if (nodeMap[edge[1]] === partition2 && nodeMap[edge[2]] === partition1) { return false; } return true; }); // All edges pointing to partition2 should now point to partition1 for (var i = 0; i < newEdges.length; i++) { var edge = newEdges[i]; if (edge[1] === partition2) { // Check source newEdges[i] = edge.slice(0); newEdges[i][1] = partition1; } else if (edge[2] === partition2) { // Check target newEdges[i] = edge.slice(0); newEdges[i][2] = partition1; } } // Move all nodes from partition2 to partition1 for (var i = 0; i < nodeMap.length; i++) { if (nodeMap[i] === partition2) { nodeMap[i] = partition1; } } return newEdges; }; // Contracts a graph until we reach a certain number of meta nodes var contractUntil = function contractUntil(metaNodeMap, remainingEdges, size, sizeLimit) { // Stop condition if (size <= sizeLimit) { return remainingEdges; } // Choose an edge randomly var edgeIndex = Math.floor(Math.random() * remainingEdges.length); // Colapse graph based on edge var newEdges = colapse(edgeIndex, metaNodeMap, remainingEdges); return contractUntil(metaNodeMap, newEdges, size - 1, sizeLimit); }; var cy = this._private.cy; var edges = this.edges().stdFilter(function (e) { return !e.isLoop(); }); var nodes = this.nodes(); var numNodes = nodes.length; var numEdges = edges.length; var numIter = Math.ceil(Math.pow(Math.log(numNodes) / Math.LN2, 2)); var stopSize = Math.floor(numNodes / Math.sqrt(2)); if (numNodes < 2) { util.error('At least 2 nodes are required for Karger-Stein algorithm'); return undefined; } // Create numerical identifiers for each node // mapping: node id -> position in nodes array // for reverse mapping, simply use nodes array var id2position = {}; for (var i = 0; i < numNodes; i++) { id2position[nodes[i].id()] = i; } // Now store edge destination as indexes // Format for each edge (edge index, source node index, target node index) var edgeIndexes = []; for (var i = 0; i < numEdges; i++) { var e = edges[i]; edgeIndexes.push([i, id2position[e.source().id()], id2position[e.target().id()]]); } // We will store the best cut found here var minCutSize = Infinity; var minCut; // Initial meta node partition var originalMetaNode = []; for (var i = 0; i < numNodes; i++) { originalMetaNode.push(i); } // Main loop for (var iter = 0; iter <= numIter; iter++) { // Create new meta node partition var metaNodeMap = originalMetaNode.slice(0); // Contract until stop point (stopSize nodes) var edgesState = contractUntil(metaNodeMap, edgeIndexes, numNodes, stopSize); // Create a copy of the colapsed nodes state var metaNodeMap2 = metaNodeMap.slice(0); // Run 2 iterations starting in the stop state var res1 = contractUntil(metaNodeMap, edgesState, stopSize, 2); var res2 = contractUntil(metaNodeMap2, edgesState, stopSize, 2); // Is any of the 2 results the best cut so far? if (res1.length <= res2.length && res1.length < minCutSize) { minCutSize = res1.length; minCut = [res1, metaNodeMap]; } else if (res2.length <= res1.length && res2.length < minCutSize) { minCutSize = res2.length; minCut = [res2, metaNodeMap2]; } } // end of main loop // Construct result var resEdges = minCut[0].map(function (e) { return edges[e[0]]; }); var partition1 = []; var partition2 = []; // traverse metaNodeMap for best cut var witnessNodePartition = minCut[1][0]; for (var i = 0; i < minCut[1].length; i++) { var partitionId = minCut[1][i]; if (partitionId === witnessNodePartition) { partition1.push(nodes[i]); } else { partition2.push(nodes[i]); } } var ret = { cut: eles.spawn(cy, resEdges), partition1: eles.spawn(partition1), partition2: eles.spawn(partition2) }; return ret; } }; // elesfn module.exports = elesfn; /***/ }), /* 39 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var elesfn = { pageRank: function pageRank(options) { options = options || {}; var normalizeVector = function normalizeVector(vector) { var length = vector.length; // First, get sum of all elements var total = 0; for (var i = 0; i < length; i++) { total += vector[i]; } // Now, divide each by the sum of all elements for (var i = 0; i < length; i++) { vector[i] = vector[i] / total; } }; // dampingFactor - optional if (options != null && options.dampingFactor != null) { var dampingFactor = options.dampingFactor; } else { var dampingFactor = 0.8; // Default damping factor } // desired precision - optional if (options != null && options.precision != null) { var epsilon = options.precision; } else { var epsilon = 0.000001; // Default precision } // Max number of iterations - optional if (options != null && options.iterations != null) { var numIter = options.iterations; } else { var numIter = 200; // Default number of iterations } // Weight function - optional if (options != null && options.weight != null && is.fn(options.weight)) { var weightFn = options.weight; } else { // If not specified, assume each edge has equal weight (1) var weightFn = function weightFn(e) { return 1; }; } var cy = this._private.cy; var edges = this.edges().stdFilter(function (e) { return !e.isLoop(); }); var nodes = this.nodes(); var numNodes = nodes.length; var numEdges = edges.length; // Create numerical identifiers for each node // mapping: node id -> position in nodes array // for reverse mapping, simply use nodes array var id2position = {}; for (var i = 0; i < numNodes; i++) { id2position[nodes[i].id()] = i; } // Construct transposed adjacency matrix // First lets have a zeroed matrix of the right size // We'll also keep track of the sum of each column var matrix = []; var columnSum = []; var additionalProb = (1 - dampingFactor) / numNodes; // Create null matric for (var i = 0; i < numNodes; i++) { var newRow = []; for (var j = 0; j < numNodes; j++) { newRow.push(0.0); } matrix.push(newRow); columnSum.push(0.0); } // Now, process edges for (var i = 0; i < numEdges; i++) { var edge = edges[i]; var s = id2position[edge.source().id()]; var t = id2position[edge.target().id()]; var w = weightFn(edge); // Update matrix matrix[t][s] += w; // Update column sum columnSum[s] += w; } // Add additional probability based on damping factor // Also, take into account columns that have sum = 0 var p = 1.0 / numNodes + additionalProb; // Shorthand // Traverse matrix, column by column for (var j = 0; j < numNodes; j++) { if (columnSum[j] === 0) { // No 'links' out from node jth, assume equal probability for each possible node for (var i = 0; i < numNodes; i++) { matrix[i][j] = p; } } else { // Node jth has outgoing link, compute normalized probabilities for (var i = 0; i < numNodes; i++) { matrix[i][j] = matrix[i][j] / columnSum[j] + additionalProb; } } } // Compute dominant eigenvector using power method var eigenvector = []; var nullVector = []; var previous; // Start with a vector of all 1's // Also, initialize a null vector which will be used as shorthand for (var i = 0; i < numNodes; i++) { eigenvector.push(1.0); nullVector.push(0.0); } for (var iter = 0; iter < numIter; iter++) { // New array with all 0's var temp = nullVector.slice(0); // Multiply matrix with previous result for (var i = 0; i < numNodes; i++) { for (var j = 0; j < numNodes; j++) { temp[i] += matrix[i][j] * eigenvector[j]; } } normalizeVector(temp); previous = eigenvector; eigenvector = temp; var diff = 0; // Compute difference (squared module) of both vectors for (var i = 0; i < numNodes; i++) { diff += Math.pow(previous[i] - eigenvector[i], 2); } // If difference is less than the desired threshold, stop iterating if (diff < epsilon) { break; } } // Construct result var res = { rank: function rank(node) { if (is.string(node)) { // is a selector string var nodeId = cy.filter(node)[0].id(); } else { // is a node object var nodeId = node.id(); } return eigenvector[id2position[nodeId]]; } }; return res; } // pageRank }; // elesfn module.exports = elesfn; /***/ }), /* 40 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var util = __webpack_require__(1); var elesfn = { degreeCentralityNormalized: function degreeCentralityNormalized(options) { options = options || {}; var cy = this.cy(); // directed - optional if (options.directed != null) { var directed = options.directed; } else { var directed = false; } var nodes = this.nodes(); var numNodes = nodes.length; if (!directed) { var degrees = {}; var maxDegree = 0; for (var i = 0; i < numNodes; i++) { var node = nodes[i]; // add current node to the current options object and call degreeCentrality var currDegree = this.degreeCentrality(util.extend({}, options, { root: node })); if (maxDegree < currDegree.degree) maxDegree = currDegree.degree; degrees[node.id()] = currDegree.degree; } return { degree: function degree(node) { if (maxDegree == 0) return 0; if (is.string(node)) { // from is a selector string var node = cy.filter(node)[0].id(); } else { // from is a node var node = node.id(); } return degrees[node] / maxDegree; } }; } else { var indegrees = {}; var outdegrees = {}; var maxIndegree = 0; var maxOutdegree = 0; for (var i = 0; i < numNodes; i++) { var node = nodes[i]; // add current node to the current options object and call degreeCentrality var currDegree = this.degreeCentrality(util.extend({}, options, { root: node })); if (maxIndegree < currDegree.indegree) maxIndegree = currDegree.indegree; if (maxOutdegree < currDegree.outdegree) maxOutdegree = currDegree.outdegree; indegrees[node.id()] = currDegree.indegree; outdegrees[node.id()] = currDegree.outdegree; } return { indegree: function indegree(node) { if (maxIndegree == 0) return 0; if (is.string(node)) { // from is a selector string var node = cy.filter(node)[0].id(); } else { // from is a node var node = node.id(); } return indegrees[node] / maxIndegree; }, outdegree: function outdegree(node) { if (maxOutdegree == 0) return 0; if (is.string(node)) { // from is a selector string var node = cy.filter(node)[0].id(); } else { // from is a node var node = node.id(); } return outdegrees[node] / maxOutdegree; } }; } }, // degreeCentralityNormalized // Implemented from the algorithm in Opsahl's paper // "Node centrality in weighted networks: Generalizing degree and shortest paths" // check the heading 2 "Degree" degreeCentrality: function degreeCentrality(options) { options = options || {}; var callingEles = this; // root - mandatory! if (options != null && options.root != null) { var root = is.string(options.root) ? this.filter(options.root)[0] : options.root[0]; } else { return undefined; } // weight - optional if (options.weight != null && is.fn(options.weight)) { var weightFn = options.weight; } else { // If not specified, assume each edge has equal weight (1) var weightFn = function weightFn(e) { return 1; }; } // directed - optional if (options.directed != null) { var directed = options.directed; } else { var directed = false; } // alpha - optional if (options.alpha != null && is.number(options.alpha)) { var alpha = options.alpha; } else { alpha = 0; } if (!directed) { var connEdges = root.connectedEdges().intersection(callingEles); var k = connEdges.length; var s = 0; // Now, sum edge weights for (var i = 0; i < connEdges.length; i++) { var edge = connEdges[i]; s += weightFn(edge); } return { degree: Math.pow(k, 1 - alpha) * Math.pow(s, alpha) }; } else { var incoming = root.connectedEdges('edge[target = "' + root.id() + '"]').intersection(callingEles); var outgoing = root.connectedEdges('edge[source = "' + root.id() + '"]').intersection(callingEles); var k_in = incoming.length; var k_out = outgoing.length; var s_in = 0; var s_out = 0; // Now, sum incoming edge weights for (var i = 0; i < incoming.length; i++) { var edge = incoming[i]; s_in += weightFn(edge); } // Now, sum outgoing edge weights for (var i = 0; i < outgoing.length; i++) { var edge = outgoing[i]; s_out += weightFn(edge); } return { indegree: Math.pow(k_in, 1 - alpha) * Math.pow(s_in, alpha), outdegree: Math.pow(k_out, 1 - alpha) * Math.pow(s_out, alpha) }; } } // degreeCentrality }; // elesfn // nice, short mathemathical alias elesfn.dc = elesfn.degreeCentrality; elesfn.dcn = elesfn.degreeCentralityNormalised = elesfn.degreeCentralityNormalized; module.exports = elesfn; /***/ }), /* 41 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var elesfn = { closenessCentralityNormalized: function closenessCentralityNormalized(options) { options = options || {}; var cy = this.cy(); var harmonic = options.harmonic; if (harmonic === undefined) { harmonic = true; } var closenesses = {}; var maxCloseness = 0; var nodes = this.nodes(); var fw = this.floydWarshall({ weight: options.weight, directed: options.directed }); // Compute closeness for every node and find the maximum closeness for (var i = 0; i < nodes.length; i++) { var currCloseness = 0; for (var j = 0; j < nodes.length; j++) { if (i != j) { var d = fw.distance(nodes[i], nodes[j]); if (harmonic) { currCloseness += 1 / d; } else { currCloseness += d; } } } if (!harmonic) { currCloseness = 1 / currCloseness; } if (maxCloseness < currCloseness) { maxCloseness = currCloseness; } closenesses[nodes[i].id()] = currCloseness; } return { closeness: function closeness(node) { if (maxCloseness == 0) { return 0; } if (is.string(node)) { // from is a selector string var node = cy.filter(node)[0].id(); } else { // from is a node var node = node.id(); } return closenesses[node] / maxCloseness; } }; }, // Implemented from pseudocode from wikipedia closenessCentrality: function closenessCentrality(options) { options = options || {}; // root - mandatory! if (options.root != null) { if (is.string(options.root)) { // use it as a selector, e.g. "#rootID var root = this.filter(options.root)[0]; } else { var root = options.root[0]; } } else { return undefined; } // weight - optional if (options.weight != null && is.fn(options.weight)) { var weight = options.weight; } else { var weight = function weight() { return 1; }; } // directed - optional if (options.directed != null && is.bool(options.directed)) { var directed = options.directed; } else { var directed = false; } var harmonic = options.harmonic; if (harmonic === undefined) { harmonic = true; } // we need distance from this node to every other node var dijkstra = this.dijkstra({ root: root, weight: weight, directed: directed }); var totalDistance = 0; var nodes = this.nodes(); for (var i = 0; i < nodes.length; i++) { if (nodes[i].id() != root.id()) { var d = dijkstra.distanceTo(nodes[i]); if (harmonic) { totalDistance += 1 / d; } else { totalDistance += d; } } } return harmonic ? totalDistance : 1 / totalDistance; } // closenessCentrality }; // elesfn // nice, short mathemathical alias elesfn.cc = elesfn.closenessCentrality; elesfn.ccn = elesfn.closenessCentralityNormalised = elesfn.closenessCentralityNormalized; module.exports = elesfn; /***/ }), /* 42 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var Heap = __webpack_require__(9); var elesfn = { // Implemented from the algorithm in the paper "On Variants of Shortest-Path Betweenness Centrality and their Generic Computation" by Ulrik Brandes betweennessCentrality: function betweennessCentrality(options) { options = options || {}; // Weight - optional var weighted, weightFn; if (is.fn(options.weight)) { weightFn = options.weight; weighted = true; } else { weighted = false; } // Directed - default false var directed = options.directed != null ? options.directed : false; var cy = this._private.cy; // starting var V = this.nodes(); var A = {}; var _C = {}; var max = 0; var C = { set: function set(key, val) { _C[key] = val; if (val > max) { max = val; } }, get: function get(key) { return _C[key]; } }; // A contains the neighborhoods of every node for (var i = 0; i < V.length; i++) { var v = V[i]; var vid = v.id(); if (directed) { A[vid] = v.outgoers().nodes(); // get outgoers of every node } else { A[vid] = v.openNeighborhood().nodes(); // get neighbors of every node } C.set(vid, 0); } for (var s = 0; s < V.length; s++) { var sid = V[s].id(); var S = []; // stack var P = {}; var g = {}; var d = {}; var Q = new Heap(function (a, b) { return d[a] - d[b]; }); // queue // init dictionaries for (var i = 0; i < V.length; i++) { var vid = V[i].id(); P[vid] = []; g[vid] = 0; d[vid] = Infinity; } g[sid] = 1; // sigma d[sid] = 0; // distance to s Q.push(sid); while (!Q.empty()) { var v = Q.pop(); S.push(v); if (weighted) { for (var j = 0; j < A[v].length; j++) { var w = A[v][j]; var vEle = cy.getElementById(v); var edge; if (vEle.edgesTo(w).length > 0) { edge = vEle.edgesTo(w)[0]; } else { edge = w.edgesTo(vEle)[0]; } var edgeWeight = weightFn(edge); w = w.id(); if (d[w] > d[v] + edgeWeight) { d[w] = d[v] + edgeWeight; if (Q.nodes.indexOf(w) < 0) { //if w is not in Q Q.push(w); } else { // update position if w is in Q Q.updateItem(w); } g[w] = 0; P[w] = []; } if (d[w] == d[v] + edgeWeight) { g[w] = g[w] + g[v]; P[w].push(v); } } } else { for (var j = 0; j < A[v].length; j++) { var w = A[v][j].id(); if (d[w] == Infinity) { Q.push(w); d[w] = d[v] + 1; } if (d[w] == d[v] + 1) { g[w] = g[w] + g[v]; P[w].push(v); } } } } var e = {}; for (var i = 0; i < V.length; i++) { e[V[i].id()] = 0; } while (S.length > 0) { var w = S.pop(); for (var j = 0; j < P[w].length; j++) { var v = P[w][j]; e[v] = e[v] + g[v] / g[w] * (1 + e[w]); if (w != V[s].id()) { C.set(w, C.get(w) + e[w]); } } } } var ret = { betweenness: function betweenness(node) { if (is.string(node)) { var node = cy.filter(node).id(); } else { var node = node.id(); } return C.get(node); }, betweennessNormalized: function betweennessNormalized(node) { if (max == 0) return 0; if (is.string(node)) { var node = cy.filter(node).id(); } else { var node = node.id(); } return C.get(node) / max; } }; // alias ret.betweennessNormalised = ret.betweennessNormalized; return ret; } // betweennessCentrality }; // elesfn // nice, short mathemathical alias elesfn.bc = elesfn.betweennessCentrality; module.exports = elesfn; /***/ }), /* 43 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var define = __webpack_require__(4); var elesfn = { animate: define.animate(), animation: define.animation(), animated: define.animated(), clearQueue: define.clearQueue(), delay: define.delay(), delayAnimation: define.delayAnimation(), stop: define.stop() }; module.exports = elesfn; /***/ }), /* 44 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var Animation = __webpack_require__(45); var math = __webpack_require__(2); var is = __webpack_require__(0); var define = { animated: function animated() { return function animatedImpl() { var self = this; var selfIsArrayLike = self.length !== undefined; var all = selfIsArrayLike ? self : [self]; // put in array if not array-like var cy = this._private.cy || this; if (!cy.styleEnabled()) { return false; } var ele = all[0]; if (ele) { return ele._private.animation.current.length > 0; } }; }, // animated clearQueue: function clearQueue() { return function clearQueueImpl() { var self = this; var selfIsArrayLike = self.length !== undefined; var all = selfIsArrayLike ? self : [self]; // put in array if not array-like var cy = this._private.cy || this; if (!cy.styleEnabled()) { return this; } for (var i = 0; i < all.length; i++) { var ele = all[i]; ele._private.animation.queue = []; } return this; }; }, // clearQueue delay: function delay() { return function delayImpl(time, complete) { var cy = this._private.cy || this; if (!cy.styleEnabled()) { return this; } return this.animate({ delay: time, duration: time, complete: complete }); }; }, // delay delayAnimation: function delayAnimation() { return function delayAnimationImpl(time, complete) { var cy = this._private.cy || this; if (!cy.styleEnabled()) { return this; } return this.animation({ delay: time, duration: time, complete: complete }); }; }, // delay animation: function animation() { return function animationImpl(properties, params) { var self = this; var selfIsArrayLike = self.length !== undefined; var all = selfIsArrayLike ? self : [self]; // put in array if not array-like var cy = this._private.cy || this; var isCore = !selfIsArrayLike; var isEles = !isCore; if (!cy.styleEnabled()) { return this; } var style = cy.style(); properties = util.assign({}, properties, params); var propertiesEmpty = Object.keys(properties).length === 0; if (propertiesEmpty) { return new Animation(all[0], properties); // nothing to animate } if (properties.duration === undefined) { properties.duration = 400; } switch (properties.duration) { case 'slow': properties.duration = 600; break; case 'fast': properties.duration = 200; break; } if (isEles) { properties.style = style.getPropsList(properties.style || properties.css); properties.css = undefined; } if (isEles && properties.renderedPosition != null) { var rpos = properties.renderedPosition; var pan = cy.pan(); var zoom = cy.zoom(); properties.position = math.renderedToModelPosition(rpos, zoom, pan); } // override pan w/ panBy if set if (isCore && properties.panBy != null) { var panBy = properties.panBy; var cyPan = cy.pan(); properties.pan = { x: cyPan.x + panBy.x, y: cyPan.y + panBy.y }; } // override pan w/ center if set var center = properties.center || properties.centre; if (isCore && center != null) { var centerPan = cy.getCenterPan(center.eles, properties.zoom); if (centerPan != null) { properties.pan = centerPan; } } // override pan & zoom w/ fit if set if (isCore && properties.fit != null) { var fit = properties.fit; var fitVp = cy.getFitViewport(fit.eles || fit.boundingBox, fit.padding); if (fitVp != null) { properties.pan = fitVp.pan; properties.zoom = fitVp.zoom; } } // override zoom (& potentially pan) w/ zoom obj if set if (isCore && is.plainObject(properties.zoom)) { var vp = cy.getZoomedViewport(properties.zoom); if (vp != null) { if (vp.zoomed) { properties.zoom = vp.zoom; } if (vp.panned) { properties.pan = vp.pan; } } } return new Animation(all[0], properties); }; }, // animate animate: function animate() { return function animateImpl(properties, params) { var self = this; var selfIsArrayLike = self.length !== undefined; var all = selfIsArrayLike ? self : [self]; // put in array if not array-like var cy = this._private.cy || this; if (!cy.styleEnabled()) { return this; } if (params) { properties = util.extend({}, properties, params); } // manually hook and run the animation for (var i = 0; i < all.length; i++) { var ele = all[i]; var queue = ele.animated() && (properties.queue === undefined || properties.queue); var ani = ele.animation(properties, queue ? { queue: true } : undefined); ani.play(); } return this; // chaining }; }, // animate stop: function stop() { return function stopImpl(clearQueue, jumpToEnd) { var self = this; var selfIsArrayLike = self.length !== undefined; var all = selfIsArrayLike ? self : [self]; // put in array if not array-like var cy = this._private.cy || this; if (!cy.styleEnabled()) { return this; } for (var i = 0; i < all.length; i++) { var ele = all[i]; var _p = ele._private; var anis = _p.animation.current; for (var j = 0; j < anis.length; j++) { var ani = anis[j]; var ani_p = ani._private; if (jumpToEnd) { // next iteration of the animation loop, the animation // will go straight to the end and be removed ani_p.duration = 0; } } // clear the queue of future animations if (clearQueue) { _p.animation.queue = []; } if (!jumpToEnd) { _p.animation.current = []; } } // we have to notify (the animation loop doesn't do it for us on `stop`) cy.notify({ eles: this, type: 'draw' }); return this; }; } // stop }; // define module.exports = define; /***/ }), /* 45 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var is = __webpack_require__(0); var Promise = __webpack_require__(5); var Animation = function Animation(target, opts, opts2) { var _p = this._private = util.extend({ duration: 1000 }, opts, opts2); _p.target = target; _p.style = _p.style || _p.css; _p.started = false; _p.playing = false; _p.hooked = false; _p.applying = false; _p.progress = 0; _p.completes = []; _p.frames = []; if (_p.complete && is.fn(_p.complete)) { _p.completes.push(_p.complete); } // for future timeline/animations impl this.length = 1; this[0] = this; }; var anifn = Animation.prototype; util.extend(anifn, { instanceString: function instanceString() { return 'animation'; }, hook: function hook() { var _p = this._private; if (!_p.hooked) { // add to target's animation queue var q = void 0; var tAni = _p.target._private.animation; if (_p.queue) { q = tAni.queue; } else { q = tAni.current; } q.push(this); // add to the animation loop pool if (is.elementOrCollection(_p.target)) { _p.target.cy().addToAnimationPool(_p.target); } _p.hooked = true; } return this; }, play: function play() { var _p = this._private; // autorewind if (_p.progress === 1) { _p.progress = 0; } _p.playing = true; _p.started = false; // needs to be started by animation loop _p.stopped = false; this.hook(); // the animation loop will start the animation... return this; }, playing: function playing() { return this._private.playing; }, apply: function apply() { var _p = this._private; _p.applying = true; _p.started = false; // needs to be started by animation loop _p.stopped = false; this.hook(); // the animation loop will apply the animation at this progress return this; }, applying: function applying() { return this._private.applying; }, pause: function pause() { var _p = this._private; _p.playing = false; _p.started = false; return this; }, stop: function stop() { var _p = this._private; _p.playing = false; _p.started = false; _p.stopped = true; // to be removed from animation queues return this; }, rewind: function rewind() { return this.progress(0); }, fastforward: function fastforward() { return this.progress(1); }, time: function time(t) { var _p = this._private; if (t === undefined) { return _p.progress * _p.duration; } else { return this.progress(t / _p.duration); } }, progress: function progress(p) { var _p = this._private; var wasPlaying = _p.playing; if (p === undefined) { return _p.progress; } else { if (wasPlaying) { this.pause(); } _p.progress = p; _p.started = false; if (wasPlaying) { this.play(); } } return this; }, completed: function completed() { return this._private.progress === 1; }, reverse: function reverse() { var _p = this._private; var wasPlaying = _p.playing; if (wasPlaying) { this.pause(); } _p.progress = 1 - _p.progress; _p.started = false; var swap = function swap(a, b) { var _pa = _p[a]; if (_pa == null) { return; } _p[a] = _p[b]; _p[b] = _pa; }; swap('zoom', 'startZoom'); swap('pan', 'startPan'); swap('position', 'startPosition'); // swap styles if (_p.style) { for (var i = 0; i < _p.style.length; i++) { var prop = _p.style[i]; var name = prop.name; var startStyleProp = _p.startStyle[name]; _p.startStyle[name] = prop; _p.style[i] = startStyleProp; } } if (wasPlaying) { this.play(); } return this; }, promise: function promise(type) { var _p = this._private; var arr = void 0; switch (type) { case 'frame': arr = _p.frames; break; default: case 'complete': case 'completed': arr = _p.completes; } return new Promise(function (resolve, reject) { arr.push(function () { resolve(); }); }); } }); anifn.complete = anifn.completed; module.exports = Animation; /***/ }), /* 46 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var util = __webpack_require__(1); var is = __webpack_require__(0); var define = { // access data field data: function data(params) { var defaults = { field: 'data', bindingEvent: 'data', allowBinding: false, allowSetting: false, allowGetting: false, settingEvent: 'data', settingTriggersEvent: false, triggerFnName: 'trigger', immutableKeys: {}, // key => true if immutable updateStyle: false, beforeGet: function beforeGet(self) {}, beforeSet: function beforeSet(self, obj) {}, onSet: function onSet(self) {}, canSet: function canSet(self) { return true; } }; params = util.extend({}, defaults, params); return function dataImpl(name, value) { var p = params; var self = this; var selfIsArrayLike = self.length !== undefined; var all = selfIsArrayLike ? self : [self]; // put in array if not array-like var single = selfIsArrayLike ? self[0] : self; // .data('foo', ...) if (is.string(name)) { // set or get property // .data('foo') if (p.allowGetting && value === undefined) { // get var ret = void 0; if (single) { p.beforeGet(single); ret = single._private[p.field][name]; } return ret; // .data('foo', 'bar') } else if (p.allowSetting && value !== undefined) { // set var valid = !p.immutableKeys[name]; if (valid) { var change = _defineProperty({}, name, value); p.beforeSet(self, change); for (var i = 0, l = all.length; i < l; i++) { var ele = all[i]; if (p.canSet(ele)) { ele._private[p.field][name] = value; } } // update mappers if asked if (p.updateStyle) { self.updateStyle(); } // call onSet callback p.onSet(self); if (p.settingTriggersEvent) { self[p.triggerFnName](p.settingEvent); } } } // .data({ 'foo': 'bar' }) } else if (p.allowSetting && is.plainObject(name)) { // extend var obj = name; var k = void 0, v = void 0; var keys = Object.keys(obj); p.beforeSet(self, obj); for (var _i = 0; _i < keys.length; _i++) { k = keys[_i]; v = obj[k]; var _valid = !p.immutableKeys[k]; if (_valid) { for (var j = 0; j < all.length; j++) { var _ele = all[j]; if (p.canSet(_ele)) { _ele._private[p.field][k] = v; } } } } // update mappers if asked if (p.updateStyle) { self.updateStyle(); } // call onSet callback p.onSet(self); if (p.settingTriggersEvent) { self[p.triggerFnName](p.settingEvent); } // .data(function(){ ... }) } else if (p.allowBinding && is.fn(name)) { // bind to event var fn = name; self.on(p.bindingEvent, fn); // .data() } else if (p.allowGetting && name === undefined) { // get whole object var _ret = void 0; if (single) { p.beforeGet(single); _ret = single._private[p.field]; } return _ret; } return self; // maintain chainability }; // function }, // data // remove data field removeData: function removeData(params) { var defaults = { field: 'data', event: 'data', triggerFnName: 'trigger', triggerEvent: false, immutableKeys: {} // key => true if immutable }; params = util.extend({}, defaults, params); return function removeDataImpl(names) { var p = params; var self = this; var selfIsArrayLike = self.length !== undefined; var all = selfIsArrayLike ? self : [self]; // put in array if not array-like // .removeData('foo bar') if (is.string(names)) { // then get the list of keys, and delete them var keys = names.split(/\s+/); var l = keys.length; for (var i = 0; i < l; i++) { // delete each non-empty key var key = keys[i]; if (is.emptyString(key)) { continue; } var valid = !p.immutableKeys[key]; // not valid if immutable if (valid) { for (var i_a = 0, l_a = all.length; i_a < l_a; i_a++) { all[i_a]._private[p.field][key] = undefined; } } } if (p.triggerEvent) { self[p.triggerFnName](p.event); } // .removeData() } else if (names === undefined) { // then delete all keys for (var _i_a = 0, _l_a = all.length; _i_a < _l_a; _i_a++) { var _privateFields = all[_i_a]._private[p.field]; var _keys = Object.keys(_privateFields); for (var _i2 = 0; _i2 < _keys.length; _i2++) { var _key = _keys[_i2]; var validKeyToDelete = !p.immutableKeys[_key]; if (validKeyToDelete) { _privateFields[_key] = undefined; } } } if (p.triggerEvent) { self[p.triggerFnName](p.event); } } return self; // maintain chaining }; // function } // removeData }; // define module.exports = define; /***/ }), /* 47 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var Promise = __webpack_require__(5); var define = { eventAliasesOn: function eventAliasesOn(proto) { var p = proto; p.addListener = p.listen = p.bind = p.on; p.unlisten = p.unbind = p.off = p.removeListener; p.trigger = p.emit; // this is just a wrapper alias of .on() p.pon = p.promiseOn = function (events, selector) { var self = this; var args = Array.prototype.slice.call(arguments, 0); return new Promise(function (resolve, reject) { var callback = function callback(e) { self.off.apply(self, offArgs); resolve(e); }; var onArgs = args.concat([callback]); var offArgs = onArgs.concat([]); self.on.apply(self, onArgs); }); }; } }; // define module.exports = define; /***/ }), /* 48 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var Set = __webpack_require__(8); var elesfn = { classes: function classes(_classes) { _classes = (_classes || '').match(/\S+/g) || []; var self = this; var changed = []; var classesMap = new Set(_classes); // check and update each ele var _loop = function _loop(j) { var ele = self[j]; var _p = ele._private; var eleClasses = _p.classes; var changedEle = false; // check if ele has all of the passed classes classesMap.forEach(function (cls) { var eleHasClass = eleClasses.has(cls); if (!eleHasClass) { changedEle = true; } }); // check if ele has classes outside of those passed if (!changedEle) { eleClasses.forEach(function (eleCls) { var specdClass = classesMap.has(eleCls); if (!specdClass) { changedEle = true; } }); } if (changedEle) { _p.classes = new Set(classesMap); changed.push(ele); } }; for (var j = 0; j < self.length; j++) { _loop(j); } // trigger update style on those eles that had class changes if (changed.length > 0) { this.spawn(changed).updateStyle().emit('class'); } return self; }, addClass: function addClass(classes) { return this.toggleClass(classes, true); }, hasClass: function hasClass(className) { var ele = this[0]; return ele != null && ele._private.classes.has(className); }, toggleClass: function toggleClass(classesStr, toggle) { var classes = classesStr.match(/\S+/g) || []; var self = this; var changed = []; // eles who had classes changed for (var i = 0, il = self.length; i < il; i++) { var _ele = self[i]; var _changedEle = false; for (var j = 0; j < classes.length; j++) { var cls = classes[j]; var _eleClasses = _ele._private.classes; var hasClass = _eleClasses.has(cls); var shouldAdd = toggle || toggle === undefined && !hasClass; if (shouldAdd) { _eleClasses.add(cls); if (!hasClass && !_changedEle) { changed.push(_ele); _changedEle = true; } } else { // then remove _eleClasses.delete(cls); if (hasClass && !_changedEle) { changed.push(_ele); _changedEle = true; } } } // for j classes } // for i eles // trigger update style on those eles that had class changes if (changed.length > 0) { this.spawn(changed).updateStyle().emit('class'); } return self; }, removeClass: function removeClass(classes) { return this.toggleClass(classes, false); }, flashClass: function flashClass(classes, duration) { var self = this; if (duration == null) { duration = 250; } else if (duration === 0) { return self; // nothing to do really } self.addClass(classes); setTimeout(function () { self.removeClass(classes); }, duration); return self; } }; module.exports = elesfn; /***/ }), /* 49 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var Selector = __webpack_require__(6); var elesfn = { allAre: function allAre(selector) { var selObj = new Selector(selector); return this.every(function (ele) { return selObj.matches(ele); }); }, is: function is(selector) { var selObj = new Selector(selector); return this.some(function (ele) { return selObj.matches(ele); }); }, some: function some(fn, thisArg) { for (var i = 0; i < this.length; i++) { var ret = !thisArg ? fn(this[i], i, this) : fn.apply(thisArg, [this[i], i, this]); if (ret) { return true; } } return false; }, every: function every(fn, thisArg) { for (var i = 0; i < this.length; i++) { var ret = !thisArg ? fn(this[i], i, this) : fn.apply(thisArg, [this[i], i, this]); if (!ret) { return false; } } return true; }, same: function same(collection) { collection = this.cy().collection(collection); // cheap extra check if (this.length !== collection.length) { return false; } return this.every(function (ele) { return collection.hasElementWithId(ele.id()); }); }, anySame: function anySame(collection) { collection = this.cy().collection(collection); return this.some(function (ele) { return collection.hasElementWithId(ele.id()); }); }, allAreNeighbors: function allAreNeighbors(collection) { collection = this.cy().collection(collection); var nhood = this.neighborhood(); return collection.every(function (ele) { return nhood.hasElementWithId(ele.id()); }); }, contains: function contains(collection) { collection = this.cy().collection(collection); var self = this; return collection.every(function (ele) { return self.hasElementWithId(ele.id()); }); } }; elesfn.allAreNeighbours = elesfn.allAreNeighbors; elesfn.has = elesfn.contains; module.exports = elesfn; /***/ }), /* 50 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var exprs = __webpack_require__(51); var newQuery = __webpack_require__(10); // of all the expressions, find the first match in the remaining text var consumeExpr = function consumeExpr(remaining) { var expr = void 0; var match = void 0; var name = void 0; for (var j = 0; j < exprs.length; j++) { var e = exprs[j]; var n = e.name; var m = remaining.match(e.regexObj); if (m != null) { match = m; expr = e; name = n; var consumed = m[0]; remaining = remaining.substring(consumed.length); break; // we've consumed one expr, so we can return now } } return { expr: expr, match: match, name: name, remaining: remaining }; }; // consume all leading whitespace var consumeWhitespace = function consumeWhitespace(remaining) { var match = remaining.match(/^\s+/); if (match) { var consumed = match[0]; remaining = remaining.substring(consumed.length); } return remaining; }; var parse = function parse(selector) { var self = this; var remaining = self._private.selectorText = selector; var currentQuery = self[0] = newQuery(); self.length = 1; remaining = consumeWhitespace(remaining); // get rid of leading whitespace for (;;) { var check = consumeExpr(remaining); if (check.expr == null) { util.error('The selector `' + selector + '`is invalid'); return false; } else { var args = check.match.slice(1); // let the token populate the selector object in currentQuery var ret = check.expr.populate(self, currentQuery, args); if (ret === false) { return false; // exit if population failed } else if (ret != null) { currentQuery = ret; // change the current query to be filled if the expr specifies } } remaining = check.remaining; // we're done when there's nothing left to parse if (remaining.match(/^\s*$/)) { break; } } // adjust references for subject for (var j = 0; j < self.length; j++) { var query = self[j]; if (query.subject != null) { // go up the tree until we reach the subject for (;;) { if (query.subject === query) { break; } // done if subject is self if (query.parent != null) { // swap parent/child reference var parent = query.parent; var child = query; child.parent = null; parent.child = child; query = parent; // go up the tree } else if (query.ancestor != null) { // swap ancestor/descendant var ancestor = query.ancestor; var descendant = query; descendant.ancestor = null; ancestor.descendant = descendant; query = ancestor; // go up the tree } else if (query.source || query.target || query.connectedNodes) { util.error('The selector `' + self.text() + '` can not contain a subject selector that applies to the source or target of an edge selector'); return false; } else { util.error('When adjusting references for the selector `' + self.text() + '`, neither parent nor ancestor was found'); return false; } } // for self[j] = query.subject; // subject should be the root query } // if } // for return true; // success }; module.exports = { parse: parse }; /***/ }), /* 51 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var _require = __webpack_require__(15), stateSelectorRegex = _require.stateSelectorRegex; var tokens = __webpack_require__(52); var util = __webpack_require__(1); var newQuery = __webpack_require__(10); // when a token like a variable has escaped meta characters, we need to clean the backslashes out // so that values get compared properly in Selector.filter() var cleanMetaChars = function cleanMetaChars(str) { return str.replace(new RegExp('\\\\(' + tokens.metaChar + ')', 'g'), function (match, $1) { return $1; }); }; var replaceLastQuery = function replaceLastQuery(selector, examiningQuery, replacementQuery) { if (examiningQuery === selector[selector.length - 1]) { selector[selector.length - 1] = replacementQuery; } }; // NOTE: add new expression syntax here to have it recognised by the parser; // - a query contains all adjacent (i.e. no separator in between) expressions; // - the current query is stored in selector[i] --- you can use the reference to `this` in the populate function; // - you need to check the query objects in Selector.filter() for it actually filter properly, but that's pretty straight forward // - when you add something here, also add to Selector.toString() var exprs = [{ name: 'group', query: true, regex: '(' + tokens.group + ')', populate: function populate(selector, query, _ref) { var _ref2 = _slicedToArray(_ref, 1), group = _ref2[0]; query.group = group === '*' ? group : group + 's'; } }, { name: 'state', query: true, regex: stateSelectorRegex, populate: function populate(selector, query, _ref3) { var _ref4 = _slicedToArray(_ref3, 1), state = _ref4[0]; query.colonSelectors.push(state); } }, { name: 'id', query: true, regex: '\\#(' + tokens.id + ')', populate: function populate(selector, query, _ref5) { var _ref6 = _slicedToArray(_ref5, 1), id = _ref6[0]; query.ids.push(cleanMetaChars(id)); } }, { name: 'className', query: true, regex: '\\.(' + tokens.className + ')', populate: function populate(selector, query, _ref7) { var _ref8 = _slicedToArray(_ref7, 1), className = _ref8[0]; query.classes.push(cleanMetaChars(className)); } }, { name: 'dataExists', query: true, regex: '\\[\\s*(' + tokens.variable + ')\\s*\\]', populate: function populate(selector, query, _ref9) { var _ref10 = _slicedToArray(_ref9, 1), variable = _ref10[0]; query.data.push({ field: cleanMetaChars(variable) }); } }, { name: 'dataCompare', query: true, regex: '\\[\\s*(' + tokens.variable + ')\\s*(' + tokens.comparatorOp + ')\\s*(' + tokens.value + ')\\s*\\]', populate: function populate(selector, query, _ref11) { var _ref12 = _slicedToArray(_ref11, 3), variable = _ref12[0], comparatorOp = _ref12[1], value = _ref12[2]; var valueIsString = new RegExp('^' + tokens.string + '$').exec(value) != null; if (valueIsString) { value = value.substring(1, value.length - 1); } else { value = parseFloat(value); } query.data.push({ field: cleanMetaChars(variable), operator: comparatorOp, value: value }); } }, { name: 'dataBool', query: true, regex: '\\[\\s*(' + tokens.boolOp + ')\\s*(' + tokens.variable + ')\\s*\\]', populate: function populate(selector, query, _ref13) { var _ref14 = _slicedToArray(_ref13, 2), boolOp = _ref14[0], variable = _ref14[1]; query.data.push({ field: cleanMetaChars(variable), operator: boolOp }); } }, { name: 'metaCompare', query: true, regex: '\\[\\[\\s*(' + tokens.meta + ')\\s*(' + tokens.comparatorOp + ')\\s*(' + tokens.number + ')\\s*\\]\\]', populate: function populate(selector, query, _ref15) { var _ref16 = _slicedToArray(_ref15, 3), meta = _ref16[0], comparatorOp = _ref16[1], number = _ref16[2]; query.meta.push({ field: cleanMetaChars(meta), operator: comparatorOp, value: parseFloat(number) }); } }, { name: 'nextQuery', separator: true, regex: tokens.separator, populate: function populate(selector) { // go on to next query var nextQuery = selector[selector.length++] = newQuery(); selector.currentSubject = null; return nextQuery; } }, { name: 'directedEdge', separator: true, regex: tokens.directedEdge, populate: function populate(selector, query) { var edgeQuery = newQuery(); var source = query; var target = newQuery(); edgeQuery.group = 'edges'; edgeQuery.target = target; edgeQuery.source = source; edgeQuery.subject = selector.currentSubject; // the query in the selector should be the edge rather than the source replaceLastQuery(selector, query, edgeQuery); // we're now populating the target query with expressions that follow return target; } }, { name: 'undirectedEdge', separator: true, regex: tokens.undirectedEdge, populate: function populate(selector, query) { var edgeQuery = newQuery(); var source = query; var target = newQuery(); edgeQuery.group = 'edges'; edgeQuery.connectedNodes = [source, target]; edgeQuery.subject = selector.currentSubject; // the query in the selector should be the edge rather than the source replaceLastQuery(selector, query, edgeQuery); // we're now populating the target query with expressions that follow return target; } }, { name: 'child', separator: true, regex: tokens.child, populate: function populate(selector, query) { // this query is the parent of the following query var childQuery = newQuery(); childQuery.parent = query; childQuery.subject = selector.currentSubject; // it's cheaper to compare children first and go up so replace the parent replaceLastQuery(selector, query, childQuery); // we're now populating the child query with expressions that follow return childQuery; } }, { name: 'descendant', separator: true, regex: tokens.descendant, populate: function populate(selector, query) { // this query is the ancestor of the following query var descendantQuery = newQuery(); descendantQuery.ancestor = query; descendantQuery.subject = selector.currentSubject; // it's cheaper to compare descendants first and go up so replace the ancestor replaceLastQuery(selector, query, descendantQuery); // we're now populating the descendant query with expressions that follow return descendantQuery; } }, { name: 'subject', modifier: true, regex: tokens.subject, populate: function populate(selector, query) { if (selector.currentSubject != null && query.subject != query) { util.error('Redefinition of subject in selector `' + selector.toString() + '`'); return false; } selector.currentSubject = query; query.subject = query; selector[selector.length - 1].subject = query; } }]; exprs.forEach(function (e) { return e.regexObj = new RegExp('^' + e.regex); }); module.exports = exprs; /***/ }), /* 52 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); // tokens in the query language var tokens = { metaChar: '[\\!\\"\\#\\$\\%\\&\\\'\\(\\)\\*\\+\\,\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\]\\^\\`\\{\\|\\}\\~]', // chars we need to escape in let names, etc comparatorOp: '=|\\!=|>|>=|<|<=|\\$=|\\^=|\\*=', // binary comparison op (used in data selectors) boolOp: '\\?|\\!|\\^', // boolean (unary) operators (used in data selectors) string: '"(?:\\\\"|[^"])*"' + '|' + "'(?:\\\\'|[^'])*'", // string literals (used in data selectors) -- doublequotes | singlequotes number: util.regex.number, // number literal (used in data selectors) --- e.g. 0.1234, 1234, 12e123 meta: 'degree|indegree|outdegree', // allowed metadata fields (i.e. allowed functions to use from Collection) separator: '\\s*,\\s*', // queries are separated by commas, e.g. edge[foo = 'bar'], node.someClass descendant: '\\s+', child: '\\s+>\\s+', subject: '\\$', group: 'node|edge|\\*', directedEdge: '\\s+->\\s+', undirectedEdge: '\\s+<->\\s+' }; tokens.variable = '(?:[\\w-]|(?:\\\\' + tokens.metaChar + '))+'; // a variable name tokens.value = tokens.string + '|' + tokens.number; // a value literal, either a string or number tokens.className = tokens.variable; // a class name (follows variable conventions) tokens.id = tokens.variable; // an element id (follows variable conventions) (function () { var ops = void 0, op = void 0, i = void 0; // add @ variants to comparatorOp ops = tokens.comparatorOp.split('|'); for (i = 0; i < ops.length; i++) { op = ops[i]; tokens.comparatorOp += '|@' + op; } // add ! variants to comparatorOp ops = tokens.comparatorOp.split('|'); for (i = 0; i < ops.length; i++) { op = ops[i]; if (op.indexOf('!') >= 0) { continue; } // skip ops that explicitly contain ! if (op === '=') { continue; } // skip = b/c != is explicitly defined tokens.comparatorOp += '|\\!' + op; } })(); module.exports = tokens; /***/ }), /* 53 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var _require = __webpack_require__(15), stateSelectorMatches = _require.stateSelectorMatches; var is = __webpack_require__(0); // generic checking for data/metadata var operandsMatch = function operandsMatch(query, params) { var allDataMatches = true; for (var k = 0; k < query[params.name].length; k++) { var data = query[params.name][k]; var operator = data.operator; var value = data.value; var field = data.field; var _matches = void 0; var fieldVal = params.fieldValue(field); if (operator != null && value != null) { var fieldStr = !is.string(fieldVal) && !is.number(fieldVal) ? '' : '' + fieldVal; var valStr = '' + value; var caseInsensitive = false; if (operator.indexOf('@') >= 0) { fieldStr = fieldStr.toLowerCase(); valStr = valStr.toLowerCase(); operator = operator.replace('@', ''); caseInsensitive = true; } var notExpr = false; if (operator.indexOf('!') >= 0) { operator = operator.replace('!', ''); notExpr = true; } // if we're doing a case insensitive comparison, then we're using a STRING comparison // even if we're comparing numbers if (caseInsensitive) { value = valStr.toLowerCase(); fieldVal = fieldStr.toLowerCase(); } var isIneqCmp = false; switch (operator) { case '*=': _matches = fieldStr.indexOf(valStr) >= 0; break; case '$=': _matches = fieldStr.indexOf(valStr, fieldStr.length - valStr.length) >= 0; break; case '^=': _matches = fieldStr.indexOf(valStr) === 0; break; case '=': _matches = fieldVal === value; break; case '>': isIneqCmp = true; _matches = fieldVal > value; break; case '>=': isIneqCmp = true; _matches = fieldVal >= value; break; case '<': isIneqCmp = true; _matches = fieldVal < value; break; case '<=': isIneqCmp = true; _matches = fieldVal <= value; break; default: _matches = false; break; } // apply the not op, but null vals for inequalities should always stay non-matching if (notExpr && (fieldVal != null || !isIneqCmp)) { _matches = !_matches; } } else if (operator != null) { switch (operator) { case '?': _matches = fieldVal ? true : false; break; case '!': _matches = fieldVal ? false : true; break; case '^': _matches = fieldVal === undefined; break; } } else { _matches = fieldVal !== undefined; } if (!_matches) { allDataMatches = false; break; } } // for return allDataMatches; }; // operandsMatch // check parent/child relations var confirmRelations = function confirmRelations(query, isNecessary, eles) { if (query != null) { var _matches2 = false; if (!isNecessary) { return false; } eles = eles(); // save cycles if query == null // query must match for at least one element (may be recursive) for (var i = 0; i < eles.length; i++) { if (queryMatches(query, eles[i])) { _matches2 = true; break; } } return _matches2; } else { return true; } }; var queryMatches = function queryMatches(query, ele) { // make single group-only selectors really cheap to check since they're the most common ones if (query.groupOnly) { return query.group === '*' || query.group === ele.group(); } // check group if (query.group != null && query.group != '*' && query.group != ele.group()) { return false; } var cy = ele.cy(); var k = void 0; // check colon selectors var allColonSelectorsMatch = true; for (k = 0; k < query.colonSelectors.length; k++) { var sel = query.colonSelectors[k]; allColonSelectorsMatch = stateSelectorMatches(sel, ele); if (!allColonSelectorsMatch) break; } if (!allColonSelectorsMatch) return false; // check id var allIdsMatch = true; for (k = 0; k < query.ids.length; k++) { var id = query.ids[k]; var actualId = ele.id(); allIdsMatch = allIdsMatch && id == actualId; if (!allIdsMatch) break; } if (!allIdsMatch) return false; // check classes var allClassesMatch = true; for (k = 0; k < query.classes.length; k++) { var cls = query.classes[k]; allClassesMatch = allClassesMatch && ele.hasClass(cls); if (!allClassesMatch) break; } if (!allClassesMatch) return false; // check data matches var allDataMatches = operandsMatch(query, { name: 'data', fieldValue: function fieldValue(field) { return ele.data(field); } }); if (!allDataMatches) { return false; } // check metadata matches var allMetaMatches = operandsMatch(query, { name: 'meta', fieldValue: function fieldValue(field) { return ele[field](); } }); if (!allMetaMatches) { return false; } // check collection if (query.collection != null) { var matchesAny = query.collection.hasElementWithId(ele.id()); if (!matchesAny) { return false; } } // check filter function if (query.filter != null && ele.collection().some(query.filter)) { return false; } var isCompound = cy.hasCompoundNodes(); var getSource = function getSource() { return ele.source(); }; var getTarget = function getTarget() { return ele.target(); }; if (!confirmRelations(query.parent, isCompound, function () { return ele.parent(); })) { return false; } if (!confirmRelations(query.ancestor, isCompound, function () { return ele.parents(); })) { return false; } if (!confirmRelations(query.child, isCompound, function () { return ele.children(); })) { return false; } if (!confirmRelations(query.descendant, isCompound, function () { return ele.descendants(); })) { return false; } if (!confirmRelations(query.source, true, getSource)) { return false; } if (!confirmRelations(query.target, true, getTarget)) { return false; } if (query.connectedNodes) { var q0 = query.connectedNodes[0]; var q1 = query.connectedNodes[1]; if (confirmRelations(q0, true, getSource) && confirmRelations(q1, true, getTarget)) { // match } else if (confirmRelations(q0, true, getTarget) && confirmRelations(q1, true, getSource)) { // match } else { return false; } } // we've reached the end, so we've matched everything for this query return true; }; // queryMatches // filter an existing collection var filter = function filter(collection) { var self = this; var cy = collection.cy(); // don't bother trying if it's invalid if (self.invalid()) { return cy.collection(); } // for 1 id #foo queries, just get the element if (self.length === 1 && self[0].length === 1 && self[0].ids.length === 1) { return collection.getElementById(self[0].ids[0]).collection(); } var selectorFunction = function selectorFunction(element) { for (var j = 0; j < self.length; j++) { var query = self[j]; if (queryMatches(query, element)) { return true; } } return false; }; if (self.text() == null) { selectorFunction = function selectorFunction() { return true; }; } var filteredCollection = collection.filter(selectorFunction); return filteredCollection; }; // filter // does selector match a single element? var matches = function matches(ele) { var self = this; // don't bother trying if it's invalid if (self.invalid()) { return false; } for (var j = 0; j < self.length; j++) { var query = self[j]; if (queryMatches(query, ele)) { return true; } } return false; }; // filter module.exports = { matches: matches, filter: filter }; /***/ }), /* 54 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var Set = __webpack_require__(8); var elesfn = { parent: function parent(selector) { var parents = []; // optimisation for single ele call if (this.length === 1) { var parent = this[0]._private.parent; if (parent) { return parent; } } for (var i = 0; i < this.length; i++) { var ele = this[i]; var _parent = ele._private.parent; if (_parent) { parents.push(_parent); } } return this.spawn(parents, { unique: true }).filter(selector); }, parents: function parents(selector) { var parents = []; var eles = this.parent(); while (eles.nonempty()) { for (var i = 0; i < eles.length; i++) { var ele = eles[i]; parents.push(ele); } eles = eles.parent(); } return this.spawn(parents, { unique: true }).filter(selector); }, commonAncestors: function commonAncestors(selector) { var ancestors = void 0; for (var i = 0; i < this.length; i++) { var ele = this[i]; var parents = ele.parents(); ancestors = ancestors || parents; ancestors = ancestors.intersect(parents); // current list must be common with current ele parents set } return ancestors.filter(selector); }, orphans: function orphans(selector) { return this.stdFilter(function (ele) { return ele.isOrphan(); }).filter(selector); }, nonorphans: function nonorphans(selector) { return this.stdFilter(function (ele) { return ele.isChild(); }).filter(selector); }, children: function children(selector) { var children = []; for (var i = 0; i < this.length; i++) { var ele = this[i]; children = children.concat(ele._private.children); } return this.spawn(children, { unique: true }).filter(selector); }, siblings: function siblings(selector) { return this.parent().children().not(this).filter(selector); }, isParent: function isParent() { var ele = this[0]; if (ele) { return ele.isNode() && ele._private.children.length !== 0; } }, isChildless: function isChildless() { var ele = this[0]; if (ele) { return ele.isNode() && ele._private.children.length === 0; } }, isChild: function isChild() { var ele = this[0]; if (ele) { return ele.isNode() && ele._private.parent != null; } }, isOrphan: function isOrphan() { var ele = this[0]; if (ele) { return ele.isNode() && ele._private.parent == null; } }, descendants: function descendants(selector) { var elements = []; function add(eles) { for (var i = 0; i < eles.length; i++) { var ele = eles[i]; elements.push(ele); if (ele.children().nonempty()) { add(ele.children()); } } } add(this.children()); return this.spawn(elements, { unique: true }).filter(selector); } }; function forEachCompound(eles, fn, includeSelf, recursiveStep) { var q = []; var did = new Set(); var cy = eles.cy(); var hasCompounds = cy.hasCompoundNodes(); for (var i = 0; i < eles.length; i++) { var ele = eles[i]; if (includeSelf) { q.push(ele); } else if (hasCompounds) { recursiveStep(q, did, ele); } } while (q.length > 0) { var _ele = q.shift(); fn(_ele); did.add(_ele.id()); if (hasCompounds) { recursiveStep(q, did, _ele); } } return eles; } function addChildren(q, did, ele) { if (ele.isParent()) { var children = ele._private.children; for (var i = 0; i < children.length; i++) { var child = children[i]; if (!did.has(child.id())) { q.push(child); } } } } // very efficient version of eles.add( eles.descendants() ).forEach() // for internal use elesfn.forEachDown = function (fn) { var includeSelf = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; return forEachCompound(this, fn, includeSelf, addChildren); }; function addParent(q, did, ele) { if (ele.isChild()) { var parent = ele._private.parent; if (!did.has(parent.id())) { q.push(parent); } } } elesfn.forEachUp = function (fn) { var includeSelf = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; return forEachCompound(this, fn, includeSelf, addParent); }; function addParentAndChildren(q, did, ele) { addParent(q, did, ele); addChildren(q, did, ele); } elesfn.forEachUpAndDown = function (fn) { var includeSelf = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; return forEachCompound(this, fn, includeSelf, addParentAndChildren); }; // aliases elesfn.ancestors = elesfn.parents; module.exports = elesfn; /***/ }), /* 55 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var define = __webpack_require__(4); var fn = void 0, elesfn = void 0; fn = elesfn = { data: define.data({ field: 'data', bindingEvent: 'data', allowBinding: true, allowSetting: true, settingEvent: 'data', settingTriggersEvent: true, triggerFnName: 'trigger', allowGetting: true, immutableKeys: { 'id': true, 'source': true, 'target': true, 'parent': true }, updateStyle: true }), removeData: define.removeData({ field: 'data', event: 'data', triggerFnName: 'trigger', triggerEvent: true, immutableKeys: { 'id': true, 'source': true, 'target': true, 'parent': true }, updateStyle: true }), scratch: define.data({ field: 'scratch', bindingEvent: 'scratch', allowBinding: true, allowSetting: true, settingEvent: 'scratch', settingTriggersEvent: true, triggerFnName: 'trigger', allowGetting: true, updateStyle: true }), removeScratch: define.removeData({ field: 'scratch', event: 'scratch', triggerFnName: 'trigger', triggerEvent: true, updateStyle: true }), rscratch: define.data({ field: 'rscratch', allowBinding: false, allowSetting: true, settingTriggersEvent: false, allowGetting: true }), removeRscratch: define.removeData({ field: 'rscratch', triggerEvent: false }), id: function id() { var ele = this[0]; if (ele) { return ele._private.data.id; } } }; // aliases fn.attr = fn.data; fn.removeAttr = fn.removeData; module.exports = elesfn; /***/ }), /* 56 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var elesfn = {}; function defineDegreeFunction(callback) { return function (includeLoops) { var self = this; if (includeLoops === undefined) { includeLoops = true; } if (self.length === 0) { return; } if (self.isNode() && !self.removed()) { var degree = 0; var node = self[0]; var connectedEdges = node._private.edges; for (var i = 0; i < connectedEdges.length; i++) { var edge = connectedEdges[i]; if (!includeLoops && edge.isLoop()) { continue; } degree += callback(node, edge); } return degree; } else { return; } }; } util.extend(elesfn, { degree: defineDegreeFunction(function (node, edge) { if (edge.source().same(edge.target())) { return 2; } else { return 1; } }), indegree: defineDegreeFunction(function (node, edge) { if (edge.target().same(node)) { return 1; } else { return 0; } }), outdegree: defineDegreeFunction(function (node, edge) { if (edge.source().same(node)) { return 1; } else { return 0; } }) }); function defineDegreeBoundsFunction(degreeFn, callback) { return function (includeLoops) { var ret = void 0; var nodes = this.nodes(); for (var i = 0; i < nodes.length; i++) { var ele = nodes[i]; var degree = ele[degreeFn](includeLoops); if (degree !== undefined && (ret === undefined || callback(degree, ret))) { ret = degree; } } return ret; }; } util.extend(elesfn, { minDegree: defineDegreeBoundsFunction('degree', function (degree, min) { return degree < min; }), maxDegree: defineDegreeBoundsFunction('degree', function (degree, max) { return degree > max; }), minIndegree: defineDegreeBoundsFunction('indegree', function (degree, min) { return degree < min; }), maxIndegree: defineDegreeBoundsFunction('indegree', function (degree, max) { return degree > max; }), minOutdegree: defineDegreeBoundsFunction('outdegree', function (degree, min) { return degree < min; }), maxOutdegree: defineDegreeBoundsFunction('outdegree', function (degree, max) { return degree > max; }) }); util.extend(elesfn, { totalDegree: function totalDegree(includeLoops) { var total = 0; var nodes = this.nodes(); for (var i = 0; i < nodes.length; i++) { total += nodes[i].degree(includeLoops); } return total; } }); module.exports = elesfn; /***/ }), /* 57 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var position = __webpack_require__(58); var bounds = __webpack_require__(59); var widthHeight = __webpack_require__(60); var edgePoints = __webpack_require__(61); module.exports = util.assign({}, position, bounds, widthHeight, edgePoints); /***/ }), /* 58 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var define = __webpack_require__(4); var is = __webpack_require__(0); var math = __webpack_require__(2); var fn = void 0, elesfn = void 0; var beforePositionSet = function beforePositionSet(eles, newPos) { for (var i = 0; i < eles.length; i++) { var ele = eles[i]; if (ele.isParent() && !ele.locked()) { var oldPos = ele._private.position; var delta = { x: newPos.x - oldPos.x, y: newPos.y - oldPos.y }; eles.children().shift(delta); } } }; fn = elesfn = { position: define.data({ field: 'position', bindingEvent: 'position', allowBinding: true, allowSetting: true, settingEvent: 'position', settingTriggersEvent: true, triggerFnName: 'emitAndNotify', allowGetting: true, validKeys: ['x', 'y'], beforeGet: function beforeGet(ele) { ele.updateCompoundBounds(); }, beforeSet: beforePositionSet, onSet: function onSet(eles) { eles.dirtyCompoundBoundsCache(); }, canSet: function canSet(ele) { return !ele.locked(); } }), // position but no notification to renderer silentPosition: define.data({ field: 'position', bindingEvent: 'position', allowBinding: false, allowSetting: true, settingEvent: 'position', settingTriggersEvent: false, triggerFnName: 'trigger', allowGetting: false, validKeys: ['x', 'y'], beforeSet: beforePositionSet, onSet: function onSet(eles) { eles.dirtyCompoundBoundsCache(); }, canSet: function canSet(ele) { return !ele.locked(); } }), positions: function positions(pos, silent) { if (is.plainObject(pos)) { if (silent) { this.silentPosition(pos); } else { this.position(pos); } } else if (is.fn(pos)) { var _fn = pos; var cy = this.cy(); cy.startBatch(); for (var i = 0; i < this.length; i++) { var ele = this[i]; var _pos = void 0; if (_pos = _fn(ele, i)) { if (silent) { ele.silentPosition(_pos); } else { ele.position(_pos); } } } cy.endBatch(); } return this; // chaining }, silentPositions: function silentPositions(pos) { return this.positions(pos, true); }, shift: function shift(dim, val) { var delta = void 0; if (is.plainObject(dim)) { delta = dim; } else if (is.string(dim) && is.number(val)) { delta = { x: 0, y: 0 }; delta[dim] = val; } if (delta != null) { for (var i = 0; i < this.length; i++) { var ele = this[i]; var pos = ele.position(); ele.position({ x: pos.x + delta.x, y: pos.y + delta.y }); } } return this; }, // get/set the rendered (i.e. on screen) positon of the element renderedPosition: function renderedPosition(dim, val) { var ele = this[0]; var cy = this.cy(); var zoom = cy.zoom(); var pan = cy.pan(); var rpos = is.plainObject(dim) ? dim : undefined; var setting = rpos !== undefined || val !== undefined && is.string(dim); if (ele && ele.isNode()) { // must have an element and must be a node to return position if (setting) { for (var i = 0; i < this.length; i++) { var _ele = this[i]; if (val !== undefined) { // set one dimension _ele.position(dim, (val - pan[dim]) / zoom); } else if (rpos !== undefined) { // set whole position _ele.position(math.renderedToModelPosition(rpos, zoom, pan)); } } } else { // getting var pos = ele.position(); rpos = math.modelToRenderedPosition(pos, zoom, pan); if (dim === undefined) { // then return the whole rendered position return rpos; } else { // then return the specified dimension return rpos[dim]; } } } else if (!setting) { return undefined; // for empty collection case } return this; // chaining }, // get/set the position relative to the parent relativePosition: function relativePosition(dim, val) { var ele = this[0]; var cy = this.cy(); var ppos = is.plainObject(dim) ? dim : undefined; var setting = ppos !== undefined || val !== undefined && is.string(dim); var hasCompoundNodes = cy.hasCompoundNodes(); if (ele && ele.isNode()) { // must have an element and must be a node to return position if (setting) { for (var i = 0; i < this.length; i++) { var _ele2 = this[i]; var parent = hasCompoundNodes ? _ele2.parent() : null; var hasParent = parent && parent.length > 0; var relativeToParent = hasParent; if (hasParent) { parent = parent[0]; } var origin = relativeToParent ? parent.position() : { x: 0, y: 0 }; if (val !== undefined) { // set one dimension _ele2.position(dim, val + origin[dim]); } else if (ppos !== undefined) { // set whole position _ele2.position({ x: ppos.x + origin.x, y: ppos.y + origin.y }); } } } else { // getting var pos = ele.position(); var _parent = hasCompoundNodes ? ele.parent() : null; var _hasParent = _parent && _parent.length > 0; var _relativeToParent = _hasParent; if (_hasParent) { _parent = _parent[0]; } var _origin = _relativeToParent ? _parent.position() : { x: 0, y: 0 }; ppos = { x: pos.x - _origin.x, y: pos.y - _origin.y }; if (dim === undefined) { // then return the whole rendered position return ppos; } else { // then return the specified dimension return ppos[dim]; } } } else if (!setting) { return undefined; // for empty collection case } return this; // chaining } }; // aliases fn.modelPosition = fn.point = fn.position; fn.modelPositions = fn.points = fn.positions; fn.renderedPoint = fn.renderedPosition; fn.relativePoint = fn.relativePosition; module.exports = elesfn; /***/ }), /* 59 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var util = __webpack_require__(1); var math = __webpack_require__(2); var fn = void 0, elesfn = void 0; fn = elesfn = {}; elesfn.renderedBoundingBox = function (options) { var bb = this.boundingBox(options); var cy = this.cy(); var zoom = cy.zoom(); var pan = cy.pan(); var x1 = bb.x1 * zoom + pan.x; var x2 = bb.x2 * zoom + pan.x; var y1 = bb.y1 * zoom + pan.y; var y2 = bb.y2 * zoom + pan.y; return { x1: x1, x2: x2, y1: y1, y2: y2, w: x2 - x1, h: y2 - y1 }; }; elesfn.dirtyCompoundBoundsCache = function () { var cy = this.cy(); if (!cy.styleEnabled() || !cy.hasCompoundNodes()) { return this; } this.forEachUp(function (ele) { ele._private.compoundBoundsClean = false; if (ele.isParent()) { ele.emit('bounds'); } }); return this; }; elesfn.updateCompoundBounds = function () { var cy = this.cy(); // save cycles for non compound graphs or when style disabled if (!cy.styleEnabled() || !cy.hasCompoundNodes()) { return this; } // save cycles when batching -- but bounds will be stale (or not exist yet) if (cy.batching()) { return this; } var updated = []; function update(parent) { if (!parent.isParent()) { return; } var _p = parent._private; var children = parent.children(); var includeLabels = parent.pstyle('compound-sizing-wrt-labels').value === 'include'; var min = { width: { val: parent.pstyle('min-width').pfValue, left: parent.pstyle('min-width-bias-left'), right: parent.pstyle('min-width-bias-right') }, height: { val: parent.pstyle('min-height').pfValue, top: parent.pstyle('min-height-bias-top'), bottom: parent.pstyle('min-height-bias-bottom') } }; var bb = children.boundingBox({ includeLabels: includeLabels, includeOverlays: false, // updating the compound bounds happens outside of the regular // cache cycle (i.e. before fired events) useCache: false }); var pos = _p.position; // if children take up zero area then keep position and fall back on stylesheet w/h if (bb.w === 0 || bb.h === 0) { bb = { w: parent.pstyle('width').pfValue, h: parent.pstyle('height').pfValue }; bb.x1 = pos.x - bb.w / 2; bb.x2 = pos.x + bb.w / 2; bb.y1 = pos.y - bb.h / 2; bb.y2 = pos.y + bb.h / 2; } function computeBiasValues(propDiff, propBias, propBiasComplement) { var biasDiff = 0; var biasComplementDiff = 0; var biasTotal = propBias + propBiasComplement; if (propDiff > 0 && biasTotal > 0) { biasDiff = propBias / biasTotal * propDiff; biasComplementDiff = propBiasComplement / biasTotal * propDiff; } return { biasDiff: biasDiff, biasComplementDiff: biasComplementDiff }; } function computePaddingValues(width, height, paddingObject, relativeTo) { // Assuming percentage is number from 0 to 1 if (paddingObject.units === '%') { switch (relativeTo) { case 'width': return width > 0 ? paddingObject.pfValue * width : 0; case 'height': return height > 0 ? paddingObject.pfValue * height : 0; case 'average': return width > 0 && height > 0 ? paddingObject.pfValue * (width + height) / 2 : 0; case 'min': return width > 0 && height > 0 ? width > height ? paddingObject.pfValue * height : paddingObject.pfValue * width : 0; case 'max': return width > 0 && height > 0 ? width > height ? paddingObject.pfValue * width : paddingObject.pfValue * height : 0; default: return 0; } } else if (paddingObject.units === 'px') { return paddingObject.pfValue; } else { return 0; } } var leftVal = min.width.left.value; if (min.width.left.units === 'px' && min.width.val > 0) { leftVal = leftVal * 100 / min.width.val; } var rightVal = min.width.right.value; if (min.width.right.units === 'px' && min.width.val > 0) { rightVal = rightVal * 100 / min.width.val; } var topVal = min.height.top.value; if (min.height.top.units === 'px' && min.height.val > 0) { topVal = topVal * 100 / min.height.val; } var bottomVal = min.height.bottom.value; if (min.height.bottom.units === 'px' && min.height.val > 0) { bottomVal = bottomVal * 100 / min.height.val; } var widthBiasDiffs = computeBiasValues(min.width.val - bb.w, leftVal, rightVal); var diffLeft = widthBiasDiffs.biasDiff; var diffRight = widthBiasDiffs.biasComplementDiff; var heightBiasDiffs = computeBiasValues(min.height.val - bb.h, topVal, bottomVal); var diffTop = heightBiasDiffs.biasDiff; var diffBottom = heightBiasDiffs.biasComplementDiff; _p.autoPadding = computePaddingValues(bb.w, bb.h, parent.pstyle('padding'), parent.pstyle('padding-relative-to').value); _p.autoWidth = Math.max(bb.w, min.width.val); pos.x = (-diffLeft + bb.x1 + bb.x2 + diffRight) / 2; _p.autoHeight = Math.max(bb.h, min.height.val); pos.y = (-diffTop + bb.y1 + bb.y2 + diffBottom) / 2; updated.push(parent); } for (var i = 0; i < this.length; i++) { var ele = this[i]; var _p = ele._private; if (!_p.compoundBoundsClean) { update(ele); if (!cy._private.batchingStyle) { _p.compoundBoundsClean = true; } } } return this; }; var noninf = function noninf(x) { if (x === Infinity || x === -Infinity) { return 0; } return x; }; var updateBounds = function updateBounds(b, x1, y1, x2, y2) { // don't update with zero area boxes if (x2 - x1 === 0 || y2 - y1 === 0) { return; } // don't update with null dim if (x1 == null || y1 == null || x2 == null || y2 == null) { return; } b.x1 = x1 < b.x1 ? x1 : b.x1; b.x2 = x2 > b.x2 ? x2 : b.x2; b.y1 = y1 < b.y1 ? y1 : b.y1; b.y2 = y2 > b.y2 ? y2 : b.y2; }; var updateBoundsFromBox = function updateBoundsFromBox(b, b2) { return updateBounds(b, b2.x1, b2.y1, b2.x2, b2.y2); }; var prefixedProperty = function prefixedProperty(obj, field, prefix) { return util.getPrefixedProperty(obj, field, prefix); }; var updateBoundsFromArrow = function updateBoundsFromArrow(bounds, ele, prefix) { if (ele.cy().headless()) { return; } var _p = ele._private; var rstyle = _p.rstyle; var halfArW = rstyle.arrowWidth / 2; var arrowType = ele.pstyle(prefix + '-arrow-shape').value; var x = void 0; var y = void 0; if (arrowType !== 'none') { if (prefix === 'source') { x = rstyle.srcX; y = rstyle.srcY; } else if (prefix === 'target') { x = rstyle.tgtX; y = rstyle.tgtY; } else { x = rstyle.midX; y = rstyle.midY; } updateBounds(bounds, x - halfArW, y - halfArW, x + halfArW, y + halfArW); } }; var updateBoundsFromLabel = function updateBoundsFromLabel(bounds, ele, prefix) { if (ele.cy().headless()) { return; } var prefixDash = void 0; if (prefix) { prefixDash = prefix + '-'; } else { prefixDash = ''; } var _p = ele._private; var rstyle = _p.rstyle; var label = ele.pstyle(prefixDash + 'label').strValue; if (label) { var halign = ele.pstyle('text-halign'); var valign = ele.pstyle('text-valign'); var labelWidth = prefixedProperty(rstyle, 'labelWidth', prefix); var labelHeight = prefixedProperty(rstyle, 'labelHeight', prefix); var labelX = prefixedProperty(rstyle, 'labelX', prefix); var labelY = prefixedProperty(rstyle, 'labelY', prefix); var marginX = ele.pstyle(prefixDash + 'text-margin-x').pfValue; var marginY = ele.pstyle(prefixDash + 'text-margin-y').pfValue; var isEdge = ele.isEdge(); var rotation = ele.pstyle(prefixDash + 'text-rotation'); var outlineWidth = ele.pstyle('text-outline-width').pfValue; var borderWidth = ele.pstyle('text-border-width').pfValue; var halfBorderWidth = borderWidth / 2; var padding = ele.pstyle('text-background-padding').pfValue; var lh = labelHeight + 2 * padding; var lw = labelWidth + 2 * padding; var lw_2 = lw / 2; var lh_2 = lh / 2; var lx1 = void 0, lx2 = void 0, ly1 = void 0, ly2 = void 0; if (isEdge) { lx1 = labelX - lw_2; lx2 = labelX + lw_2; ly1 = labelY - lh_2; ly2 = labelY + lh_2; } else { switch (halign.value) { case 'left': lx1 = labelX - lw; lx2 = labelX; break; case 'center': lx1 = labelX - lw_2; lx2 = labelX + lw_2; break; case 'right': lx1 = labelX; lx2 = labelX + lw; break; } switch (valign.value) { case 'top': ly1 = labelY - lh; ly2 = labelY; break; case 'center': ly1 = labelY - lh_2; ly2 = labelY + lh_2; break; case 'bottom': ly1 = labelY; ly2 = labelY + lh; break; } } var isAutorotate = isEdge && rotation.strValue === 'autorotate'; var isPfValue = rotation.pfValue != null && rotation.pfValue !== 0; if (isAutorotate || isPfValue) { var theta = isAutorotate ? prefixedProperty(_p.rstyle, 'labelAngle', prefix) : rotation.pfValue; var cos = Math.cos(theta); var sin = Math.sin(theta); var rotate = function rotate(x, y) { x = x - labelX; y = y - labelY; return { x: x * cos - y * sin + labelX, y: x * sin + y * cos + labelY }; }; var px1y1 = rotate(lx1, ly1); var px1y2 = rotate(lx1, ly2); var px2y1 = rotate(lx2, ly1); var px2y2 = rotate(lx2, ly2); lx1 = Math.min(px1y1.x, px1y2.x, px2y1.x, px2y2.x); lx2 = Math.max(px1y1.x, px1y2.x, px2y1.x, px2y2.x); ly1 = Math.min(px1y1.y, px1y2.y, px2y1.y, px2y2.y); ly2 = Math.max(px1y1.y, px1y2.y, px2y1.y, px2y2.y); } lx1 += marginX - Math.max(outlineWidth, halfBorderWidth); lx2 += marginX + Math.max(outlineWidth, halfBorderWidth); ly1 += marginY - Math.max(outlineWidth, halfBorderWidth); ly2 += marginY + Math.max(outlineWidth, halfBorderWidth); updateBounds(bounds, lx1, ly1, lx2, ly2); } return bounds; }; // get the bounding box of the elements (in raw model position) var boundingBoxImpl = function boundingBoxImpl(ele, options) { var cy = ele._private.cy; var styleEnabled = cy.styleEnabled(); var headless = cy.headless(); var bounds = { x1: Infinity, y1: Infinity, x2: -Infinity, y2: -Infinity }; var _p = ele._private; var display = styleEnabled ? ele.pstyle('display').value : 'element'; var isNode = ele.isNode(); var isEdge = ele.isEdge(); var ex1 = void 0, ex2 = void 0, ey1 = void 0, ey2 = void 0; // extrema of body / lines var x = void 0, y = void 0; // node pos var displayed = display !== 'none'; if (displayed) { var overlayOpacity = 0; var overlayPadding = 0; if (styleEnabled && options.includeOverlays) { overlayOpacity = ele.pstyle('overlay-opacity').value; if (overlayOpacity !== 0) { overlayPadding = ele.pstyle('overlay-padding').value; } } var w = 0; var wHalf = 0; if (styleEnabled) { w = ele.pstyle('width').pfValue; wHalf = w / 2; } if (isNode && options.includeNodes) { var pos = ele.position(); x = pos.x; y = pos.y; var _w = ele.outerWidth(); var halfW = _w / 2; var h = ele.outerHeight(); var halfH = h / 2; // handle node dimensions ///////////////////////// ex1 = x - halfW - overlayPadding; ex2 = x + halfW + overlayPadding; ey1 = y - halfH - overlayPadding; ey2 = y + halfH + overlayPadding; updateBounds(bounds, ex1, ey1, ex2, ey2); } else if (isEdge && options.includeEdges) { var rstyle = _p.rstyle || {}; // handle edge dimensions (rough box estimate) ////////////////////////////////////////////// if (styleEnabled && !headless) { ex1 = Math.min(rstyle.srcX, rstyle.midX, rstyle.tgtX); ex2 = Math.max(rstyle.srcX, rstyle.midX, rstyle.tgtX); ey1 = Math.min(rstyle.srcY, rstyle.midY, rstyle.tgtY); ey2 = Math.max(rstyle.srcY, rstyle.midY, rstyle.tgtY); // take into account edge width ex1 -= wHalf; ex2 += wHalf; ey1 -= wHalf; ey2 += wHalf; updateBounds(bounds, ex1, ey1, ex2, ey2); } // precise haystacks //////////////////// if (styleEnabled && !headless && ele.pstyle('curve-style').strValue === 'haystack') { var hpts = rstyle.haystackPts || []; ex1 = hpts[0].x; ey1 = hpts[0].y; ex2 = hpts[1].x; ey2 = hpts[1].y; if (ex1 > ex2) { var temp = ex1; ex1 = ex2; ex2 = temp; } if (ey1 > ey2) { var _temp = ey1; ey1 = ey2; ey2 = _temp; } updateBounds(bounds, ex1 - wHalf, ey1 - wHalf, ex2 + wHalf, ey2 + wHalf); // handle points along edge /////////////////////////// } else { var pts = rstyle.bezierPts || rstyle.linePts || []; for (var j = 0; j < pts.length; j++) { var pt = pts[j]; ex1 = pt.x - wHalf; ex2 = pt.x + wHalf; ey1 = pt.y - wHalf; ey2 = pt.y + wHalf; updateBounds(bounds, ex1, ey1, ex2, ey2); } // fallback on source and target positions ////////////////////////////////////////// if (pts.length === 0) { var n1 = ele.source(); var n1pos = n1.position(); var n2 = ele.target(); var n2pos = n2.position(); ex1 = n1pos.x; ex2 = n2pos.x; ey1 = n1pos.y; ey2 = n2pos.y; if (ex1 > ex2) { var _temp2 = ex1; ex1 = ex2; ex2 = _temp2; } if (ey1 > ey2) { var _temp3 = ey1; ey1 = ey2; ey2 = _temp3; } // take into account edge width ex1 -= wHalf; ex2 += wHalf; ey1 -= wHalf; ey2 += wHalf; updateBounds(bounds, ex1, ey1, ex2, ey2); } } } // edges // handle edge arrow size ///////////////////////// if (styleEnabled && options.includeEdges && isEdge) { updateBoundsFromArrow(bounds, ele, 'mid-source', options); updateBoundsFromArrow(bounds, ele, 'mid-target', options); updateBoundsFromArrow(bounds, ele, 'source', options); updateBoundsFromArrow(bounds, ele, 'target', options); } // ghost //////// if (styleEnabled) { var ghost = ele.pstyle('ghost').value === 'yes'; if (ghost) { var gx = ele.pstyle('ghost-offset-x').pfValue; var gy = ele.pstyle('ghost-offset-y').pfValue; updateBounds(bounds, bounds.x1 + gx, bounds.y1 + gy, bounds.x2 + gx, bounds.y2 + gy); } } // overlay ////////// if (styleEnabled) { ex1 = bounds.x1; ex2 = bounds.x2; ey1 = bounds.y1; ey2 = bounds.y2; updateBounds(bounds, ex1 - overlayPadding, ey1 - overlayPadding, ex2 + overlayPadding, ey2 + overlayPadding); } // handle label dimensions ////////////////////////// if (styleEnabled && options.includeLabels) { updateBoundsFromLabel(bounds, ele, null, options); if (isEdge) { updateBoundsFromLabel(bounds, ele, 'source', options); updateBoundsFromLabel(bounds, ele, 'target', options); } } // style enabled for labels } // if displayed bounds.x1 = noninf(bounds.x1); bounds.y1 = noninf(bounds.y1); bounds.x2 = noninf(bounds.x2); bounds.y2 = noninf(bounds.y2); bounds.w = noninf(bounds.x2 - bounds.x1); bounds.h = noninf(bounds.y2 - bounds.y1); // expand bounds by 1 because antialiasing can increase the visual/effective size by 1 on all sides if (bounds.w > 0 && bounds.h > 0 && displayed) { math.expandBoundingBox(bounds, 1); } return bounds; }; var tf = function tf(val) { if (val) { return 't'; } else { return 'f'; } }; var getKey = function getKey(opts) { var key = ''; key += tf(opts.incudeNodes); key += tf(opts.includeEdges); key += tf(opts.includeLabels); key += tf(opts.includeOverlays); return key; }; var cachedBoundingBoxImpl = function cachedBoundingBoxImpl(ele, opts) { var _p = ele._private; var bb = void 0; var headless = ele.cy().headless(); var key = opts === defBbOpts ? defBbOptsKey : getKey(opts); if (!opts.useCache || headless || !_p.bbCache || !_p.bbCache[key]) { bb = boundingBoxImpl(ele, opts); if (!headless) { _p.bbCache = _p.bbCache || {}; _p.bbCache[key] = bb; } } else { bb = _p.bbCache[key]; } return bb; }; var defBbOpts = { includeNodes: true, includeEdges: true, includeLabels: true, includeOverlays: true, useCache: true }; var defBbOptsKey = getKey(defBbOpts); function filledBbOpts(options) { return { includeNodes: util.default(options.includeNodes, defBbOpts.includeNodes), includeEdges: util.default(options.includeEdges, defBbOpts.includeEdges), includeLabels: util.default(options.includeLabels, defBbOpts.includeLabels), includeOverlays: util.default(options.includeOverlays, defBbOpts.includeOverlays), useCache: util.default(options.useCache, defBbOpts.useCache) }; } elesfn.boundingBox = function (options) { // the main usecase is ele.boundingBox() for a single element with no/def options // specified s.t. the cache is used, so check for this case to make it faster by // avoiding the overhead of the rest of the function if (this.length === 1 && this[0]._private.bbCache && (options === undefined || options.useCache === undefined || options.useCache === true)) { if (options === undefined) { options = defBbOpts; } else { options = filledBbOpts(options); } return cachedBoundingBoxImpl(this[0], options); } var bounds = { x1: Infinity, y1: Infinity, x2: -Infinity, y2: -Infinity }; options = options || util.staticEmptyObject(); var opts = filledBbOpts(options); var eles = this; var cy = eles.cy(); var styleEnabled = cy.styleEnabled(); if (styleEnabled) { this.recalculateRenderedStyle(opts.useCache); } this.updateCompoundBounds(); var updatedEdge = {}; // use to avoid duplicated edge updates for (var i = 0; i < eles.length; i++) { var ele = eles[i]; if (styleEnabled && ele.isEdge() && ele.pstyle('curve-style').strValue === 'bezier' && !updatedEdge[ele.id()]) { var edges = ele.parallelEdges(); for (var j = 0; j < edges.length; j++) { // make all as updated updatedEdge[edges[j].id()] = true; } edges.recalculateRenderedStyle(opts.useCache); // n.b. ele.parallelEdges() single is cached } updateBoundsFromBox(bounds, cachedBoundingBoxImpl(ele, opts)); } bounds.x1 = noninf(bounds.x1); bounds.y1 = noninf(bounds.y1); bounds.x2 = noninf(bounds.x2); bounds.y2 = noninf(bounds.y2); bounds.w = noninf(bounds.x2 - bounds.x1); bounds.h = noninf(bounds.y2 - bounds.y1); return bounds; }; // private helper to get bounding box for custom node positions // - good for perf in certain cases but currently requires dirtying the rendered style // - would be better to not modify the nodes but the nodes are read directly everywhere in the renderer... // - try to use for only things like discrete layouts where the node position would change anyway elesfn.boundingBoxAt = function (fn) { var nodes = this.nodes(); if (is.plainObject(fn)) { var obj = fn; fn = function fn() { return obj; }; } // save the current position and set the new one, per node for (var i = 0; i < nodes.length; i++) { var n = nodes[i]; var _p = n._private; var pos = _p.position; var newPos = fn.call(n, n, i); _p.bbAtOldPos = { x: pos.x, y: pos.y }; if (newPos) { pos.x = newPos.x; pos.y = newPos.y; } } this.emit('dirty'); // let the renderer know we've manually dirtied rendered dim calcs nodes.dirtyCompoundBoundsCache().updateCompoundBounds(); var bb = this.boundingBox({ useCache: false }); // restore the original position, per node for (var _i = 0; _i < nodes.length; _i++) { var _n = nodes[_i]; var _p2 = _n._private; var _pos = _n._private.position; var old = _p2.bbAtOldPos; _pos.x = old.x; _pos.y = old.y; } nodes.dirtyCompoundBoundsCache(); this.emit('dirty'); // let the renderer know we've manually dirtied rendered dim calcs return bb; }; fn.boundingbox = fn.boundingBox; fn.renderedBoundingbox = fn.renderedBoundingBox; module.exports = elesfn; /***/ }), /* 60 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var fn = void 0, elesfn = void 0; fn = elesfn = {}; var defineDimFns = function defineDimFns(opts) { opts.uppercaseName = util.capitalize(opts.name); opts.autoName = 'auto' + opts.uppercaseName; opts.labelName = 'label' + opts.uppercaseName; opts.outerName = 'outer' + opts.uppercaseName; opts.uppercaseOuterName = util.capitalize(opts.outerName); fn[opts.name] = function dimImpl() { var ele = this[0]; var _p = ele._private; var cy = _p.cy; var styleEnabled = cy._private.styleEnabled; if (ele) { if (styleEnabled) { if (ele.isParent()) { ele.updateCompoundBounds(); return _p[opts.autoName] || 0; } var d = ele.pstyle(opts.name); switch (d.strValue) { case 'label': ele.recalculateRenderedStyle(); return _p.rstyle[opts.labelName] || 0; default: return d.pfValue; } } else { return 1; } } }; fn['outer' + opts.uppercaseName] = function outerDimImpl() { var ele = this[0]; var _p = ele._private; var cy = _p.cy; var styleEnabled = cy._private.styleEnabled; if (ele) { if (styleEnabled) { var dim = ele[opts.name](); var border = ele.pstyle('border-width').pfValue; // n.b. 1/2 each side var padding = 2 * ele.padding(); return dim + border + padding; } else { return 1; } } }; fn['rendered' + opts.uppercaseName] = function renderedDimImpl() { var ele = this[0]; if (ele) { var d = ele[opts.name](); return d * this.cy().zoom(); } }; fn['rendered' + opts.uppercaseOuterName] = function renderedOuterDimImpl() { var ele = this[0]; if (ele) { var od = ele[opts.outerName](); return od * this.cy().zoom(); } }; }; defineDimFns({ name: 'width' }); defineDimFns({ name: 'height' }); elesfn.padding = function () { var ele = this[0]; var _p = ele._private; if (ele.isParent()) { ele.updateCompoundBounds(); if (_p.autoPadding !== undefined) { return _p.autoPadding; } else { return ele.pstyle('padding').pfValue; } } else { return ele.pstyle('padding').pfValue; } }; module.exports = elesfn; /***/ }), /* 61 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var ifEdge = function ifEdge(self, then) { if (self.isEdge()) { return then(self.renderer()); } }; module.exports = { controlPoints: function controlPoints() { var _this = this; return ifEdge(this, function (renderer) { return renderer.getControlPoints(_this); }); }, segmentPoints: function segmentPoints() { var _this2 = this; return ifEdge(this, function (renderer) { return renderer.getSegmentPoints(_this2); }); }, sourceEndpoint: function sourceEndpoint() { var _this3 = this; return ifEdge(this, function (renderer) { return renderer.getSourceEndpoint(_this3); }); }, targetEndpoint: function targetEndpoint() { var _this4 = this; return ifEdge(this, function (renderer) { return renderer.getTargetEndpoint(_this4); }); }, midpoint: function midpoint() { var _this5 = this; return ifEdge(this, function (renderer) { return renderer.getEdgeMidpoint(_this5); }); } }; /***/ }), /* 62 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var Emitter = __webpack_require__(11); var define = __webpack_require__(4); var is = __webpack_require__(0); var util = __webpack_require__(1); var Selector = __webpack_require__(6); var emitterOptions = { qualifierCompare: function qualifierCompare(selector1, selector2) { if (selector1 == null || selector2 == null) { return selector1 == null && selector2 == null; } else { return selector1.sameText(selector2); } }, eventMatches: function eventMatches(ele, listener, eventObj) { var selector = listener.qualifier; if (selector != null) { return ele !== eventObj.target && is.element(eventObj.target) && selector.matches(eventObj.target); } return true; }, eventFields: function eventFields(ele) { return { cy: ele.cy(), target: ele }; }, callbackContext: function callbackContext(ele, listener, eventObj) { return listener.qualifier != null ? eventObj.target : ele; }, beforeEmit: function beforeEmit(context, listener /*, eventObj*/) { if (listener.conf && listener.conf.once) { listener.conf.onceCollection.removeListener(listener.event, listener.qualifier, listener.callback); } }, bubble: function bubble() { return true; }, parent: function parent(ele) { return ele.isChild() ? ele.parent() : ele.cy(); } }; var argSelector = function argSelector(arg) { if (is.string(arg)) { return new Selector(arg); } else { return arg; } }; var elesfn = { createEmitter: function createEmitter() { for (var i = 0; i < this.length; i++) { var ele = this[i]; var _p = ele._private; if (!_p.emitter) { _p.emitter = new Emitter(util.assign({ context: ele }, emitterOptions)); } } return this; }, emitter: function emitter() { return this._private.emitter; }, on: function on(events, selector, callback) { for (var i = 0; i < this.length; i++) { var ele = this[i]; ele.emitter().on(events, argSelector(selector), callback); } return this; }, removeListener: function removeListener(events, selector, callback) { for (var i = 0; i < this.length; i++) { var ele = this[i]; ele.emitter().removeListener(events, argSelector(selector), callback); } return this; }, one: function one(events, selector, callback) { for (var i = 0; i < this.length; i++) { var ele = this[i]; ele.emitter().one(events, argSelector(selector), callback); } return this; }, once: function once(events, selector, callback) { for (var i = 0; i < this.length; i++) { var ele = this[i]; ele.emitter().on(events, argSelector(selector), callback, { once: true, onceCollection: this }); } }, emit: function emit(events, extraParams) { for (var i = 0; i < this.length; i++) { var ele = this[i]; ele.emitter().emit(events, extraParams); } return this; }, emitAndNotify: function emitAndNotify(event, extraParams) { // for internal use only if (this.length === 0) { return; } // empty collections don't need to notify anything // notify renderer this.cy().notify({ type: event, eles: this }); this.emit(event, extraParams); return this; } }; define.eventAliasesOn(elesfn); module.exports = elesfn; /***/ }), /* 63 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var Selector = __webpack_require__(6); var elesfn = { nodes: function nodes(selector) { return this.filter(function (ele) { return ele.isNode(); }).filter(selector); }, edges: function edges(selector) { return this.filter(function (ele) { return ele.isEdge(); }).filter(selector); }, filter: function filter(_filter, thisArg) { if (_filter === undefined) { // check this first b/c it's the most common/performant case return this; } else if (is.string(_filter) || is.elementOrCollection(_filter)) { return new Selector(_filter).filter(this); } else if (is.fn(_filter)) { var filterEles = this.spawn(); var eles = this; for (var i = 0; i < eles.length; i++) { var ele = eles[i]; var include = thisArg ? _filter.apply(thisArg, [ele, i, eles]) : _filter(ele, i, eles); if (include) { filterEles.merge(ele); } } return filterEles; } return this.spawn(); // if not handled by above, give 'em an empty collection }, not: function not(toRemove) { if (!toRemove) { return this; } else { if (is.string(toRemove)) { toRemove = this.filter(toRemove); } var elements = []; var rMap = toRemove._private.map; for (var i = 0; i < this.length; i++) { var element = this[i]; var remove = rMap.has(element.id()); if (!remove) { elements.push(element); } } return this.spawn(elements); } }, absoluteComplement: function absoluteComplement() { var cy = this.cy(); return cy.mutableElements().not(this); }, intersect: function intersect(other) { // if a selector is specified, then filter by it instead if (is.string(other)) { var selector = other; return this.filter(selector); } var elements = []; var col1 = this; var col2 = other; var col1Smaller = this.length < other.length; var map2 = col1Smaller ? col2._private.map : col1._private.map; var col = col1Smaller ? col1 : col2; for (var i = 0; i < col.length; i++) { var id = col[i]._private.data.id; var entry = map2.get(id); if (entry) { elements.push(entry.ele); } } return this.spawn(elements); }, xor: function xor(other) { var cy = this._private.cy; if (is.string(other)) { other = cy.$(other); } var elements = []; var col1 = this; var col2 = other; var add = function add(col, other) { for (var i = 0; i < col.length; i++) { var ele = col[i]; var id = ele._private.data.id; var inOther = other.hasElementWithId(id); if (!inOther) { elements.push(ele); } } }; add(col1, col2); add(col2, col1); return this.spawn(elements); }, diff: function diff(other) { var cy = this._private.cy; if (is.string(other)) { other = cy.$(other); } var left = []; var right = []; var both = []; var col1 = this; var col2 = other; var add = function add(col, other, retEles) { for (var i = 0; i < col.length; i++) { var ele = col[i]; var id = ele._private.data.id; var inOther = other.hasElementWithId(id); if (inOther) { both.push(ele); } else { retEles.push(ele); } } }; add(col1, col2, left); add(col2, col1, right); return { left: this.spawn(left, { unique: true }), right: this.spawn(right, { unique: true }), both: this.spawn(both, { unique: true }) }; }, add: function add(toAdd) { var cy = this._private.cy; if (!toAdd) { return this; } if (is.string(toAdd)) { var selector = toAdd; toAdd = cy.mutableElements().filter(selector); } var elements = []; for (var i = 0; i < this.length; i++) { elements.push(this[i]); } var map = this._private.map; for (var _i = 0; _i < toAdd.length; _i++) { var add = !map.has(toAdd[_i].id()); if (add) { elements.push(toAdd[_i]); } } return this.spawn(elements); }, // in place merge on calling collection merge: function merge(toAdd) { var _p = this._private; var cy = _p.cy; if (!toAdd) { return this; } if (toAdd && is.string(toAdd)) { var selector = toAdd; toAdd = cy.mutableElements().filter(selector); } var map = _p.map; for (var i = 0; i < toAdd.length; i++) { var toAddEle = toAdd[i]; var id = toAddEle._private.data.id; var add = !map.has(id); if (add) { var index = this.length++; this[index] = toAddEle; map.set(id, { ele: toAddEle, index: index }); } else { // replace var _index = map.get(id).index; this[_index] = toAddEle; map.set(id, { ele: toAddEle, index: _index }); } } return this; // chaining }, // remove single ele in place in calling collection unmergeOne: function unmergeOne(ele) { ele = ele[0]; var _p = this._private; var id = ele._private.data.id; var map = _p.map; var entry = map.get(id); if (!entry) { return this; // no need to remove } var i = entry.index; // remove ele this[i] = undefined; map.delete(id); var unmergedLastEle = i === this.length - 1; // replace empty spot with last ele in collection if (this.length > 1 && !unmergedLastEle) { var lastEleI = this.length - 1; var lastEle = this[lastEleI]; var lastEleId = lastEle._private.data.id; this[lastEleI] = undefined; this[i] = lastEle; map.set(lastEleId, { ele: lastEle, index: i }); } // the collection is now 1 ele smaller this.length--; return this; }, // remove eles in place on calling collection unmerge: function unmerge(toRemove) { var cy = this._private.cy; if (!toRemove) { return this; } if (toRemove && is.string(toRemove)) { var selector = toRemove; toRemove = cy.mutableElements().filter(selector); } for (var i = 0; i < toRemove.length; i++) { this.unmergeOne(toRemove[i]); } return this; // chaining }, map: function map(mapFn, thisArg) { var arr = []; var eles = this; for (var i = 0; i < eles.length; i++) { var ele = eles[i]; var ret = thisArg ? mapFn.apply(thisArg, [ele, i, eles]) : mapFn(ele, i, eles); arr.push(ret); } return arr; }, reduce: function reduce(fn, initialValue) { var val = initialValue; var eles = this; for (var i = 0; i < eles.length; i++) { val = fn(val, eles[i], i, eles); } return val; }, max: function max(valFn, thisArg) { var max = -Infinity; var maxEle = void 0; var eles = this; for (var i = 0; i < eles.length; i++) { var ele = eles[i]; var val = thisArg ? valFn.apply(thisArg, [ele, i, eles]) : valFn(ele, i, eles); if (val > max) { max = val; maxEle = ele; } } return { value: max, ele: maxEle }; }, min: function min(valFn, thisArg) { var min = Infinity; var minEle = void 0; var eles = this; for (var i = 0; i < eles.length; i++) { var ele = eles[i]; var val = thisArg ? valFn.apply(thisArg, [ele, i, eles]) : valFn(ele, i, eles); if (val < min) { min = val; minEle = ele; } } return { value: min, ele: minEle }; } }; // aliases var fn = elesfn; fn['u'] = fn['|'] = fn['+'] = fn.union = fn.or = fn.add; fn['\\'] = fn['!'] = fn['-'] = fn.difference = fn.relativeComplement = fn.subtract = fn.not; fn['n'] = fn['&'] = fn['.'] = fn.and = fn.intersection = fn.intersect; fn['^'] = fn['(+)'] = fn['(-)'] = fn.symmetricDifference = fn.symdiff = fn.xor; fn.fnFilter = fn.filterFn = fn.stdFilter = fn.filter; fn.complement = fn.abscomp = fn.absoluteComplement; module.exports = elesfn; /***/ }), /* 64 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var elesfn = { isNode: function isNode() { return this.group() === 'nodes'; }, isEdge: function isEdge() { return this.group() === 'edges'; }, isLoop: function isLoop() { return this.isEdge() && this.source().id() === this.target().id(); }, isSimple: function isSimple() { return this.isEdge() && this.source().id() !== this.target().id(); }, group: function group() { var ele = this[0]; if (ele) { return ele._private.group; } } }; module.exports = elesfn; /***/ }), /* 65 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var zIndexSort = __webpack_require__(17); var util = __webpack_require__(1); var elesfn = { forEach: function forEach(fn, thisArg) { if (is.fn(fn)) { for (var i = 0; i < this.length; i++) { var ele = this[i]; var ret = thisArg ? fn.apply(thisArg, [ele, i, this]) : fn(ele, i, this); if (ret === false) { break; } // exit each early on return false } } return this; }, toArray: function toArray() { var array = []; for (var i = 0; i < this.length; i++) { array.push(this[i]); } return array; }, slice: function slice(start, end) { var array = []; var thisSize = this.length; if (end == null) { end = thisSize; } if (start == null) { start = 0; } if (start < 0) { start = thisSize + start; } if (end < 0) { end = thisSize + end; } for (var i = start; i >= 0 && i < end && i < thisSize; i++) { array.push(this[i]); } return this.spawn(array); }, size: function size() { return this.length; }, eq: function eq(i) { return this[i] || this.spawn(); }, first: function first() { return this[0] || this.spawn(); }, last: function last() { return this[this.length - 1] || this.spawn(); }, empty: function empty() { return this.length === 0; }, nonempty: function nonempty() { return !this.empty(); }, sort: function sort(sortFn) { if (!is.fn(sortFn)) { return this; } var sorted = this.toArray().sort(sortFn); return this.spawn(sorted); }, sortByZIndex: function sortByZIndex() { return this.sort(zIndexSort); }, zDepth: function zDepth() { var ele = this[0]; if (!ele) { return undefined; } // let cy = ele.cy(); var _p = ele._private; var group = _p.group; if (group === 'nodes') { var depth = _p.data.parent ? ele.parents().size() : 0; if (!ele.isParent()) { return util.MAX_INT - 1; // childless nodes always on top } return depth; } else { var src = _p.source; var tgt = _p.target; var srcDepth = src.zDepth(); var tgtDepth = tgt.zDepth(); return Math.max(srcDepth, tgtDepth, 0); // depth of deepest parent } } }; elesfn.each = elesfn.forEach; module.exports = elesfn; /***/ }), /* 66 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var util = __webpack_require__(1); var Promise = __webpack_require__(5); var math = __webpack_require__(2); var elesfn = { // Calculates and returns node dimensions { x, y } based on options given layoutDimensions: function layoutDimensions(options) { options = util.assign({ nodeDimensionsIncludeLabels: true }, options); if (options.nodeDimensionsIncludeLabels) { var bbDim = this.boundingBox(); return { w: bbDim.w, h: bbDim.h }; } else { return { w: this.outerWidth(), h: this.outerHeight() }; } }, // using standard layout options, apply position function (w/ or w/o animation) layoutPositions: function layoutPositions(layout, options, fn) { var nodes = this.nodes(); var cy = this.cy(); var layoutEles = options.eles; // nodes & edges var getMemoizeKey = function getMemoizeKey(node, i) { return node.id() + '$' + i; }; var fnMem = util.memoize(fn, getMemoizeKey); // memoized version of position function layout.emit({ type: 'layoutstart', layout: layout }); layout.animations = []; var calculateSpacing = function calculateSpacing(spacing, nodesBb, pos) { var center = { x: nodesBb.x1 + nodesBb.w / 2, y: nodesBb.y1 + nodesBb.h / 2 }; var spacingVector = { // scale from center of bounding box (not necessarily 0,0) x: (pos.x - center.x) * spacing, y: (pos.y - center.y) * spacing }; return { x: center.x + spacingVector.x, y: center.y + spacingVector.y }; }; var useSpacingFactor = options.spacingFactor && options.spacingFactor !== 1; var spacingBb = function spacingBb() { if (!useSpacingFactor) { return null; } var bb = math.makeBoundingBox(); for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; var pos = fnMem(node, i); math.expandBoundingBoxByPoint(bb, pos.x, pos.y); } return bb; }; var bb = spacingBb(); var getFinalPos = util.memoize(function (node, i) { var newPos = fnMem(node, i); var pos = node.position(); if (!is.number(pos.x) || !is.number(pos.y)) { node.silentPosition({ x: 0, y: 0 }); } if (useSpacingFactor) { var spacing = Math.abs(options.spacingFactor); newPos = calculateSpacing(spacing, bb, newPos); } if (options.transform != null) { newPos = options.transform(node, newPos); } return newPos; }, getMemoizeKey); if (options.animate) { for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; var newPos = getFinalPos(node, i); var animateNode = options.animateFilter == null || options.animateFilter(node, i); if (animateNode) { var ani = node.animation({ position: newPos, duration: options.animationDuration, easing: options.animationEasing }); layout.animations.push(ani); ani.play(); } else { node.position(newPos); } } if (options.fit) { var fitAni = cy.animation({ fit: { boundingBox: layoutEles.boundingBoxAt(getFinalPos), padding: options.padding }, duration: options.animationDuration, easing: options.animationEasing }); layout.animations.push(fitAni); fitAni.play(); } else if (options.zoom !== undefined && options.pan !== undefined) { var zoomPanAni = cy.animation({ zoom: options.zoom, pan: options.pan, duration: options.animationDuration, easing: options.animationEasing }); layout.animations.push(zoomPanAni); zoomPanAni.play(); } layout.one('layoutready', options.ready); layout.emit({ type: 'layoutready', layout: layout }); Promise.all(layout.animations.map(function (ani) { return ani.promise(); })).then(function () { layout.one('layoutstop', options.stop); layout.emit({ type: 'layoutstop', layout: layout }); }); } else { nodes.positions(getFinalPos); if (options.fit) { cy.fit(options.eles, options.padding); } if (options.zoom != null) { cy.zoom(options.zoom); } if (options.pan) { cy.pan(options.pan); } layout.one('layoutready', options.ready); layout.emit({ type: 'layoutready', layout: layout }); layout.one('layoutstop', options.stop); layout.emit({ type: 'layoutstop', layout: layout }); } return this; // chaining }, layout: function layout(options) { var cy = this.cy(); return cy.makeLayout(util.extend({}, options, { eles: this })); } }; // aliases: elesfn.createLayout = elesfn.makeLayout = elesfn.layout; module.exports = elesfn; /***/ }), /* 67 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); function styleCache(key, fn, ele) { var _p = ele._private; var cache = _p.styleCache = _p.styleCache || {}; var val; if ((val = cache[key]) != null) { return val; } else { val = cache[key] = fn(ele); return val; } } function cacheStyleFunction(key, fn) { return function cachedStyleFunction(ele) { return styleCache(key, fn, ele); }; } function cachePrototypeStyleFunction(key, fn) { var selfFn = function selfFn(ele) { return fn.call(ele); }; return function cachedPrototypeStyleFunction() { var ele = this[0]; if (ele) { return styleCache(key, selfFn, ele); } }; } var elesfn = { recalculateRenderedStyle: function recalculateRenderedStyle(useCache) { var cy = this.cy(); var renderer = cy.renderer(); var styleEnabled = cy.styleEnabled(); if (renderer && styleEnabled) { renderer.recalculateRenderedStyle(this, useCache); } return this; }, dirtyStyleCache: function dirtyStyleCache() { var cy = this.cy(); var dirty = function dirty(ele) { return ele._private.styleCache = {}; }; if (cy.hasCompoundNodes()) { var eles = void 0; eles = this.spawnSelf().merge(this.descendants()).merge(this.parents()); eles.merge(eles.connectedEdges()); eles.forEach(dirty); } else { this.forEach(function (ele) { dirty(ele); ele.connectedEdges().forEach(dirty); }); } return this; }, // fully updates (recalculates) the style for the elements updateStyle: function updateStyle(notifyRenderer) { var cy = this._private.cy; if (!cy.styleEnabled()) { return this; } if (cy._private.batchingStyle) { var bEles = cy._private.batchStyleEles; bEles.merge(this); return this; // chaining and exit early when batching } var hasCompounds = cy.hasCompoundNodes(); var style = cy.style(); var updatedEles = this; notifyRenderer = notifyRenderer || notifyRenderer === undefined ? true : false; if (hasCompounds) { // then add everything up and down for compound selector checks updatedEles = this.spawnSelf().merge(this.descendants()).merge(this.parents()); } var changedEles = style.apply(updatedEles); changedEles.dirtyStyleCache(); changedEles.dirtyCompoundBoundsCache(); if (notifyRenderer) { changedEles.emitAndNotify('style'); // let renderer know we changed style } else { changedEles.emit('style'); // just fire the event } return this; // chaining }, // just update the mappers in the elements' styles; cheaper than eles.updateStyle() updateMappers: function updateMappers(notifyRenderer) { var cy = this._private.cy; var style = cy.style(); notifyRenderer = notifyRenderer || notifyRenderer === undefined ? true : false; if (!cy.styleEnabled()) { return this; } var changedEles = style.updateMappers(this); changedEles.dirtyStyleCache(); changedEles.dirtyCompoundBoundsCache(); if (notifyRenderer) { changedEles.emitAndNotify('style'); // let renderer know we changed style } else { changedEles.emit('style'); // just fire the event } return this; // chaining }, // get the internal parsed style object for the specified property parsedStyle: function parsedStyle(property) { var ele = this[0]; var cy = ele.cy(); if (!cy.styleEnabled()) { return; } if (ele) { return ele._private.style[property] || cy.style().getDefaultProperty(property); } }, numericStyle: function numericStyle(property) { var ele = this[0]; if (!ele.cy().styleEnabled()) { return; } if (ele) { var pstyle = ele.pstyle(property); return pstyle.pfValue !== undefined ? pstyle.pfValue : pstyle.value; } }, numericStyleUnits: function numericStyleUnits(property) { var ele = this[0]; if (!ele.cy().styleEnabled()) { return; } if (ele) { return ele.pstyle(property).units; } }, // get the specified css property as a rendered value (i.e. on-screen value) // or get the whole rendered style if no property specified (NB doesn't allow setting) renderedStyle: function renderedStyle(property) { var cy = this.cy(); if (!cy.styleEnabled()) { return this; } var ele = this[0]; if (ele) { return cy.style().getRenderedStyle(ele, property); } }, // read the calculated css style of the element or override the style (via a bypass) style: function style(name, value) { var cy = this.cy(); if (!cy.styleEnabled()) { return this; } var updateTransitions = false; var style = cy.style(); if (is.plainObject(name)) { // then extend the bypass var props = name; style.applyBypass(this, props, updateTransitions); this.dirtyStyleCache(); this.dirtyCompoundBoundsCache(); this.emitAndNotify('style'); // let the renderer know we've updated style } else if (is.string(name)) { if (value === undefined) { // then get the property from the style var ele = this[0]; if (ele) { return style.getStylePropertyValue(ele, name); } else { // empty collection => can't get any value return; } } else { // then set the bypass with the property value style.applyBypass(this, name, value, updateTransitions); this.dirtyStyleCache(); this.dirtyCompoundBoundsCache(); this.emitAndNotify('style'); // let the renderer know we've updated style } } else if (name === undefined) { var _ele = this[0]; if (_ele) { return style.getRawStyle(_ele); } else { // empty collection => can't get any value return; } } return this; // chaining }, removeStyle: function removeStyle(names) { var cy = this.cy(); if (!cy.styleEnabled()) { return this; } var updateTransitions = false; var style = cy.style(); var eles = this; if (names === undefined) { for (var i = 0; i < eles.length; i++) { var ele = eles[i]; style.removeAllBypasses(ele, updateTransitions); } } else { names = names.split(/\s+/); for (var _i = 0; _i < eles.length; _i++) { var _ele2 = eles[_i]; style.removeBypasses(_ele2, names, updateTransitions); } } this.dirtyStyleCache(); this.dirtyCompoundBoundsCache(); this.emitAndNotify('style'); // let the renderer know we've updated style return this; // chaining }, show: function show() { this.css('display', 'element'); return this; // chaining }, hide: function hide() { this.css('display', 'none'); return this; // chaining }, effectiveOpacity: function effectiveOpacity() { var cy = this.cy(); if (!cy.styleEnabled()) { return 1; } var hasCompoundNodes = cy.hasCompoundNodes(); var ele = this[0]; if (ele) { var _p = ele._private; var parentOpacity = ele.pstyle('opacity').value; if (!hasCompoundNodes) { return parentOpacity; } var parents = !_p.data.parent ? null : ele.parents(); if (parents) { for (var i = 0; i < parents.length; i++) { var parent = parents[i]; var opacity = parent.pstyle('opacity').value; parentOpacity = opacity * parentOpacity; } } return parentOpacity; } }, transparent: function transparent() { var cy = this.cy(); if (!cy.styleEnabled()) { return false; } var ele = this[0]; var hasCompoundNodes = ele.cy().hasCompoundNodes(); if (ele) { if (!hasCompoundNodes) { return ele.pstyle('opacity').value === 0; } else { return ele.effectiveOpacity() === 0; } } }, backgrounding: function backgrounding() { var cy = this.cy(); if (!cy.styleEnabled()) { return false; } var ele = this[0]; return ele._private.backgrounding ? true : false; } }; function checkCompound(ele, parentOk) { var _p = ele._private; var parents = _p.data.parent ? ele.parents() : null; if (parents) { for (var i = 0; i < parents.length; i++) { var parent = parents[i]; if (!parentOk(parent)) { return false; } } } return true; } function defineDerivedStateFunction(specs) { var ok = specs.ok; var edgeOkViaNode = specs.edgeOkViaNode || specs.ok; var parentOk = specs.parentOk || specs.ok; return function () { var cy = this.cy(); if (!cy.styleEnabled()) { return true; } var ele = this[0]; var hasCompoundNodes = cy.hasCompoundNodes(); if (ele) { var _p = ele._private; if (!ok(ele)) { return false; } if (ele.isNode()) { return !hasCompoundNodes || checkCompound(ele, parentOk); } else { var src = _p.source; var tgt = _p.target; return edgeOkViaNode(src) && (!hasCompoundNodes || checkCompound(src, edgeOkViaNode)) && (src === tgt || edgeOkViaNode(tgt) && (!hasCompoundNodes || checkCompound(tgt, edgeOkViaNode))); } } }; } var eleTakesUpSpace = cacheStyleFunction('eleTakesUpSpace', function (ele) { return ele.pstyle('display').value === 'element' && ele.width() !== 0 && (ele.isNode() ? ele.height() !== 0 : true); }); elesfn.takesUpSpace = cachePrototypeStyleFunction('takesUpSpace', defineDerivedStateFunction({ ok: eleTakesUpSpace })); var eleInteractive = cacheStyleFunction('eleInteractive', function (ele) { return ele.pstyle('events').value === 'yes' && ele.pstyle('visibility').value === 'visible' && eleTakesUpSpace(ele); }); var parentInteractive = cacheStyleFunction('parentInteractive', function (parent) { return parent.pstyle('visibility').value === 'visible' && eleTakesUpSpace(parent); }); elesfn.interactive = cachePrototypeStyleFunction('interactive', defineDerivedStateFunction({ ok: eleInteractive, parentOk: parentInteractive, edgeOkViaNode: eleTakesUpSpace })); elesfn.noninteractive = function () { var ele = this[0]; if (ele) { return !ele.interactive(); } }; var eleVisible = cacheStyleFunction('eleVisible', function (ele) { return ele.pstyle('visibility').value === 'visible' && ele.pstyle('opacity').pfValue !== 0 && eleTakesUpSpace(ele); }); var edgeVisibleViaNode = eleTakesUpSpace; elesfn.visible = cachePrototypeStyleFunction('visible', defineDerivedStateFunction({ ok: eleVisible, edgeOkViaNode: edgeVisibleViaNode })); elesfn.hidden = function () { var ele = this[0]; if (ele) { return !ele.visible(); } }; elesfn.bypass = elesfn.css = elesfn.style; elesfn.renderedCss = elesfn.renderedStyle; elesfn.removeBypass = elesfn.removeCss = elesfn.removeStyle; elesfn.pstyle = elesfn.parsedStyle; module.exports = elesfn; /***/ }), /* 68 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var elesfn = {}; function defineSwitchFunction(params) { return function () { var args = arguments; var changedEles = []; // e.g. cy.nodes().select( data, handler ) if (args.length === 2) { var data = args[0]; var handler = args[1]; this.on(params.event, data, handler); } // e.g. cy.nodes().select( handler ) else if (args.length === 1) { var _handler = args[0]; this.on(params.event, _handler); } // e.g. cy.nodes().select() else if (args.length === 0) { for (var i = 0; i < this.length; i++) { var ele = this[i]; var able = !params.ableField || ele._private[params.ableField]; var changed = ele._private[params.field] != params.value; if (params.overrideAble) { var overrideAble = params.overrideAble(ele); if (overrideAble !== undefined) { able = overrideAble; if (!overrideAble) { return this; } // to save cycles assume not able for all on override } } if (able) { ele._private[params.field] = params.value; if (changed) { changedEles.push(ele); } } } var changedColl = this.spawn(changedEles); changedColl.updateStyle(); // change of state => possible change of style changedColl.emit(params.event); } return this; }; } function defineSwitchSet(params) { elesfn[params.field] = function () { var ele = this[0]; if (ele) { if (params.overrideField) { var val = params.overrideField(ele); if (val !== undefined) { return val; } } return ele._private[params.field]; } }; elesfn[params.on] = defineSwitchFunction({ event: params.on, field: params.field, ableField: params.ableField, overrideAble: params.overrideAble, value: true }); elesfn[params.off] = defineSwitchFunction({ event: params.off, field: params.field, ableField: params.ableField, overrideAble: params.overrideAble, value: false }); } defineSwitchSet({ field: 'locked', overrideField: function overrideField(ele) { return ele.cy().autolock() ? true : undefined; }, on: 'lock', off: 'unlock' }); defineSwitchSet({ field: 'grabbable', overrideField: function overrideField(ele) { return ele.cy().autoungrabify() ? false : undefined; }, on: 'grabify', off: 'ungrabify' }); defineSwitchSet({ field: 'selected', ableField: 'selectable', overrideAble: function overrideAble(ele) { return ele.cy().autounselectify() ? false : undefined; }, on: 'select', off: 'unselect' }); defineSwitchSet({ field: 'selectable', overrideField: function overrideField(ele) { return ele.cy().autounselectify() ? false : undefined; }, on: 'selectify', off: 'unselectify' }); elesfn.deselect = elesfn.unselect; elesfn.grabbed = function () { var ele = this[0]; if (ele) { return ele._private.grabbed; } }; defineSwitchSet({ field: 'active', on: 'activate', off: 'unactivate' }); elesfn.inactive = function () { var ele = this[0]; if (ele) { return !ele._private.active; } }; module.exports = elesfn; /***/ }), /* 69 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var is = __webpack_require__(0); var elesfn = {}; var cache = function cache(fn, name) { return function traversalCache(arg1, arg2, arg3, arg4) { var selectorOrEles = arg1; var eles = this; var key = void 0; if (selectorOrEles == null) { key = 'null'; } else if (is.elementOrCollection(selectorOrEles) && selectorOrEles.length === 1) { key = '#' + selectorOrEles.id(); } if (eles.length === 1 && key) { var _p = eles[0]._private; var tch = _p.traversalCache = _p.traversalCache || {}; var ch = tch[name] = tch[name] || {}; var cacheHit = ch[key]; if (cacheHit) { return cacheHit; } else { return ch[key] = fn.call(eles, arg1, arg2, arg3, arg4); } } else { return fn.call(eles, arg1, arg2, arg3, arg4); } }; }; // DAG functions //////////////// var defineDagExtremity = function defineDagExtremity(params) { return function dagExtremityImpl(selector) { var eles = this; var ret = []; for (var i = 0; i < eles.length; i++) { var ele = eles[i]; if (!ele.isNode()) { continue; } var disqualified = false; var edges = ele.connectedEdges(); for (var j = 0; j < edges.length; j++) { var edge = edges[j]; var src = edge.source(); var tgt = edge.target(); if (params.noIncomingEdges && tgt === ele && src !== ele || params.noOutgoingEdges && src === ele && tgt !== ele) { disqualified = true; break; } } if (!disqualified) { ret.push(ele); } } return this.spawn(ret, { unique: true }).filter(selector); }; }; var defineDagOneHop = function defineDagOneHop(params) { return function (selector) { var eles = this; var oEles = []; for (var i = 0; i < eles.length; i++) { var ele = eles[i]; if (!ele.isNode()) { continue; } var edges = ele.connectedEdges(); for (var j = 0; j < edges.length; j++) { var edge = edges[j]; var src = edge.source(); var tgt = edge.target(); if (params.outgoing && src === ele) { oEles.push(edge); oEles.push(tgt); } else if (params.incoming && tgt === ele) { oEles.push(edge); oEles.push(src); } } } return this.spawn(oEles, { unique: true }).filter(selector); }; }; var defineDagAllHops = function defineDagAllHops(params) { return function (selector) { var eles = this; var sEles = []; var sElesIds = {}; for (;;) { var next = params.outgoing ? eles.outgoers() : eles.incomers(); if (next.length === 0) { break; } // done if none left var newNext = false; for (var i = 0; i < next.length; i++) { var n = next[i]; var nid = n.id(); if (!sElesIds[nid]) { sElesIds[nid] = true; sEles.push(n); newNext = true; } } if (!newNext) { break; } // done if touched all outgoers already eles = next; } return this.spawn(sEles, { unique: true }).filter(selector); }; }; elesfn.clearTraversalCache = function () { for (var i = 0; i < this.length; i++) { this[i]._private.traversalCache = null; } }; util.extend(elesfn, { // get the root nodes in the DAG roots: defineDagExtremity({ noIncomingEdges: true }), // get the leaf nodes in the DAG leaves: defineDagExtremity({ noOutgoingEdges: true }), // normally called children in graph theory // these nodes =edges=> outgoing nodes outgoers: cache(defineDagOneHop({ outgoing: true }), 'outgoers'), // aka DAG descendants successors: defineDagAllHops({ outgoing: true }), // normally called parents in graph theory // these nodes <=edges= incoming nodes incomers: cache(defineDagOneHop({ incoming: true }), 'incomers'), // aka DAG ancestors predecessors: defineDagAllHops({ incoming: true }) }); // Neighbourhood functions ////////////////////////// util.extend(elesfn, { neighborhood: cache(function (selector) { var elements = []; var nodes = this.nodes(); for (var i = 0; i < nodes.length; i++) { // for all nodes var node = nodes[i]; var connectedEdges = node.connectedEdges(); // for each connected edge, add the edge and the other node for (var j = 0; j < connectedEdges.length; j++) { var edge = connectedEdges[j]; var src = edge.source(); var tgt = edge.target(); var otherNode = node === src ? tgt : src; // need check in case of loop if (otherNode.length > 0) { elements.push(otherNode[0]); // add node 1 hop away } // add connected edge elements.push(edge[0]); } } return this.spawn(elements, { unique: true }).filter(selector); }, 'neighborhood'), closedNeighborhood: function closedNeighborhood(selector) { return this.neighborhood().add(this).filter(selector); }, openNeighborhood: function openNeighborhood(selector) { return this.neighborhood(selector); } }); // aliases elesfn.neighbourhood = elesfn.neighborhood; elesfn.closedNeighbourhood = elesfn.closedNeighborhood; elesfn.openNeighbourhood = elesfn.openNeighborhood; // Edge functions ///////////////// util.extend(elesfn, { source: cache(function sourceImpl(selector) { var ele = this[0]; var src = void 0; if (ele) { src = ele._private.source || ele.cy().collection(); } return src && selector ? src.filter(selector) : src; }, 'source'), target: cache(function targetImpl(selector) { var ele = this[0]; var tgt = void 0; if (ele) { tgt = ele._private.target || ele.cy().collection(); } return tgt && selector ? tgt.filter(selector) : tgt; }, 'target'), sources: defineSourceFunction({ attr: 'source' }), targets: defineSourceFunction({ attr: 'target' }) }); function defineSourceFunction(params) { return function sourceImpl(selector) { var sources = []; for (var i = 0; i < this.length; i++) { var ele = this[i]; var src = ele._private[params.attr]; if (src) { sources.push(src); } } return this.spawn(sources, { unique: true }).filter(selector); }; } util.extend(elesfn, { edgesWith: cache(defineEdgesWithFunction(), 'edgesWith'), edgesTo: cache(defineEdgesWithFunction({ thisIsSrc: true }), 'edgesTo') }); function defineEdgesWithFunction(params) { return function edgesWithImpl(otherNodes) { var elements = []; var cy = this._private.cy; var p = params || {}; // get elements if a selector is specified if (is.string(otherNodes)) { otherNodes = cy.$(otherNodes); } for (var h = 0; h < otherNodes.length; h++) { var edges = otherNodes[h]._private.edges; for (var i = 0; i < edges.length; i++) { var edge = edges[i]; var edgeData = edge._private.data; var thisToOther = this.hasElementWithId(edgeData.source) && otherNodes.hasElementWithId(edgeData.target); var otherToThis = otherNodes.hasElementWithId(edgeData.source) && this.hasElementWithId(edgeData.target); var edgeConnectsThisAndOther = thisToOther || otherToThis; if (!edgeConnectsThisAndOther) { continue; } if (p.thisIsSrc || p.thisIsTgt) { if (p.thisIsSrc && !thisToOther) { continue; } if (p.thisIsTgt && !otherToThis) { continue; } } elements.push(edge); } } return this.spawn(elements, { unique: true }); }; } util.extend(elesfn, { connectedEdges: cache(function (selector) { var retEles = []; var eles = this; for (var i = 0; i < eles.length; i++) { var node = eles[i]; if (!node.isNode()) { continue; } var edges = node._private.edges; for (var j = 0; j < edges.length; j++) { var edge = edges[j]; retEles.push(edge); } } return this.spawn(retEles, { unique: true }).filter(selector); }, 'connectedEdges'), connectedNodes: cache(function (selector) { var retEles = []; var eles = this; for (var i = 0; i < eles.length; i++) { var edge = eles[i]; if (!edge.isEdge()) { continue; } retEles.push(edge.source()[0]); retEles.push(edge.target()[0]); } return this.spawn(retEles, { unique: true }).filter(selector); }, 'connectedNodes'), parallelEdges: cache(defineParallelEdgesFunction(), 'parallelEdges'), codirectedEdges: cache(defineParallelEdgesFunction({ codirected: true }), 'codirectedEdges') }); function defineParallelEdgesFunction(params) { var defaults = { codirected: false }; params = util.extend({}, defaults, params); return function parallelEdgesImpl(selector) { // micro-optimised for renderer var elements = []; var edges = this.edges(); var p = params; // look at all the edges in the collection for (var i = 0; i < edges.length; i++) { var edge1 = edges[i]; var edge1_p = edge1._private; var src1 = edge1_p.source; var srcid1 = src1._private.data.id; var tgtid1 = edge1_p.data.target; var srcEdges1 = src1._private.edges; // look at edges connected to the src node of this edge for (var j = 0; j < srcEdges1.length; j++) { var edge2 = srcEdges1[j]; var edge2data = edge2._private.data; var tgtid2 = edge2data.target; var srcid2 = edge2data.source; var codirected = tgtid2 === tgtid1 && srcid2 === srcid1; var oppdirected = srcid1 === tgtid2 && tgtid1 === srcid2; if (p.codirected && codirected || !p.codirected && (codirected || oppdirected)) { elements.push(edge2); } } } return this.spawn(elements, { unique: true }).filter(selector); }; } // Misc functions ///////////////// util.extend(elesfn, { components: function components() { var self = this; var cy = self.cy(); var visited = self.spawn(); var unvisited = self.nodes().spawnSelf(); var components = []; var visitInComponent = function visitInComponent(node, component) { visited.merge(node); unvisited.unmerge(node); component.merge(node); }; if (unvisited.empty()) { return self.spawn(); } var _loop = function _loop() { var component = cy.collection(); components.push(component); var root = unvisited[0]; visitInComponent(root, component); self.bfs({ directed: false, roots: root, visit: function visit(v, e, u, i, depth) { visitInComponent(v, component); } }); }; do { _loop(); } while (unvisited.length > 0); return components.map(function (component) { var connectedEdges = component.connectedEdges().stdFilter(function (edge) { return component.anySame(edge.source()) && component.anySame(edge.target()); }); return component.union(connectedEdges); }); } }); module.exports = elesfn; /***/ }), /* 70 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var util = __webpack_require__(1); var Collection = __webpack_require__(7); var Element = __webpack_require__(14); var corefn = { add: function add(opts) { var elements = void 0; var cy = this; // add the elements if (is.elementOrCollection(opts)) { var eles = opts; if (eles._private.cy === cy) { // same instance => just restore elements = eles.restore(); } else { // otherwise, copy from json var jsons = []; for (var i = 0; i < eles.length; i++) { var ele = eles[i]; jsons.push(ele.json()); } elements = new Collection(cy, jsons); } } // specify an array of options else if (is.array(opts)) { var _jsons = opts; elements = new Collection(cy, _jsons); } // specify via opts.nodes and opts.edges else if (is.plainObject(opts) && (is.array(opts.nodes) || is.array(opts.edges))) { var elesByGroup = opts; var _jsons2 = []; var grs = ['nodes', 'edges']; for (var _i = 0, il = grs.length; _i < il; _i++) { var group = grs[_i]; var elesArray = elesByGroup[group]; if (is.array(elesArray)) { for (var j = 0, jl = elesArray.length; j < jl; j++) { var json = util.extend({ group: group }, elesArray[j]); _jsons2.push(json); } } } elements = new Collection(cy, _jsons2); } // specify options for one element else { var _json = opts; elements = new Element(cy, _json).collection(); } return elements; }, remove: function remove(collection) { if (is.elementOrCollection(collection)) { // already have right ref } else if (is.string(collection)) { var selector = collection; collection = this.$(selector); } return collection.remove(); } }; module.exports = corefn; /***/ }), /* 71 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var define = __webpack_require__(4); var util = __webpack_require__(1); var stepAll = __webpack_require__(72); var corefn = { // pull in animation functions animate: define.animate(), animation: define.animation(), animated: define.animated(), clearQueue: define.clearQueue(), delay: define.delay(), delayAnimation: define.delayAnimation(), stop: define.stop(), addToAnimationPool: function addToAnimationPool(eles) { var cy = this; if (!cy.styleEnabled()) { return; } // save cycles when no style used cy._private.aniEles.merge(eles); }, stopAnimationLoop: function stopAnimationLoop() { this._private.animationsRunning = false; }, startAnimationLoop: function startAnimationLoop() { var cy = this; cy._private.animationsRunning = true; if (!cy.styleEnabled()) { return; } // save cycles when no style used // NB the animation loop will exec in headless environments if style enabled // and explicit cy.destroy() is necessary to stop the loop function headlessStep() { if (!cy._private.animationsRunning) { return; } util.requestAnimationFrame(function animationStep(now) { stepAll(now, cy); headlessStep(); }); } var renderer = cy.renderer(); if (renderer && renderer.beforeRender) { // let the renderer schedule animations renderer.beforeRender(function rendererAnimationStep(willDraw, now) { stepAll(now, cy); }, renderer.beforeRenderPriorities.animations); } else { // manage the animation loop ourselves headlessStep(); // first call } } }; module.exports = corefn; /***/ }), /* 72 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var step = __webpack_require__(73); var startAnimation = __webpack_require__(78); function stepAll(now, cy) { var eles = cy._private.aniEles; var doneEles = []; function stepOne(ele, isCore) { var _p = ele._private; var current = _p.animation.current; var queue = _p.animation.queue; var ranAnis = false; // cancel all animations on display:none ele if (!isCore && ele.pstyle('display').value === 'none') { // put all current and queue animations in this tick's current list // and empty the lists for the element current = current.splice(0, current.length).concat(queue.splice(0, queue.length)); // stop all animations for (var i = 0; i < current.length; i++) { current[i].stop(); } } // if nothing currently animating, get something from the queue if (current.length === 0) { var next = queue.shift(); if (next) { current.push(next); } } var callbacks = function callbacks(_callbacks) { for (var j = _callbacks.length - 1; j >= 0; j--) { var cb = _callbacks[j]; cb(); } _callbacks.splice(0, _callbacks.length); }; // step and remove if done for (var _i = current.length - 1; _i >= 0; _i--) { var ani = current[_i]; var ani_p = ani._private; if (ani_p.stopped) { current.splice(_i, 1); ani_p.hooked = false; ani_p.playing = false; ani_p.started = false; callbacks(ani_p.frames); continue; } if (!ani_p.playing && !ani_p.applying) { continue; } // an apply() while playing shouldn't do anything if (ani_p.playing && ani_p.applying) { ani_p.applying = false; } if (!ani_p.started) { startAnimation(ele, ani, now, isCore); } step(ele, ani, now, isCore); if (ani_p.applying) { ani_p.applying = false; } callbacks(ani_p.frames); if (ani.completed()) { current.splice(_i, 1); ani_p.hooked = false; ani_p.playing = false; ani_p.started = false; callbacks(ani_p.completes); } ranAnis = true; } if (!isCore && current.length === 0 && queue.length === 0) { doneEles.push(ele); } return ranAnis; } // stepElement // handle all eles var ranEleAni = false; for (var e = 0; e < eles.length; e++) { var ele = eles[e]; var handledThisEle = stepOne(ele); ranEleAni = ranEleAni || handledThisEle; } // each element var ranCoreAni = stepOne(cy, true); // notify renderer if (ranEleAni || ranCoreAni) { if (eles.length > 0) { eles.dirtyCompoundBoundsCache(); cy.notify({ type: 'draw', eles: eles }); } else { cy.notify({ type: 'draw' }); } } // remove elements from list of currently animating if its queues are empty eles.unmerge(doneEles); cy.emit('step'); } // stepAll module.exports = stepAll; /***/ }), /* 73 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var easings = __webpack_require__(74); var ease = __webpack_require__(77); var is = __webpack_require__(0); function step(self, ani, now, isCore) { var isEles = !isCore; var _p = self._private; var ani_p = ani._private; var pEasing = ani_p.easing; var startTime = ani_p.startTime; var cy = isCore ? self : self.cy(); var style = cy.style(); if (!ani_p.easingImpl) { if (pEasing == null) { // use default ani_p.easingImpl = easings['linear']; } else { // then define w/ name var easingVals = void 0; if (is.string(pEasing)) { var easingProp = style.parse('transition-timing-function', pEasing); easingVals = easingProp.value; } else { // then assume preparsed array easingVals = pEasing; } var name = void 0, args = void 0; if (is.string(easingVals)) { name = easingVals; args = []; } else { name = easingVals[1]; args = easingVals.slice(2).map(function (n) { return +n; }); } if (args.length > 0) { // create with args if (name === 'spring') { args.push(ani_p.duration); // need duration to generate spring } ani_p.easingImpl = easings[name].apply(null, args); } else { // static impl by name ani_p.easingImpl = easings[name]; } } } var easing = ani_p.easingImpl; var percent = void 0; if (ani_p.duration === 0) { percent = 1; } else { percent = (now - startTime) / ani_p.duration; } if (ani_p.applying) { percent = ani_p.progress; } if (percent < 0) { percent = 0; } else if (percent > 1) { percent = 1; } if (ani_p.delay == null) { // then update var startPos = ani_p.startPosition; var endPos = ani_p.position; if (endPos && isEles && !self.locked()) { var pos = self.position(); if (valid(startPos.x, endPos.x)) { pos.x = ease(startPos.x, endPos.x, percent, easing); } if (valid(startPos.y, endPos.y)) { pos.y = ease(startPos.y, endPos.y, percent, easing); } self.emit('position'); } var startPan = ani_p.startPan; var endPan = ani_p.pan; var pan = _p.pan; var animatingPan = endPan != null && isCore; if (animatingPan) { if (valid(startPan.x, endPan.x)) { pan.x = ease(startPan.x, endPan.x, percent, easing); } if (valid(startPan.y, endPan.y)) { pan.y = ease(startPan.y, endPan.y, percent, easing); } self.emit('pan'); } var startZoom = ani_p.startZoom; var endZoom = ani_p.zoom; var animatingZoom = endZoom != null && isCore; if (animatingZoom) { if (valid(startZoom, endZoom)) { _p.zoom = ease(startZoom, endZoom, percent, easing); } self.emit('zoom'); } if (animatingPan || animatingZoom) { self.emit('viewport'); } var props = ani_p.style; if (props && props.length > 0 && isEles) { for (var i = 0; i < props.length; i++) { var prop = props[i]; var _name = prop.name; var end = prop; var start = ani_p.startStyle[_name]; var propSpec = style.properties[start.name]; var easedVal = ease(start, end, percent, easing, propSpec); style.overrideBypass(self, _name, easedVal); } // for props self.emit('style'); } // if } ani_p.progress = percent; return percent; } function valid(start, end) { if (start == null || end == null) { return false; } if (is.number(start) && is.number(end)) { return true; } else if (start && end) { return true; } return false; } module.exports = step; /***/ }), /* 74 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var generateCubicBezier = __webpack_require__(75); var generateSpringRK4 = __webpack_require__(76); var cubicBezier = function cubicBezier(t1, p1, t2, p2) { var bezier = generateCubicBezier(t1, p1, t2, p2); return function (start, end, percent) { return start + (end - start) * bezier(percent); }; }; var easings = { 'linear': function linear(start, end, percent) { return start + (end - start) * percent; }, // default easings 'ease': cubicBezier(0.25, 0.1, 0.25, 1), 'ease-in': cubicBezier(0.42, 0, 1, 1), 'ease-out': cubicBezier(0, 0, 0.58, 1), 'ease-in-out': cubicBezier(0.42, 0, 0.58, 1), // sine 'ease-in-sine': cubicBezier(0.47, 0, 0.745, 0.715), 'ease-out-sine': cubicBezier(0.39, 0.575, 0.565, 1), 'ease-in-out-sine': cubicBezier(0.445, 0.05, 0.55, 0.95), // quad 'ease-in-quad': cubicBezier(0.55, 0.085, 0.68, 0.53), 'ease-out-quad': cubicBezier(0.25, 0.46, 0.45, 0.94), 'ease-in-out-quad': cubicBezier(0.455, 0.03, 0.515, 0.955), // cubic 'ease-in-cubic': cubicBezier(0.55, 0.055, 0.675, 0.19), 'ease-out-cubic': cubicBezier(0.215, 0.61, 0.355, 1), 'ease-in-out-cubic': cubicBezier(0.645, 0.045, 0.355, 1), // quart 'ease-in-quart': cubicBezier(0.895, 0.03, 0.685, 0.22), 'ease-out-quart': cubicBezier(0.165, 0.84, 0.44, 1), 'ease-in-out-quart': cubicBezier(0.77, 0, 0.175, 1), // quint 'ease-in-quint': cubicBezier(0.755, 0.05, 0.855, 0.06), 'ease-out-quint': cubicBezier(0.23, 1, 0.32, 1), 'ease-in-out-quint': cubicBezier(0.86, 0, 0.07, 1), // expo 'ease-in-expo': cubicBezier(0.95, 0.05, 0.795, 0.035), 'ease-out-expo': cubicBezier(0.19, 1, 0.22, 1), 'ease-in-out-expo': cubicBezier(1, 0, 0, 1), // circ 'ease-in-circ': cubicBezier(0.6, 0.04, 0.98, 0.335), 'ease-out-circ': cubicBezier(0.075, 0.82, 0.165, 1), 'ease-in-out-circ': cubicBezier(0.785, 0.135, 0.15, 0.86), // user param easings... 'spring': function spring(tension, friction, duration) { if (duration === 0) { // can't get a spring w/ duration 0 return easings.linear; // duration 0 => jump to end so impl doesn't matter } var spring = generateSpringRK4(tension, friction, duration); return function (start, end, percent) { return start + (end - start) * spring(percent); }; }, 'cubic-bezier': cubicBezier }; module.exports = easings; /***/ }), /* 75 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /* global Float32Array */ /*! Bezier curve function generator. Copyright Gaetan Renaudeau. MIT License: http://en.wikipedia.org/wiki/MIT_License */ function generateCubicBezier(mX1, mY1, mX2, mY2) { var NEWTON_ITERATIONS = 4, NEWTON_MIN_SLOPE = 0.001, SUBDIVISION_PRECISION = 0.0000001, SUBDIVISION_MAX_ITERATIONS = 10, kSplineTableSize = 11, kSampleStepSize = 1.0 / (kSplineTableSize - 1.0), float32ArraySupported = typeof Float32Array !== 'undefined'; /* Must contain four arguments. */ if (arguments.length !== 4) { return false; } /* Arguments must be numbers. */ for (var i = 0; i < 4; ++i) { if (typeof arguments[i] !== "number" || isNaN(arguments[i]) || !isFinite(arguments[i])) { return false; } } /* X values must be in the [0, 1] range. */ mX1 = Math.min(mX1, 1); mX2 = Math.min(mX2, 1); mX1 = Math.max(mX1, 0); mX2 = Math.max(mX2, 0); var mSampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize); function A(aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; } function B(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; } function C(aA1) { return 3.0 * aA1; } function calcBezier(aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; } function getSlope(aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); } function newtonRaphsonIterate(aX, aGuessT) { for (var _i = 0; _i < NEWTON_ITERATIONS; ++_i) { var currentSlope = getSlope(aGuessT, mX1, mX2); if (currentSlope === 0.0) { return aGuessT; } var currentX = calcBezier(aGuessT, mX1, mX2) - aX; aGuessT -= currentX / currentSlope; } return aGuessT; } function calcSampleValues() { for (var _i2 = 0; _i2 < kSplineTableSize; ++_i2) { mSampleValues[_i2] = calcBezier(_i2 * kSampleStepSize, mX1, mX2); } } function binarySubdivide(aX, aA, aB) { var currentX = void 0, currentT = void 0, i = 0; do { currentT = aA + (aB - aA) / 2.0; currentX = calcBezier(currentT, mX1, mX2) - aX; if (currentX > 0.0) { aB = currentT; } else { aA = currentT; } } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS); return currentT; } function getTForX(aX) { var intervalStart = 0.0, currentSample = 1, lastSample = kSplineTableSize - 1; for (; currentSample !== lastSample && mSampleValues[currentSample] <= aX; ++currentSample) { intervalStart += kSampleStepSize; } --currentSample; var dist = (aX - mSampleValues[currentSample]) / (mSampleValues[currentSample + 1] - mSampleValues[currentSample]), guessForT = intervalStart + dist * kSampleStepSize, initialSlope = getSlope(guessForT, mX1, mX2); if (initialSlope >= NEWTON_MIN_SLOPE) { return newtonRaphsonIterate(aX, guessForT); } else if (initialSlope === 0.0) { return guessForT; } else { return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize); } } var _precomputed = false; function precompute() { _precomputed = true; if (mX1 !== mY1 || mX2 !== mY2) { calcSampleValues(); } } var f = function f(aX) { if (!_precomputed) { precompute(); } if (mX1 === mY1 && mX2 === mY2) { return aX; } if (aX === 0) { return 0; } if (aX === 1) { return 1; } return calcBezier(getTForX(aX), mY1, mY2); }; f.getControlPoints = function () { return [{ x: mX1, y: mY1 }, { x: mX2, y: mY2 }]; }; var str = "generateBezier(" + [mX1, mY1, mX2, mY2] + ")"; f.toString = function () { return str; }; return f; } module.exports = generateCubicBezier; /***/ }), /* 76 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! Runge-Kutta spring physics function generator. Adapted from Framer.js, copyright Koen Bok. MIT License: http://en.wikipedia.org/wiki/MIT_License */ /* Given a tension, friction, and duration, a simulation at 60FPS will first run without a defined duration in order to calculate the full path. A second pass then adjusts the time delta -- using the relation between actual time and duration -- to calculate the path for the duration-constrained animation. */ var generateSpringRK4 = function () { function springAccelerationForState(state) { return -state.tension * state.x - state.friction * state.v; } function springEvaluateStateWithDerivative(initialState, dt, derivative) { var state = { x: initialState.x + derivative.dx * dt, v: initialState.v + derivative.dv * dt, tension: initialState.tension, friction: initialState.friction }; return { dx: state.v, dv: springAccelerationForState(state) }; } function springIntegrateState(state, dt) { var a = { dx: state.v, dv: springAccelerationForState(state) }, b = springEvaluateStateWithDerivative(state, dt * 0.5, a), c = springEvaluateStateWithDerivative(state, dt * 0.5, b), d = springEvaluateStateWithDerivative(state, dt, c), dxdt = 1.0 / 6.0 * (a.dx + 2.0 * (b.dx + c.dx) + d.dx), dvdt = 1.0 / 6.0 * (a.dv + 2.0 * (b.dv + c.dv) + d.dv); state.x = state.x + dxdt * dt; state.v = state.v + dvdt * dt; return state; } return function springRK4Factory(tension, friction, duration) { var initState = { x: -1, v: 0, tension: null, friction: null }, path = [0], time_lapsed = 0, tolerance = 1 / 10000, DT = 16 / 1000, have_duration = void 0, dt = void 0, last_state = void 0; tension = parseFloat(tension) || 500; friction = parseFloat(friction) || 20; duration = duration || null; initState.tension = tension; initState.friction = friction; have_duration = duration !== null; /* Calculate the actual time it takes for this animation to complete with the provided conditions. */ if (have_duration) { /* Run the simulation without a duration. */ time_lapsed = springRK4Factory(tension, friction); /* Compute the adjusted time delta. */ dt = time_lapsed / duration * DT; } else { dt = DT; } for (;;) { /* Next/step function .*/ last_state = springIntegrateState(last_state || initState, dt); /* Store the position. */ path.push(1 + last_state.x); time_lapsed += 16; /* If the change threshold is reached, break. */ if (!(Math.abs(last_state.x) > tolerance && Math.abs(last_state.v) > tolerance)) { break; } } /* If duration is not defined, return the actual time required for completing this animation. Otherwise, return a closure that holds the computed path and returns a snapshot of the position according to a given percentComplete. */ return !have_duration ? time_lapsed : function (percentComplete) { return path[percentComplete * (path.length - 1) | 0]; }; }; }(); module.exports = generateSpringRK4; /***/ }), /* 77 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); function getEasedValue(type, start, end, percent, easingFn) { if (percent === 1) { return end; } var val = easingFn(start, end, percent); if (type == null) { return val; } if (type.roundValue || type.color) { val = Math.round(val); } if (type.min !== undefined) { val = Math.max(val, type.min); } if (type.max !== undefined) { val = Math.min(val, type.max); } return val; } function getValue(prop, spec) { if (prop.pfValue != null || prop.value != null) { if (prop.pfValue != null && (spec == null || spec.type.units !== '%')) { return prop.pfValue; } else { return prop.value; } } else { return prop; } } function ease(startProp, endProp, percent, easingFn, propSpec) { var type = propSpec != null ? propSpec.type : null; if (percent < 0) { percent = 0; } else if (percent > 1) { percent = 1; } var start = getValue(startProp, propSpec); var end = getValue(endProp, propSpec); if (is.number(start) && is.number(end)) { return getEasedValue(type, start, end, percent, easingFn); } else if (is.array(start) && is.array(end)) { var easedArr = []; for (var i = 0; i < end.length; i++) { var si = start[i]; var ei = end[i]; if (si != null && ei != null) { var val = getEasedValue(type, si, ei, percent, easingFn); easedArr.push(val); } else { easedArr.push(ei); } } return easedArr; } return undefined; } module.exports = ease; /***/ }), /* 78 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; function startAnimation(self, ani, now, isCore) { var isEles = !isCore; var ele = self; var ani_p = ani._private; var cy = isCore ? self : self.cy(); var style = cy.style(); if (isEles) { var pos = ele.position(); ani_p.startPosition = ani_p.startPosition || { x: pos.x, y: pos.y }; ani_p.startStyle = ani_p.startStyle || style.getAnimationStartStyle(ele, ani_p.style); } if (isCore) { var pan = cy._private.pan; ani_p.startPan = ani_p.startPan || { x: pan.x, y: pan.y }; ani_p.startZoom = ani_p.startZoom != null ? ani_p.startZoom : cy._private.zoom; } ani_p.started = true; ani_p.startTime = now - ani_p.progress * ani_p.duration; } module.exports = startAnimation; /***/ }), /* 79 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var Emitter = __webpack_require__(11); var define = __webpack_require__(4); var is = __webpack_require__(0); var util = __webpack_require__(1); var Selector = __webpack_require__(6); var emitterOptions = { qualifierCompare: function qualifierCompare(selector1, selector2) { if (selector1 == null || selector2 == null) { return selector1 == null && selector2 == null; } else { return selector1.sameText(selector2); } }, eventMatches: function eventMatches(cy, listener, eventObj) { var selector = listener.qualifier; if (selector != null) { return cy !== eventObj.target && is.element(eventObj.target) && selector.matches(eventObj.target); } return true; }, eventFields: function eventFields(cy) { return { cy: cy, target: cy }; }, callbackContext: function callbackContext(cy, listener, eventObj) { return listener.qualifier != null ? eventObj.target : cy; } }; var argSelector = function argSelector(arg) { if (is.string(arg)) { return new Selector(arg); } else { return arg; } }; var elesfn = { createEmitter: function createEmitter() { var _p = this._private; if (!_p.emitter) { _p.emitter = new Emitter(util.assign({ context: this }, emitterOptions)); } return this; }, emitter: function emitter() { return this._private.emitter; }, on: function on(events, selector, callback) { this.emitter().on(events, argSelector(selector), callback); return this; }, removeListener: function removeListener(events, selector, callback) { this.emitter().removeListener(events, argSelector(selector), callback); return this; }, one: function one(events, selector, callback) { this.emitter().one(events, argSelector(selector), callback); return this; }, once: function once(events, selector, callback) { this.emitter().one(events, argSelector(selector), callback); return this; }, emit: function emit(events, extraParams) { this.emitter().emit(events, extraParams); return this; } }; define.eventAliasesOn(elesfn); module.exports = elesfn; /***/ }), /* 80 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var corefn = { png: function png(options) { var renderer = this._private.renderer; options = options || {}; return renderer.png(options); }, jpg: function jpg(options) { var renderer = this._private.renderer; options = options || {}; options.bg = options.bg || '#fff'; return renderer.jpg(options); } }; corefn.jpeg = corefn.jpg; module.exports = corefn; /***/ }), /* 81 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var is = __webpack_require__(0); var corefn = { layout: function layout(options) { var cy = this; if (options == null) { util.error('Layout options must be specified to make a layout'); return; } if (options.name == null) { util.error('A `name` must be specified to make a layout'); return; } var name = options.name; var Layout = cy.extension('layout', name); if (Layout == null) { util.error('Can not apply layout: No such layout `' + name + '` found; did you include its JS file?'); return; } var eles = void 0; if (is.string(options.eles)) { eles = cy.$(options.eles); } else { eles = options.eles != null ? options.eles : cy.$(); } var layout = new Layout(util.extend({}, options, { cy: cy, eles: eles })); return layout; } }; corefn.createLayout = corefn.makeLayout = corefn.layout; module.exports = corefn; /***/ }), /* 82 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var corefn = { notify: function notify(params) { var _p = this._private; if (_p.batchingNotify) { var bEles = _p.batchNotifyEles; var bTypes = _p.batchNotifyTypes; if (params.eles) { bEles.merge(params.eles); } if (!bTypes.ids[params.type]) { bTypes.push(params.type); bTypes.ids[params.type] = true; } return; // notifications are disabled during batching } if (!_p.notificationsEnabled) { return; } // exit on disabled var renderer = this.renderer(); // exit if destroy() called on core or renderer in between frames #1499 #1528 if (this.isDestroyed() || !renderer) { return; } renderer.notify(params); }, notifications: function notifications(bool) { var p = this._private; if (bool === undefined) { return p.notificationsEnabled; } else { p.notificationsEnabled = bool ? true : false; } }, noNotifications: function noNotifications(callback) { this.notifications(false); callback(); this.notifications(true); }, batching: function batching() { return this._private.batchCount > 0; }, startBatch: function startBatch() { var _p = this._private; if (_p.batchCount == null) { _p.batchCount = 0; } if (_p.batchCount === 0) { _p.batchingStyle = _p.batchingNotify = true; _p.batchStyleEles = this.collection(); _p.batchNotifyEles = this.collection(); _p.batchNotifyTypes = []; _p.batchNotifyTypes.ids = {}; } _p.batchCount++; return this; }, endBatch: function endBatch() { var _p = this._private; _p.batchCount--; if (_p.batchCount === 0) { // update style for dirty eles _p.batchingStyle = false; _p.batchStyleEles.updateStyle(); // notify the renderer of queued eles and event types _p.batchingNotify = false; this.notify({ type: _p.batchNotifyTypes, eles: _p.batchNotifyEles }); } return this; }, batch: function batch(callback) { this.startBatch(); callback(); this.endBatch(); return this; }, // for backwards compatibility batchData: function batchData(map) { var cy = this; return this.batch(function () { var ids = Object.keys(map); for (var i = 0; i < ids.length; i++) { var id = ids[i]; var data = map[id]; var ele = cy.getElementById(id); ele.data(data); } }); } }; module.exports = corefn; /***/ }), /* 83 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var corefn = { renderTo: function renderTo(context, zoom, pan, pxRatio) { var r = this._private.renderer; r.renderTo(context, zoom, pan, pxRatio); return this; }, renderer: function renderer() { return this._private.renderer; }, forceRender: function forceRender() { this.notify({ type: 'draw' }); return this; }, resize: function resize() { this.invalidateSize(); this.notify({ type: 'resize' }); this.emit('resize'); return this; }, initRenderer: function initRenderer(options) { var cy = this; var RendererProto = cy.extension('renderer', options.name); if (RendererProto == null) { util.error('Can not initialise: No such renderer `%s` found; did you include its JS file?', options.name); return; } cy._private.renderer = new RendererProto(util.extend({}, options, { cy: cy })); this.notify({ type: 'init' }); }, destroyRenderer: function destroyRenderer() { var cy = this; cy.notify({ type: 'destroy' }); // destroy the renderer var domEle = cy.container(); if (domEle) { domEle._cyreg = null; while (domEle.childNodes.length > 0) { domEle.removeChild(domEle.childNodes[0]); } } cy._private.renderer = null; // to be extra safe, remove the ref }, onRender: function onRender(fn) { return this.on('render', fn); }, offRender: function offRender(fn) { return this.off('render', fn); } }; corefn.invalidateDimensions = corefn.resize; module.exports = corefn; /***/ }), /* 84 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var Collection = __webpack_require__(7); var corefn = { // get a collection // - empty collection on no args // - collection of elements in the graph on selector arg // - guarantee a returned collection when elements or collection specified collection: function collection(eles, opts) { if (is.string(eles)) { return this.$(eles); } else if (is.elementOrCollection(eles)) { return eles.collection(); } else if (is.array(eles)) { return new Collection(this, eles, opts); } return new Collection(this); }, nodes: function nodes(selector) { var nodes = this.$(function (ele) { return ele.isNode(); }); if (selector) { return nodes.filter(selector); } return nodes; }, edges: function edges(selector) { var edges = this.$(function (ele) { return ele.isEdge(); }); if (selector) { return edges.filter(selector); } return edges; }, // search the graph like jQuery $: function $(selector) { var eles = this._private.elements; if (selector) { return eles.filter(selector); } else { return eles.spawnSelf(); } }, mutableElements: function mutableElements() { return this._private.elements; } }; // aliases corefn.elements = corefn.filter = corefn.$; module.exports = corefn; /***/ }), /* 85 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var Style = __webpack_require__(18); var corefn = { style: function style(newStyle) { if (newStyle) { var s = this.setStyle(newStyle); s.update(); } return this._private.style; }, setStyle: function setStyle(style) { var _p = this._private; if (is.stylesheet(style)) { _p.style = style.generateStyle(this); } else if (is.array(style)) { _p.style = Style.fromJson(this, style); } else if (is.string(style)) { _p.style = Style.fromString(this, style); } else { _p.style = Style(this); } return _p.style; } }; module.exports = corefn; /***/ }), /* 86 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var is = __webpack_require__(0); var Promise = __webpack_require__(5); var styfn = {}; // (potentially expensive calculation) // apply the style to the element based on // - its bypass // - what selectors match it styfn.apply = function (eles) { var self = this; var _p = self._private; var cy = _p.cy; var updatedEles = cy.collection(); if (_p.newStyle) { // clear style caches _p.contextStyles = {}; _p.propDiffs = {}; self.cleanElements(eles, true); } for (var ie = 0; ie < eles.length; ie++) { var ele = eles[ie]; var cxtMeta = self.getContextMeta(ele); if (cxtMeta.empty) { continue; } else { updatedEles.merge(ele); } var cxtStyle = self.getContextStyle(cxtMeta); var app = self.applyContextStyle(cxtMeta, cxtStyle, ele); if (!_p.newStyle) { self.updateTransitions(ele, app.diffProps); } self.updateStyleHints(ele); } // for elements _p.newStyle = false; return updatedEles; }; styfn.getPropertiesDiff = function (oldCxtKey, newCxtKey) { var self = this; var cache = self._private.propDiffs = self._private.propDiffs || {}; var dualCxtKey = oldCxtKey + '-' + newCxtKey; var cachedVal = cache[dualCxtKey]; if (cachedVal) { return cachedVal; } var diffProps = []; var addedProp = {}; for (var i = 0; i < self.length; i++) { var cxt = self[i]; var oldHasCxt = oldCxtKey[i] === 't'; var newHasCxt = newCxtKey[i] === 't'; var cxtHasDiffed = oldHasCxt !== newHasCxt; var cxtHasMappedProps = cxt.mappedProperties.length > 0; if (cxtHasDiffed || cxtHasMappedProps) { var props = void 0; if (cxtHasDiffed && cxtHasMappedProps) { props = cxt.properties; // suffices b/c mappedProperties is a subset of properties } else if (cxtHasDiffed) { props = cxt.properties; // need to check them all } else if (cxtHasMappedProps) { props = cxt.mappedProperties; // only need to check mapped } for (var j = 0; j < props.length; j++) { var prop = props[j]; var name = prop.name; // if a later context overrides this property, then the fact that this context has switched/diffed doesn't matter // (semi expensive check since it makes this function O(n^2) on context length, but worth it since overall result // is cached) var laterCxtOverrides = false; for (var k = i + 1; k < self.length; k++) { var laterCxt = self[k]; var hasLaterCxt = newCxtKey[k] === 't'; if (!hasLaterCxt) { continue; } // can't override unless the context is active laterCxtOverrides = laterCxt.properties[prop.name] != null; if (laterCxtOverrides) { break; } // exit early as long as one later context overrides } if (!addedProp[name] && !laterCxtOverrides) { addedProp[name] = true; diffProps.push(name); } } // for props } // if } // for contexts cache[dualCxtKey] = diffProps; return diffProps; }; styfn.getContextMeta = function (ele) { var self = this; var cxtKey = ''; var diffProps = void 0; var prevKey = ele._private.styleCxtKey || ''; if (self._private.newStyle) { prevKey = ''; // since we need to apply all style if a fresh stylesheet } // get the cxt key for (var i = 0; i < self.length; i++) { var context = self[i]; var contextSelectorMatches = context.selector && context.selector.matches(ele); // NB: context.selector may be null for 'core' if (contextSelectorMatches) { cxtKey += 't'; } else { cxtKey += 'f'; } } // for context diffProps = self.getPropertiesDiff(prevKey, cxtKey); ele._private.styleCxtKey = cxtKey; return { key: cxtKey, diffPropNames: diffProps, empty: diffProps.length === 0 }; }; // gets a computed ele style object based on matched contexts styfn.getContextStyle = function (cxtMeta) { var cxtKey = cxtMeta.key; var self = this; var cxtStyles = this._private.contextStyles = this._private.contextStyles || {}; // if already computed style, returned cached copy if (cxtStyles[cxtKey]) { return cxtStyles[cxtKey]; } var style = { _private: { key: cxtKey } }; for (var i = 0; i < self.length; i++) { var cxt = self[i]; var hasCxt = cxtKey[i] === 't'; if (!hasCxt) { continue; } for (var j = 0; j < cxt.properties.length; j++) { var prop = cxt.properties[j]; style[prop.name] = prop; } } cxtStyles[cxtKey] = style; return style; }; styfn.applyContextStyle = function (cxtMeta, cxtStyle, ele) { var self = this; var diffProps = cxtMeta.diffPropNames; var retDiffProps = {}; for (var i = 0; i < diffProps.length; i++) { var diffPropName = diffProps[i]; var cxtProp = cxtStyle[diffPropName]; var eleProp = ele.pstyle(diffPropName); if (!cxtProp) { // no context prop means delete if (!eleProp) { continue; // no existing prop means nothing needs to be removed // nb affects initial application on mapped values like control-point-distances } else if (eleProp.bypass) { cxtProp = { name: diffPropName, deleteBypassed: true }; } else { cxtProp = { name: diffPropName, delete: true }; } } // save cycles when the context prop doesn't need to be applied if (eleProp === cxtProp) { continue; } var retDiffProp = retDiffProps[diffPropName] = { prev: eleProp }; self.applyParsedProperty(ele, cxtProp); retDiffProp.next = ele.pstyle(diffPropName); if (retDiffProp.next && retDiffProp.next.bypass) { retDiffProp.next = retDiffProp.next.bypassed; } } return { diffProps: retDiffProps }; }; styfn.updateStyleHints = function (ele) { var _p = ele._private; var self = this; if (ele.removed()) { return; } // set whether has pie or not; for greater efficiency var hasPie = false; if (_p.group === 'nodes') { for (var i = 1; i <= self.pieBackgroundN; i++) { // 1..N var _size = ele.pstyle('pie-' + i + '-background-size').value; if (_size > 0) { hasPie = true; break; } } } _p.hasPie = hasPie; var transform = ele.pstyle('text-transform').strValue; var content = ele.pstyle('label').strValue; var srcContent = ele.pstyle('source-label').strValue; var tgtContent = ele.pstyle('target-label').strValue; var fStyle = ele.pstyle('font-style').strValue; var size = ele.pstyle('font-size').pfValue + 'px'; var family = ele.pstyle('font-family').strValue; // let letiant = style['font-letiant'].strValue; var weight = ele.pstyle('font-weight').strValue; var valign = ele.pstyle('text-valign').strValue; var halign = ele.pstyle('text-valign').strValue; var oWidth = ele.pstyle('text-outline-width').pfValue; var wrap = ele.pstyle('text-wrap').strValue; var wrapW = ele.pstyle('text-max-width').pfValue; var labelStyleKey = fStyle + '$' + size + '$' + family + '$' + weight + '$' + transform + '$' + valign + '$' + halign + '$' + oWidth + '$' + wrap + '$' + wrapW; _p.labelStyleKey = labelStyleKey; _p.sourceLabelKey = labelStyleKey + '$' + srcContent; _p.targetLabelKey = labelStyleKey + '$' + tgtContent; _p.labelKey = labelStyleKey + '$' + content; _p.fontKey = fStyle + '$' + weight + '$' + size + '$' + family; _p.styleKey = Date.now(); }; // apply a property to the style (for internal use) // returns whether application was successful // // now, this function flattens the property, and here's how: // // for parsedProp:{ bypass: true, deleteBypass: true } // no property is generated, instead the bypass property in the // element's style is replaced by what's pointed to by the `bypassed` // field in the bypass property (i.e. restoring the property the // bypass was overriding) // // for parsedProp:{ mapped: truthy } // the generated flattenedProp:{ mapping: prop } // // for parsedProp:{ bypass: true } // the generated flattenedProp:{ bypassed: parsedProp } styfn.applyParsedProperty = function (ele, parsedProp) { var self = this; var prop = parsedProp; var style = ele._private.style; var fieldVal = void 0, flatProp = void 0; var types = self.types; var type = self.properties[prop.name].type; var propIsBypass = prop.bypass; var origProp = style[prop.name]; var origPropIsBypass = origProp && origProp.bypass; var _p = ele._private; var flatPropMapping = 'mapping'; var checkZOrder = function checkZOrder() { self.checkZOrderTrigger(ele, prop.name, origProp ? origProp.value : null, prop.value); }; // edges connected to compound nodes can not be haystacks if (parsedProp.name === 'curve-style' && parsedProp.value === 'haystack' && ele.isEdge() && (ele.isLoop() || ele.source().isParent() || ele.target().isParent())) { prop = parsedProp = this.parse(parsedProp.name, 'bezier', propIsBypass); } if (prop.delete) { // delete the property and use the default value on falsey value style[prop.name] = undefined; checkZOrder(); return true; } if (prop.deleteBypassed) { // delete the property that the if (!origProp) { checkZOrder(); return true; // can't delete if no prop } else if (origProp.bypass) { // delete bypassed origProp.bypassed = undefined; checkZOrder(); return true; } else { return false; // we're unsuccessful deleting the bypassed } } // check if we need to delete the current bypass if (prop.deleteBypass) { // then this property is just here to indicate we need to delete if (!origProp) { checkZOrder(); return true; // property is already not defined } else if (origProp.bypass) { // then replace the bypass property with the original // because the bypassed property was already applied (and therefore parsed), we can just replace it (no reapplying necessary) style[prop.name] = origProp.bypassed; checkZOrder(); return true; } else { return false; // we're unsuccessful deleting the bypass } } var printMappingErr = function printMappingErr() { util.error('Do not assign mappings to elements without corresponding data (e.g. ele `' + ele.id() + '` for property `' + prop.name + '` with data field `' + prop.field + '`); try a `[' + prop.field + ']` selector to limit scope to elements with `' + prop.field + '` defined'); }; // put the property in the style objects switch (prop.mapped) {// flatten the property if mapped case types.mapData: { // flatten the field (e.g. data.foo.bar) var fields = prop.field.split('.'); var _fieldVal = _p.data; for (var i = 0; i < fields.length && _fieldVal; i++) { var field = fields[i]; _fieldVal = _fieldVal[field]; } var percent = void 0; if (!is.number(_fieldVal)) { // then keep the mapping but assume 0% for now percent = 0; } else { percent = (_fieldVal - prop.fieldMin) / (prop.fieldMax - prop.fieldMin); } // make sure to bound percent value if (percent < 0) { percent = 0; } else if (percent > 1) { percent = 1; } if (type.color) { var r1 = prop.valueMin[0]; var r2 = prop.valueMax[0]; var g1 = prop.valueMin[1]; var g2 = prop.valueMax[1]; var b1 = prop.valueMin[2]; var b2 = prop.valueMax[2]; var a1 = prop.valueMin[3] == null ? 1 : prop.valueMin[3]; var a2 = prop.valueMax[3] == null ? 1 : prop.valueMax[3]; var clr = [Math.round(r1 + (r2 - r1) * percent), Math.round(g1 + (g2 - g1) * percent), Math.round(b1 + (b2 - b1) * percent), Math.round(a1 + (a2 - a1) * percent)]; flatProp = { // colours are simple, so just create the flat property instead of expensive string parsing bypass: prop.bypass, // we're a bypass if the mapping property is a bypass name: prop.name, value: clr, strValue: 'rgb(' + clr[0] + ', ' + clr[1] + ', ' + clr[2] + ')' }; } else if (type.number) { var calcValue = prop.valueMin + (prop.valueMax - prop.valueMin) * percent; flatProp = this.parse(prop.name, calcValue, prop.bypass, flatPropMapping); } else { return false; // can only map to colours and numbers } if (!flatProp) { // if we can't flatten the property, then use the origProp so we still keep the mapping itself flatProp = this.parse(prop.name, origProp.strValue, prop.bypass, flatPropMapping); } if (!flatProp) { printMappingErr(); } flatProp.mapping = prop; // keep a reference to the mapping prop = flatProp; // the flattened (mapped) property is the one we want break; } // direct mapping case types.data: { // flatten the field (e.g. data.foo.bar) var _fields = prop.field.split('.'); var _fieldVal2 = _p.data; if (_fieldVal2) { for (var _i = 0; _i < _fields.length; _i++) { var _field = _fields[_i]; _fieldVal2 = _fieldVal2[_field]; } } flatProp = this.parse(prop.name, _fieldVal2, prop.bypass, flatPropMapping); if (!flatProp) { // if we can't flatten the property, then use the origProp so we still keep the mapping itself var flatPropVal = origProp ? origProp.strValue : ''; flatProp = this.parse(prop.name, flatPropVal, prop.bypass, flatPropMapping); } if (!flatProp) { printMappingErr(); } flatProp.mapping = prop; // keep a reference to the mapping prop = flatProp; // the flattened (mapped) property is the one we want break; } case types.fn: { var fn = prop.value; var fnRetVal = fn(ele); flatProp = this.parse(prop.name, fnRetVal, prop.bypass, flatPropMapping); flatProp.mapping = prop; // keep a reference to the mapping prop = flatProp; // the flattened (mapped) property is the one we want break; } case undefined: break; // just set the property default: return false; // not a valid mapping } // if the property is a bypass property, then link the resultant property to the original one if (propIsBypass) { if (origPropIsBypass) { // then this bypass overrides the existing one prop.bypassed = origProp.bypassed; // steal bypassed prop from old bypass } else { // then link the orig prop to the new bypass prop.bypassed = origProp; } style[prop.name] = prop; // and set } else { // prop is not bypass if (origPropIsBypass) { // then keep the orig prop (since it's a bypass) and link to the new prop origProp.bypassed = prop; } else { // then just replace the old prop with the new one style[prop.name] = prop; } } checkZOrder(); return true; }; styfn.cleanElements = function (eles, keepBypasses) { var self = this; var props = self.properties; for (var i = 0; i < eles.length; i++) { var ele = eles[i]; if (!keepBypasses) { ele._private.style = {}; } else { var style = ele._private.style; for (var j = 0; j < props.length; j++) { var prop = props[j]; var eleProp = style[prop.name]; if (eleProp) { if (eleProp.bypass) { eleProp.bypassed = null; } else { style[prop.name] = null; } } } } } }; // updates the visual style for all elements (useful for manual style modification after init) styfn.update = function () { var cy = this._private.cy; var eles = cy.mutableElements(); eles.updateStyle(); }; // just update the functional properties (i.e. mappings) in the elements' // styles (less expensive than recalculation) styfn.updateMappers = function (eles) { var self = this; var cy = this._private.cy; var updatedEles = cy.collection(); for (var i = 0; i < eles.length; i++) { // for each ele var ele = eles[i]; var style = ele._private.style; var updatedEle = false; for (var j = 0; j < self.properties.length; j++) { // for each prop var prop = self.properties[j]; var propInStyle = style[prop.name]; if (propInStyle && propInStyle.mapping) { var mapping = propInStyle.mapping; this.applyParsedProperty(ele, mapping); // reapply the mapping property updatedEle = true; } } if (updatedEle) { this.updateStyleHints(ele); updatedEles.merge(ele); } } return updatedEles; }; // diffProps : { name => { prev, next } } styfn.updateTransitions = function (ele, diffProps, isBypass) { var self = this; var _p = ele._private; var props = ele.pstyle('transition-property').value; var duration = ele.pstyle('transition-duration').pfValue; var delay = ele.pstyle('transition-delay').pfValue; if (props.length > 0 && duration > 0) { var style = {}; // build up the style to animate towards var anyPrev = false; for (var i = 0; i < props.length; i++) { var prop = props[i]; var styProp = ele.pstyle(prop); var diffProp = diffProps[prop]; if (!diffProp) { continue; } var prevProp = diffProp.prev; var fromProp = prevProp; var toProp = diffProp.next != null ? diffProp.next : styProp; var diff = false; var initVal = void 0; var initDt = 0.000001; // delta time % value for initVal (allows animating out of init zero opacity) if (!fromProp) { continue; } // consider px values if (is.number(fromProp.pfValue) && is.number(toProp.pfValue)) { diff = toProp.pfValue - fromProp.pfValue; // nonzero is truthy initVal = fromProp.pfValue + initDt * diff; // consider numerical values } else if (is.number(fromProp.value) && is.number(toProp.value)) { diff = toProp.value - fromProp.value; // nonzero is truthy initVal = fromProp.value + initDt * diff; // consider colour values } else if (is.array(fromProp.value) && is.array(toProp.value)) { diff = fromProp.value[0] !== toProp.value[0] || fromProp.value[1] !== toProp.value[1] || fromProp.value[2] !== toProp.value[2]; initVal = fromProp.strValue; } // the previous value is good for an animation only if it's different if (diff) { style[prop] = toProp.strValue; // to val this.applyBypass(ele, prop, initVal); // from val anyPrev = true; } } // end if props allow ani // can't transition if there's nothing previous to transition from if (!anyPrev) { return; } _p.transitioning = true; new Promise(function (resolve) { if (delay > 0) { ele.delayAnimation(delay).play().promise().then(resolve); } else { resolve(); } }).then(function () { return ele.animation({ style: style, duration: duration, easing: ele.pstyle('transition-timing-function').value, queue: false }).play().promise(); }).then(function () { // if( !isBypass ){ self.removeBypasses(ele, props); ele.emitAndNotify('style'); // } _p.transitioning = false; }); } else if (_p.transitioning) { this.removeBypasses(ele, props); ele.emitAndNotify('style'); _p.transitioning = false; } }; styfn.checkZOrderTrigger = function (ele, name, fromValue, toValue) { var prop = this.properties[name]; if (prop.triggersZOrder != null && (fromValue == null || prop.triggersZOrder(fromValue, toValue))) { this._private.cy.notify({ type: 'zorder', eles: ele }); } }; module.exports = styfn; /***/ }), /* 87 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var util = __webpack_require__(1); var styfn = {}; // bypasses are applied to an existing style on an element, and just tacked on temporarily // returns true iff application was successful for at least 1 specified property styfn.applyBypass = function (eles, name, value, updateTransitions) { var self = this; var props = []; var isBypass = true; // put all the properties (can specify one or many) in an array after parsing them if (name === '*' || name === '**') { // apply to all property names if (value !== undefined) { for (var i = 0; i < self.properties.length; i++) { var prop = self.properties[i]; var _name = prop.name; var parsedProp = this.parse(_name, value, true); if (parsedProp) { props.push(parsedProp); } } } } else if (is.string(name)) { // then parse the single property var _parsedProp = this.parse(name, value, true); if (_parsedProp) { props.push(_parsedProp); } } else if (is.plainObject(name)) { // then parse each property var specifiedProps = name; updateTransitions = value; var names = Object.keys(specifiedProps); for (var _i = 0; _i < names.length; _i++) { var _name2 = names[_i]; var _prop = self.properties[_name2]; var _value = specifiedProps[_name2]; if (_value === undefined) { // try camel case name too _value = specifiedProps[util.dash2camel(_name2)]; } if (_value !== undefined) { var _parsedProp2 = this.parse(_name2, _value, true); if (_parsedProp2) { props.push(_parsedProp2); } } } } else { // can't do anything without well defined properties return false; } // we've failed if there are no valid properties if (props.length === 0) { return false; } // now, apply the bypass properties on the elements var ret = false; // return true if at least one succesful bypass applied for (var _i2 = 0; _i2 < eles.length; _i2++) { // for each ele var ele = eles[_i2]; var diffProps = {}; var diffProp = void 0; for (var j = 0; j < props.length; j++) { // for each prop var _prop2 = props[j]; if (updateTransitions) { var prevProp = ele.pstyle(_prop2.name); diffProp = diffProps[_prop2.name] = { prev: prevProp }; } ret = this.applyParsedProperty(ele, _prop2) || ret; if (updateTransitions) { diffProp.next = ele.pstyle(_prop2.name); } } // for props if (ret) { this.updateStyleHints(ele); } if (updateTransitions) { this.updateTransitions(ele, diffProps, isBypass); } } // for eles return ret; }; // only useful in specific cases like animation styfn.overrideBypass = function (eles, name, value) { name = util.camel2dash(name); for (var i = 0; i < eles.length; i++) { var ele = eles[i]; var prop = ele._private.style[name]; var type = this.properties[name].type; var isColor = type.color; var isMulti = type.mutiple; if (!prop || !prop.bypass) { // need a bypass if one doesn't exist this.applyBypass(ele, name, value); continue; } var oldValue = prop.pfValue != null ? prop.pfValue : prop.value; prop.value = value; if (prop.pfValue != null) { prop.pfValue = value; } if (isColor) { prop.strValue = 'rgb(' + value.join(',') + ')'; } else if (isMulti) { prop.strValue = value.join(' '); } else { prop.strValue = '' + value; } this.checkZOrderTrigger(ele, name, oldValue, value); } }; styfn.removeAllBypasses = function (eles, updateTransitions) { return this.removeBypasses(eles, this.propertyNames, updateTransitions); }; styfn.removeBypasses = function (eles, props, updateTransitions) { var isBypass = true; for (var j = 0; j < eles.length; j++) { var ele = eles[j]; var diffProps = {}; for (var i = 0; i < props.length; i++) { var name = props[i]; var prop = this.properties[name]; var prevProp = ele.pstyle(prop.name); if (!prevProp || !prevProp.bypass) { // if a bypass doesn't exist for the prop, nothing needs to be removed continue; } var value = ''; // empty => remove bypass var parsedProp = this.parse(name, value, true); var diffProp = diffProps[prop.name] = { prev: prevProp }; this.applyParsedProperty(ele, parsedProp); diffProp.next = ele.pstyle(prop.name); } // for props this.updateStyleHints(ele); if (updateTransitions) { this.updateTransitions(ele, diffProps, isBypass); } } // for eles }; module.exports = styfn; /***/ }), /* 88 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var window = __webpack_require__(3); var styfn = {}; // gets what an em size corresponds to in pixels relative to a dom element styfn.getEmSizeInPixels = function () { var px = this.containerCss('font-size'); if (px != null) { return parseFloat(px); } else { return 1; // for headless } }; // gets css property from the core container styfn.containerCss = function (propName) { var cy = this._private.cy; var domElement = cy.container(); if (window && domElement && window.getComputedStyle) { return window.getComputedStyle(domElement).getPropertyValue(propName); } }; module.exports = styfn; /***/ }), /* 89 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var is = __webpack_require__(0); var styfn = {}; // gets the rendered style for an element styfn.getRenderedStyle = function (ele, prop) { if (prop) { return this.getStylePropertyValue(ele, prop, true); } else { return this.getRawStyle(ele, true); } }; // gets the raw style for an element styfn.getRawStyle = function (ele, isRenderedVal) { var self = this; ele = ele[0]; // insure it's an element if (ele) { var rstyle = {}; for (var i = 0; i < self.properties.length; i++) { var prop = self.properties[i]; var val = self.getStylePropertyValue(ele, prop.name, isRenderedVal); if (val != null) { rstyle[prop.name] = val; rstyle[util.dash2camel(prop.name)] = val; } } return rstyle; } }; styfn.getIndexedStyle = function (ele, property, subproperty, index) { var pstyle = ele.pstyle(property)[subproperty][index]; return pstyle != null ? pstyle : ele.cy().style().getDefaultProperty(property)[subproperty][0]; }; styfn.getStylePropertyValue = function (ele, propName, isRenderedVal) { var self = this; ele = ele[0]; // insure it's an element if (ele) { var prop = self.properties[propName]; if (prop.alias) { prop = prop.pointsTo; } var type = prop.type; var styleProp = ele.pstyle(prop.name); var zoom = ele.cy().zoom(); if (styleProp) { var units = styleProp.units ? type.implicitUnits || 'px' : null; var val = units ? [].concat(styleProp.pfValue).map(function (pfValue) { return pfValue * (isRenderedVal ? zoom : 1) + units; }).join(' ') : styleProp.strValue; return val; } } }; styfn.getAnimationStartStyle = function (ele, aniProps) { var rstyle = {}; for (var i = 0; i < aniProps.length; i++) { var aniProp = aniProps[i]; var name = aniProp.name; var styleProp = ele.pstyle(name); if (styleProp !== undefined) { // then make a prop of it if (is.plainObject(styleProp)) { styleProp = this.parse(name, styleProp.strValue); } else { styleProp = this.parse(name, styleProp); } } if (styleProp) { rstyle[name] = styleProp; } } return rstyle; }; styfn.getPropsList = function (propsObj) { var self = this; var rstyle = []; var style = propsObj; var props = self.properties; if (style) { var names = Object.keys(style); for (var i = 0; i < names.length; i++) { var name = names[i]; var val = style[name]; var prop = props[name] || props[util.camel2dash(name)]; var styleProp = this.parse(prop.name, val); if (styleProp) { rstyle.push(styleProp); } } } return rstyle; }; module.exports = styfn; /***/ }), /* 90 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var styfn = {}; styfn.appendFromJson = function (json) { var style = this; for (var i = 0; i < json.length; i++) { var context = json[i]; var selector = context.selector; var props = context.style || context.css; var names = Object.keys(props); style.selector(selector); // apply selector for (var j = 0; j < names.length; j++) { var name = names[j]; var value = props[name]; style.css(name, value); // apply property } } return style; }; // accessible cy.style() function styfn.fromJson = function (json) { var style = this; style.resetToDefault(); style.appendFromJson(json); return style; }; // get json from cy.style() api styfn.json = function () { var json = []; for (var i = this.defaultLength; i < this.length; i++) { var cxt = this[i]; var selector = cxt.selector; var props = cxt.properties; var css = {}; for (var j = 0; j < props.length; j++) { var prop = props[j]; css[prop.name] = prop.strValue; } json.push({ selector: !selector ? 'core' : selector.toString(), style: css }); } return json; }; module.exports = styfn; /***/ }), /* 91 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var Selector = __webpack_require__(6); var styfn = {}; styfn.appendFromString = function (string) { var self = this; var style = this; var remaining = '' + string; var selAndBlockStr = void 0; var blockRem = void 0; var propAndValStr = void 0; // remove comments from the style string remaining = remaining.replace(/[/][*](\s|.)+?[*][/]/g, ''); function removeSelAndBlockFromRemaining() { // remove the parsed selector and block from the remaining text to parse if (remaining.length > selAndBlockStr.length) { remaining = remaining.substr(selAndBlockStr.length); } else { remaining = ''; } } function removePropAndValFromRem() { // remove the parsed property and value from the remaining block text to parse if (blockRem.length > propAndValStr.length) { blockRem = blockRem.substr(propAndValStr.length); } else { blockRem = ''; } } while (true) { var nothingLeftToParse = remaining.match(/^\s*$/); if (nothingLeftToParse) { break; } var selAndBlock = remaining.match(/^\s*((?:.|\s)+?)\s*\{((?:.|\s)+?)\}/); if (!selAndBlock) { util.error('Halting stylesheet parsing: String stylesheet contains more to parse but no selector and block found in: ' + remaining); break; } selAndBlockStr = selAndBlock[0]; // parse the selector var selectorStr = selAndBlock[1]; if (selectorStr !== 'core') { var selector = new Selector(selectorStr); if (selector._private.invalid) { util.error('Skipping parsing of block: Invalid selector found in string stylesheet: ' + selectorStr); // skip this selector and block removeSelAndBlockFromRemaining(); continue; } } // parse the block of properties and values var blockStr = selAndBlock[2]; var invalidBlock = false; blockRem = blockStr; var props = []; while (true) { var _nothingLeftToParse = blockRem.match(/^\s*$/); if (_nothingLeftToParse) { break; } var propAndVal = blockRem.match(/^\s*(.+?)\s*:\s*(.+?)\s*;/); if (!propAndVal) { util.error('Skipping parsing of block: Invalid formatting of style property and value definitions found in:' + blockStr); invalidBlock = true; break; } propAndValStr = propAndVal[0]; var propStr = propAndVal[1]; var valStr = propAndVal[2]; var prop = self.properties[propStr]; if (!prop) { util.error('Skipping property: Invalid property name in: ' + propAndValStr); // skip this property in the block removePropAndValFromRem(); continue; } var parsedProp = style.parse(propStr, valStr); if (!parsedProp) { util.error('Skipping property: Invalid property definition in: ' + propAndValStr); // skip this property in the block removePropAndValFromRem(); continue; } props.push({ name: propStr, val: valStr }); removePropAndValFromRem(); } if (invalidBlock) { removeSelAndBlockFromRemaining(); break; } // put the parsed block in the style style.selector(selectorStr); for (var i = 0; i < props.length; i++) { var _prop = props[i]; style.css(_prop.name, _prop.val); } removeSelAndBlockFromRemaining(); } return style; }; styfn.fromString = function (string) { var style = this; style.resetToDefault(); style.appendFromString(string); return style; }; module.exports = styfn; /***/ }), /* 92 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var is = __webpack_require__(0); var styfn = {}; (function () { var number = util.regex.number; var rgba = util.regex.rgbaNoBackRefs; var hsla = util.regex.hslaNoBackRefs; var hex3 = util.regex.hex3; var hex6 = util.regex.hex6; var data = function data(prefix) { return '^' + prefix + '\\s*\\(\\s*([\\w\\.]+)\\s*\\)$'; }; var mapData = function mapData(prefix) { var mapArg = number + '|\\w+|' + rgba + '|' + hsla + '|' + hex3 + '|' + hex6; return '^' + prefix + '\\s*\\(([\\w\\.]+)\\s*\\,\\s*(' + number + ')\\s*\\,\\s*(' + number + ')\\s*,\\s*(' + mapArg + ')\\s*\\,\\s*(' + mapArg + ')\\)$'; }; var urlRegexes = ['^url\\s*\\(\\s*[\'"]?(.+?)[\'"]?\\s*\\)$', '^(none)$', '^(.+)$']; // each visual style property has a type and needs to be validated according to it styfn.types = { time: { number: true, min: 0, units: 's|ms', implicitUnits: 'ms' }, percent: { number: true, min: 0, max: 100, units: '%', implicitUnits: '%' }, zeroOneNumber: { number: true, min: 0, max: 1, unitless: true }, zeroOneNumbers: { number: true, min: 0, max: 1, unitless: true, multiple: true }, nOneOneNumber: { number: true, min: -1, max: 1, unitless: true }, nonNegativeInt: { number: true, min: 0, integer: true, unitless: true }, position: { enums: ['parent', 'origin'] }, nodeSize: { number: true, min: 0, enums: ['label'] }, number: { number: true, unitless: true }, numbers: { number: true, unitless: true, multiple: true }, positiveNumber: { number: true, unitless: true, min: 0, strictMin: true }, size: { number: true, min: 0 }, bidirectionalSize: { number: true }, // allows negative bidirectionalSizes: { number: true, multiple: true }, // allows negative sizeMaybePercent: { number: true, min: 0, allowPercent: true }, paddingRelativeTo: { enums: ['width', 'height', 'average', 'min', 'max'] }, bgWH: { number: true, min: 0, allowPercent: true, enums: ['auto'], multiple: true }, bgPos: { number: true, allowPercent: true, multiple: true }, bgRelativeTo: { enums: ['inner', 'include-padding'], multiple: true }, bgRepeat: { enums: ['repeat', 'repeat-x', 'repeat-y', 'no-repeat'], multiple: true }, bgFit: { enums: ['none', 'contain', 'cover'], multiple: true }, bgCrossOrigin: { enums: ['anonymous', 'use-credentials'], multiple: true }, bgClip: { enums: ['none', 'node'] }, color: { color: true }, bool: { enums: ['yes', 'no'] }, lineStyle: { enums: ['solid', 'dotted', 'dashed'] }, borderStyle: { enums: ['solid', 'dotted', 'dashed', 'double'] }, curveStyle: { enums: ['bezier', 'unbundled-bezier', 'haystack', 'segments'] }, fontFamily: { regex: '^([\\w- \\"]+(?:\\s*,\\s*[\\w- \\"]+)*)$' }, fontletiant: { enums: ['small-caps', 'normal'] }, fontStyle: { enums: ['italic', 'normal', 'oblique'] }, fontWeight: { enums: ['normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '800', '900', 100, 200, 300, 400, 500, 600, 700, 800, 900] }, textDecoration: { enums: ['none', 'underline', 'overline', 'line-through'] }, textTransform: { enums: ['none', 'uppercase', 'lowercase'] }, textWrap: { enums: ['none', 'wrap', 'ellipsis'] }, textBackgroundShape: { enums: ['rectangle', 'roundrectangle'] }, nodeShape: { enums: ['rectangle', 'roundrectangle', 'cutrectangle', 'bottomroundrectangle', 'barrel', 'ellipse', 'triangle', 'square', 'pentagon', 'hexagon', 'concavehexagon', 'heptagon', 'octagon', 'tag', 'star', 'diamond', 'vee', 'rhomboid', 'polygon'] }, compoundIncludeLabels: { enums: ['include', 'exclude'] }, arrowShape: { enums: ['tee', 'triangle', 'triangle-tee', 'triangle-cross', 'triangle-backcurve', 'half-triangle-overshot', 'vee', 'square', 'circle', 'diamond', 'none'] }, arrowFill: { enums: ['filled', 'hollow'] }, display: { enums: ['element', 'none'] }, visibility: { enums: ['hidden', 'visible'] }, zCompoundDepth: { enums: ['bottom', 'orphan', 'auto', 'top'] }, zIndexCompare: { enums: ['auto', 'manual'] }, valign: { enums: ['top', 'center', 'bottom'] }, halign: { enums: ['left', 'center', 'right'] }, text: { string: true }, data: { mapping: true, regex: data('data') }, layoutData: { mapping: true, regex: data('layoutData') }, scratch: { mapping: true, regex: data('scratch') }, mapData: { mapping: true, regex: mapData('mapData') }, mapLayoutData: { mapping: true, regex: mapData('mapLayoutData') }, mapScratch: { mapping: true, regex: mapData('mapScratch') }, fn: { mapping: true, fn: true }, url: { regexes: urlRegexes, singleRegexMatchValue: true }, urls: { regexes: urlRegexes, singleRegexMatchValue: true, multiple: true }, propList: { propList: true }, angle: { number: true, units: 'deg|rad', implicitUnits: 'rad' }, textRotation: { number: true, units: 'deg|rad', implicitUnits: 'rad', enums: ['none', 'autorotate'] }, polygonPointList: { number: true, multiple: true, evenMultiple: true, min: -1, max: 1, unitless: true }, edgeDistances: { enums: ['intersection', 'node-position'] }, edgeEndpoint: { number: true, multiple: true, units: '%|px|em|deg|rad', implicitUnits: 'px', enums: ['inside-to-node', 'outside-to-node', 'outside-to-line'], singleEnum: true, validate: function validate(valArr, unitsArr) { switch (valArr.length) { case 2: // can be % or px only return unitsArr[0] !== 'deg' && unitsArr[0] !== 'rad' && unitsArr[1] !== 'deg' && unitsArr[1] !== 'rad'; case 1: // can be enum, deg, or rad only return is.string(valArr[0]) || unitsArr[0] === 'deg' || unitsArr[0] === 'rad'; default: return false; } } }, easing: { regexes: ['^(spring)\\s*\\(\\s*(' + number + ')\\s*,\\s*(' + number + ')\\s*\\)$', '^(cubic-bezier)\\s*\\(\\s*(' + number + ')\\s*,\\s*(' + number + ')\\s*,\\s*(' + number + ')\\s*,\\s*(' + number + ')\\s*\\)$'], enums: ['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'ease-in-sine', 'ease-out-sine', 'ease-in-out-sine', 'ease-in-quad', 'ease-out-quad', 'ease-in-out-quad', 'ease-in-cubic', 'ease-out-cubic', 'ease-in-out-cubic', 'ease-in-quart', 'ease-out-quart', 'ease-in-out-quart', 'ease-in-quint', 'ease-out-quint', 'ease-in-out-quint', 'ease-in-expo', 'ease-out-expo', 'ease-in-out-expo', 'ease-in-circ', 'ease-out-circ', 'ease-in-out-circ'] } }; var zOrderDiff = { zeroNonZero: function zeroNonZero(val1, val2) { if (val1 === 0 && val2 !== 0) { return true; } else if (val1 !== 0 && val2 === 0) { return true; } else { return false; } }, anyDiff: function anyDiff(val1, val2) { return val1 !== val2; } }; var zd = zOrderDiff; // define visual style properties var t = styfn.types; var props = styfn.properties = [ // main label { name: 'label', type: t.text }, { name: 'text-rotation', type: t.textRotation }, { name: 'text-margin-x', type: t.bidirectionalSize }, { name: 'text-margin-y', type: t.bidirectionalSize }, // source label { name: 'source-label', type: t.text }, { name: 'source-text-rotation', type: t.textRotation }, { name: 'source-text-margin-x', type: t.bidirectionalSize }, { name: 'source-text-margin-y', type: t.bidirectionalSize }, { name: 'source-text-offset', type: t.size }, // target label { name: 'target-label', type: t.text }, { name: 'target-text-rotation', type: t.textRotation }, { name: 'target-text-margin-x', type: t.bidirectionalSize }, { name: 'target-text-margin-y', type: t.bidirectionalSize }, { name: 'target-text-offset', type: t.size }, // common label style { name: 'text-valign', type: t.valign }, { name: 'text-halign', type: t.halign }, { name: 'color', type: t.color }, { name: 'text-outline-color', type: t.color }, { name: 'text-outline-width', type: t.size }, { name: 'text-outline-opacity', type: t.zeroOneNumber }, { name: 'text-opacity', type: t.zeroOneNumber }, { name: 'text-background-color', type: t.color }, { name: 'text-background-opacity', type: t.zeroOneNumber }, { name: 'text-background-padding', type: t.size }, { name: 'text-border-opacity', type: t.zeroOneNumber }, { name: 'text-border-color', type: t.color }, { name: 'text-border-width', type: t.size }, { name: 'text-border-style', type: t.borderStyle }, { name: 'text-background-shape', type: t.textBackgroundShape }, // { name: 'text-decoration', type: t.textDecoration }, // not supported in canvas { name: 'text-transform', type: t.textTransform }, { name: 'text-wrap', type: t.textWrap }, { name: 'text-max-width', type: t.size }, { name: 'text-events', type: t.bool }, { name: 'font-family', type: t.fontFamily }, { name: 'font-style', type: t.fontStyle }, // { name: 'font-letiant', type: t.fontletiant }, // not useful { name: 'font-weight', type: t.fontWeight }, { name: 'font-size', type: t.size }, { name: 'min-zoomed-font-size', type: t.size }, // behaviour { name: 'events', type: t.bool }, // visibility { name: 'display', type: t.display, triggersZOrder: zd.anyDiff }, { name: 'visibility', type: t.visibility, triggersZOrder: zd.anyDiff }, { name: 'opacity', type: t.zeroOneNumber, triggersZOrder: zd.zeroNonZero }, { name: 'z-compound-depth', type: t.zCompoundDepth, triggersZOrder: zd.anyDiff }, { name: 'z-index-compare', type: t.zIndexCompare, triggersZOrder: zd.anyDiff }, { name: 'z-index', type: t.nonNegativeInt, triggersZOrder: zd.anyDiff }, // overlays { name: 'overlay-padding', type: t.size }, { name: 'overlay-color', type: t.color }, { name: 'overlay-opacity', type: t.zeroOneNumber }, // transition anis { name: 'transition-property', type: t.propList }, { name: 'transition-duration', type: t.time }, { name: 'transition-delay', type: t.time }, { name: 'transition-timing-function', type: t.easing }, // node body { name: 'height', type: t.nodeSize }, { name: 'width', type: t.nodeSize }, { name: 'shape', type: t.nodeShape }, { name: 'shape-polygon-points', type: t.polygonPointList }, { name: 'background-color', type: t.color }, { name: 'background-opacity', type: t.zeroOneNumber }, { name: 'background-blacken', type: t.nOneOneNumber }, { name: 'padding', type: t.sizeMaybePercent }, { name: 'padding-relative-to', type: t.paddingRelativeTo }, // node border { name: 'border-color', type: t.color }, { name: 'border-opacity', type: t.zeroOneNumber }, { name: 'border-width', type: t.size }, { name: 'border-style', type: t.borderStyle }, // node background images { name: 'background-image', type: t.urls }, { name: 'background-image-crossorigin', type: t.bgCrossOrigin }, { name: 'background-image-opacity', type: t.zeroOneNumbers }, { name: 'background-position-x', type: t.bgPos }, { name: 'background-position-y', type: t.bgPos }, { name: 'background-width-relative-to', type: t.bgRelativeTo }, { name: 'background-height-relative-to', type: t.bgRelativeTo }, { name: 'background-repeat', type: t.bgRepeat }, { name: 'background-fit', type: t.bgFit }, { name: 'background-clip', type: t.bgClip }, { name: 'background-width', type: t.bgWH }, { name: 'background-height', type: t.bgWH }, // compound props { name: 'position', type: t.position }, { name: 'compound-sizing-wrt-labels', type: t.compoundIncludeLabels }, { name: 'min-width', type: t.size }, { name: 'min-width-bias-left', type: t.sizeMaybePercent }, { name: 'min-width-bias-right', type: t.sizeMaybePercent }, { name: 'min-height', type: t.size }, { name: 'min-height-bias-top', type: t.sizeMaybePercent }, { name: 'min-height-bias-bottom', type: t.sizeMaybePercent }, // edge line { name: 'line-style', type: t.lineStyle }, { name: 'line-color', type: t.color }, { name: 'curve-style', type: t.curveStyle }, { name: 'haystack-radius', type: t.zeroOneNumber }, { name: 'source-endpoint', type: t.edgeEndpoint }, { name: 'target-endpoint', type: t.edgeEndpoint }, { name: 'control-point-step-size', type: t.size }, { name: 'control-point-distances', type: t.bidirectionalSizes }, { name: 'control-point-weights', type: t.numbers }, { name: 'segment-distances', type: t.bidirectionalSizes }, { name: 'segment-weights', type: t.numbers }, { name: 'edge-distances', type: t.edgeDistances }, { name: 'arrow-scale', type: t.positiveNumber }, { name: 'loop-direction', type: t.angle }, { name: 'loop-sweep', type: t.angle }, { name: 'source-distance-from-node', type: t.size }, { name: 'target-distance-from-node', type: t.size }, // ghost properties { name: 'ghost', type: t.bool }, { name: 'ghost-offset-x', type: t.bidirectionalSize }, { name: 'ghost-offset-y', type: t.bidirectionalSize }, { name: 'ghost-opacity', type: t.zeroOneNumber }, // these are just for the core { name: 'selection-box-color', type: t.color }, { name: 'selection-box-opacity', type: t.zeroOneNumber }, { name: 'selection-box-border-color', type: t.color }, { name: 'selection-box-border-width', type: t.size }, { name: 'active-bg-color', type: t.color }, { name: 'active-bg-opacity', type: t.zeroOneNumber }, { name: 'active-bg-size', type: t.size }, { name: 'outside-texture-bg-color', type: t.color }, { name: 'outside-texture-bg-opacity', type: t.zeroOneNumber }]; // define aliases var aliases = styfn.aliases = [{ name: 'content', pointsTo: 'label' }, { name: 'control-point-distance', pointsTo: 'control-point-distances' }, { name: 'control-point-weight', pointsTo: 'control-point-weights' }, { name: 'edge-text-rotation', pointsTo: 'text-rotation' }, { name: 'padding-left', pointsTo: 'padding' }, { name: 'padding-right', pointsTo: 'padding' }, { name: 'padding-top', pointsTo: 'padding' }, { name: 'padding-bottom', pointsTo: 'padding' }]; // pie backgrounds for nodes styfn.pieBackgroundN = 16; // because the pie properties are numbered, give access to a constant N (for renderer use) props.push({ name: 'pie-size', type: t.sizeMaybePercent }); for (var i = 1; i <= styfn.pieBackgroundN; i++) { props.push({ name: 'pie-' + i + '-background-color', type: t.color }); props.push({ name: 'pie-' + i + '-background-size', type: t.percent }); props.push({ name: 'pie-' + i + '-background-opacity', type: t.zeroOneNumber }); } // edge arrows var arrowPrefixes = styfn.arrowPrefixes = ['source', 'mid-source', 'target', 'mid-target']; [{ name: 'arrow-shape', type: t.arrowShape }, { name: 'arrow-color', type: t.color }, { name: 'arrow-fill', type: t.arrowFill }].forEach(function (prop) { arrowPrefixes.forEach(function (prefix) { var name = prefix + '-' + prop.name; var type = prop.type; props.push({ name: name, type: type }); }); }, {}); // list of property names styfn.propertyNames = props.map(function (p) { return p.name; }); // allow access of properties by name ( e.g. style.properties.height ) for (var _i = 0; _i < props.length; _i++) { var prop = props[_i]; props[prop.name] = prop; // allow lookup by name } // map aliases for (var _i2 = 0; _i2 < aliases.length; _i2++) { var alias = aliases[_i2]; var pointsToProp = props[alias.pointsTo]; var aliasProp = { name: alias.name, alias: true, pointsTo: pointsToProp }; // add alias prop for parsing props.push(aliasProp); props[alias.name] = aliasProp; // allow lookup by name } })(); styfn.getDefaultProperty = function (name) { return this.getDefaultProperties()[name]; }; styfn.getDefaultProperties = util.memoize(function () { var rawProps = util.extend({ // common node/edge props 'events': 'yes', 'text-events': 'no', 'text-valign': 'top', 'text-halign': 'center', 'color': '#000', 'text-outline-color': '#000', 'text-outline-width': 0, 'text-outline-opacity': 1, 'text-opacity': 1, 'text-decoration': 'none', 'text-transform': 'none', 'text-wrap': 'none', 'text-max-width': 9999, 'text-background-color': '#000', 'text-background-opacity': 0, 'text-background-shape': 'rectangle', 'text-background-padding': 0, 'text-border-opacity': 0, 'text-border-width': 0, 'text-border-style': 'solid', 'text-border-color': '#000', 'font-family': 'Helvetica Neue, Helvetica, sans-serif', 'font-style': 'normal', // 'font-letiant': fontletiant, 'font-weight': 'normal', 'font-size': 16, 'min-zoomed-font-size': 0, 'text-rotation': 'none', 'source-text-rotation': 'none', 'target-text-rotation': 'none', 'visibility': 'visible', 'display': 'element', 'opacity': 1, 'z-compound-depth': 'auto', 'z-index-compare': 'auto', 'z-index': 0, 'label': '', 'text-margin-x': 0, 'text-margin-y': 0, 'source-label': '', 'source-text-offset': 0, 'source-text-margin-x': 0, 'source-text-margin-y': 0, 'target-label': '', 'target-text-offset': 0, 'target-text-margin-x': 0, 'target-text-margin-y': 0, 'overlay-opacity': 0, 'overlay-color': '#000', 'overlay-padding': 10, 'transition-property': 'none', 'transition-duration': 0, 'transition-delay': 0, 'transition-timing-function': 'linear', // node props 'background-blacken': 0, 'background-color': '#999', 'background-opacity': 1, 'background-image': 'none', 'background-image-crossorigin': 'anonymous', 'background-image-opacity': 1, 'background-position-x': '50%', 'background-position-y': '50%', 'background-width-relative-to': 'include-padding', 'background-height-relative-to': 'include-padding', 'background-repeat': 'no-repeat', 'background-fit': 'none', 'background-clip': 'node', 'background-width': 'auto', 'background-height': 'auto', 'border-color': '#000', 'border-opacity': 1, 'border-width': 0, 'border-style': 'solid', 'height': 30, 'width': 30, 'shape': 'ellipse', 'shape-polygon-points': '-1, -1, 1, -1, 1, 1, -1, 1', // ghost props 'ghost': 'no', 'ghost-offset-y': 0, 'ghost-offset-x': 0, 'ghost-opacity': 0, // compound props 'padding': 0, 'padding-relative-to': 'width', 'position': 'origin', 'compound-sizing-wrt-labels': 'include', 'min-width': 0, 'min-width-bias-left': 0, 'min-width-bias-right': 0, 'min-height': 0, 'min-height-bias-top': 0, 'min-height-bias-bottom': 0 }, { // node pie bg 'pie-size': '100%' }, [{ name: 'pie-{{i}}-background-color', value: 'black' }, { name: 'pie-{{i}}-background-size', value: '0%' }, { name: 'pie-{{i}}-background-opacity', value: 1 }].reduce(function (css, prop) { for (var i = 1; i <= styfn.pieBackgroundN; i++) { var name = prop.name.replace('{{i}}', i); var val = prop.value; css[name] = val; } return css; }, {}), { // edge props 'line-style': 'solid', 'line-color': '#999', 'control-point-step-size': 40, 'control-point-weights': 0.5, 'segment-weights': 0.5, 'segment-distances': 20, 'edge-distances': 'intersection', 'curve-style': 'bezier', 'haystack-radius': 0, 'arrow-scale': 1, 'loop-direction': '-45deg', 'loop-sweep': '-90deg', 'source-distance-from-node': 0, 'target-distance-from-node': 0, 'source-endpoint': 'outside-to-node', 'target-endpoint': 'outside-to-node' }, [{ name: 'arrow-shape', value: 'none' }, { name: 'arrow-color', value: '#999' }, { name: 'arrow-fill', value: 'filled' }].reduce(function (css, prop) { styfn.arrowPrefixes.forEach(function (prefix) { var name = prefix + '-' + prop.name; var val = prop.value; css[name] = val; }); return css; }, {})); var parsedProps = {}; for (var i = 0; i < this.properties.length; i++) { var prop = this.properties[i]; if (prop.pointsTo) { continue; } var name = prop.name; var val = rawProps[name]; var parsedProp = this.parse(name, val); parsedProps[name] = parsedProp; } return parsedProps; }); styfn.addDefaultStylesheet = function () { this.selector('$node > node') // compound (parent) node properties .css({ 'shape': 'rectangle', 'padding': 10, 'background-color': '#eee', 'border-color': '#ccc', 'border-width': 1 }).selector('edge') // just edge properties .css({ 'width': 3, 'curve-style': 'haystack' }).selector(':parent <-> node').css({ 'curve-style': 'bezier', 'source-endpoint': 'outside-to-line', 'target-endpoint': 'outside-to-line' }).selector(':selected').css({ 'background-color': '#0169D9', 'line-color': '#0169D9', 'source-arrow-color': '#0169D9', 'target-arrow-color': '#0169D9', 'mid-source-arrow-color': '#0169D9', 'mid-target-arrow-color': '#0169D9' }).selector('node:parent:selected').css({ 'background-color': '#CCE1F9', 'border-color': '#aec8e5' }).selector(':active').css({ 'overlay-color': 'black', 'overlay-padding': 10, 'overlay-opacity': 0.25 }).selector('core') // just core properties .css({ 'selection-box-color': '#ddd', 'selection-box-opacity': 0.65, 'selection-box-border-color': '#aaa', 'selection-box-border-width': 1, 'active-bg-color': 'black', 'active-bg-opacity': 0.15, 'active-bg-size': 30, 'outside-texture-bg-color': '#000', 'outside-texture-bg-opacity': 0.125 }); this.defaultLength = this.length; }; module.exports = styfn; /***/ }), /* 93 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var is = __webpack_require__(0); var math = __webpack_require__(2); var styfn = {}; // a caching layer for property parsing styfn.parse = function (name, value, propIsBypass, propIsFlat) { var self = this; // function values can't be cached in all cases, and there isn't much benefit of caching them anyway if (is.fn(value)) { return self.parseImplWarn(name, value, propIsBypass, propIsFlat); } var flatKey = propIsFlat === 'mapping' || propIsFlat === true || propIsFlat === false || propIsFlat == null ? 'dontcare' : propIsFlat; var argHash = [name, value, propIsBypass, flatKey].join('$'); var propCache = self.propCache = self.propCache || {}; var ret = void 0; if (!(ret = propCache[argHash])) { ret = propCache[argHash] = self.parseImplWarn(name, value, propIsBypass, propIsFlat); } // - bypasses can't be shared b/c the value can be changed by animations or otherwise overridden // - mappings can't be shared b/c mappings are per-element if (propIsBypass || propIsFlat === 'mapping') { // need a copy since props are mutated later in their lifecycles ret = util.copy(ret); if (ret) { ret.value = util.copy(ret.value); // because it could be an array, e.g. colour } } return ret; }; styfn.parseImplWarn = function (name, value, propIsBypass, propIsFlat) { var prop = this.parseImpl(name, value, propIsBypass, propIsFlat); if (!prop && value != null) { util.error('The style property `%s: %s` is invalid', name, value); } return prop; }; // parse a property; return null on invalid; return parsed property otherwise // fields : // - name : the name of the property // - value : the parsed, native-typed value of the property // - strValue : a string value that represents the property value in valid css // - bypass : true iff the property is a bypass property styfn.parseImpl = function (name, value, propIsBypass, propIsFlat) { var self = this; name = util.camel2dash(name); // make sure the property name is in dash form (e.g. 'property-name' not 'propertyName') var property = self.properties[name]; var passedValue = value; var types = self.types; if (!property) { return null; } // return null on property of unknown name if (value === undefined) { return null; } // can't assign undefined // the property may be an alias if (property.alias) { property = property.pointsTo; name = property.name; } var valueIsString = is.string(value); if (valueIsString) { // trim the value to make parsing easier value = value.trim(); } var type = property.type; if (!type) { return null; } // no type, no luck // check if bypass is null or empty string (i.e. indication to delete bypass property) if (propIsBypass && (value === '' || value === null)) { return { name: name, value: value, bypass: true, deleteBypass: true }; } // check if value is a function used as a mapper if (is.fn(value)) { return { name: name, value: value, strValue: 'fn', mapped: types.fn, bypass: propIsBypass }; } // check if value is mapped var data = void 0, mapData = void 0; if (!valueIsString || propIsFlat) { // then don't bother to do the expensive regex checks } else if (data = new RegExp(types.data.regex).exec(value)) { if (propIsBypass) { return false; } // mappers not allowed in bypass var mapped = types.data; return { name: name, value: data, strValue: '' + value, mapped: mapped, field: data[1], bypass: propIsBypass }; } else if (mapData = new RegExp(types.mapData.regex).exec(value)) { if (propIsBypass) { return false; } // mappers not allowed in bypass if (type.multiple) { return false; } // impossible to map to num var _mapped = types.mapData; // we can map only if the type is a colour or a number if (!(type.color || type.number)) { return false; } var valueMin = this.parse(name, mapData[4]); // parse to validate if (!valueMin || valueMin.mapped) { return false; } // can't be invalid or mapped var valueMax = this.parse(name, mapData[5]); // parse to validate if (!valueMax || valueMax.mapped) { return false; } // can't be invalid or mapped // check if valueMin and valueMax are the same if (valueMin.value === valueMax.value) { return false; // can't make much of a mapper without a range } else if (type.color) { var c1 = valueMin.value; var c2 = valueMax.value; var same = c1[0] === c2[0] // red && c1[1] === c2[1] // green && c1[2] === c2[2] // blue && ( // optional alpha c1[3] === c2[3] // same alpha outright || (c1[3] == null || c1[3] === 1) && ( // full opacity for colour 1? c2[3] == null || c2[3] === 1) // full opacity for colour 2? ); if (same) { return false; } // can't make a mapper without a range } return { name: name, value: mapData, strValue: '' + value, mapped: _mapped, field: mapData[1], fieldMin: parseFloat(mapData[2]), // min & max are numeric fieldMax: parseFloat(mapData[3]), valueMin: valueMin.value, valueMax: valueMax.value, bypass: propIsBypass }; } if (type.multiple && propIsFlat !== 'multiple') { var vals = void 0; if (valueIsString) { vals = value.split(/\s+/); } else if (is.array(value)) { vals = value; } else { vals = [value]; } if (type.evenMultiple && vals.length % 2 !== 0) { return null; } var valArr = []; var unitsArr = []; var pfValArr = []; var hasEnum = false; for (var i = 0; i < vals.length; i++) { var p = self.parse(name, vals[i], propIsBypass, 'multiple'); hasEnum = hasEnum || is.string(p.value); valArr.push(p.value); pfValArr.push(p.pfValue != null ? p.pfValue : p.value); unitsArr.push(p.units); } if (type.validate && !type.validate(valArr, unitsArr)) { return null; } if (type.singleEnum && hasEnum) { if (valArr.length === 1 && is.string(valArr[0])) { return { name: name, value: valArr[0], strValue: valArr[0], bypass: propIsBypass }; } else { return null; } } return { name: name, value: valArr, pfValue: pfValArr, strValue: valArr.map(function (val, i) { return val + (unitsArr[i] || ''); }).join(' '), bypass: propIsBypass, units: unitsArr }; } // several types also allow enums var checkEnums = function checkEnums() { for (var _i = 0; _i < type.enums.length; _i++) { var en = type.enums[_i]; if (en === value) { return { name: name, value: value, strValue: '' + value, bypass: propIsBypass }; } } return null; }; // check the type and return the appropriate object if (type.number) { var units = void 0; var implicitUnits = 'px'; // not set => px if (type.units) { // use specified units if set units = type.units; } if (type.implicitUnits) { implicitUnits = type.implicitUnits; } if (!type.unitless) { if (valueIsString) { var unitsRegex = 'px|em' + (type.allowPercent ? '|\\%' : ''); if (units) { unitsRegex = units; } // only allow explicit units if so set var match = value.match('^(' + util.regex.number + ')(' + unitsRegex + ')?' + '$'); if (match) { value = match[1]; units = match[2] || implicitUnits; } } else if (!units || type.implicitUnits) { units = implicitUnits; // implicitly px if unspecified } } value = parseFloat(value); // if not a number and enums not allowed, then the value is invalid if (isNaN(value) && type.enums === undefined) { return null; } // check if this number type also accepts special keywords in place of numbers // (i.e. `left`, `auto`, etc) if (isNaN(value) && type.enums !== undefined) { value = passedValue; return checkEnums(); } // check if value must be an integer if (type.integer && !is.integer(value)) { return null; } // check value is within range if (type.min !== undefined && (value < type.min || type.strictMin && value === type.min) || type.max !== undefined && (value > type.max || type.strictMax && value === type.max)) { return null; } var ret = { name: name, value: value, strValue: '' + value + (units ? units : ''), units: units, bypass: propIsBypass }; // normalise value in pixels if (type.unitless || units !== 'px' && units !== 'em') { ret.pfValue = value; } else { ret.pfValue = units === 'px' || !units ? value : this.getEmSizeInPixels() * value; } // normalise value in ms if (units === 'ms' || units === 's') { ret.pfValue = units === 'ms' ? value : 1000 * value; } // normalise value in rad if (units === 'deg' || units === 'rad') { ret.pfValue = units === 'rad' ? value : math.deg2rad(value); } // normalize value in % if (units === '%') { ret.pfValue = value / 100; } return ret; } else if (type.propList) { var props = []; var propsStr = '' + value; if (propsStr === 'none') { // leave empty } else { // go over each prop var propsSplit = propsStr.split(','); for (var _i2 = 0; _i2 < propsSplit.length; _i2++) { var propName = propsSplit[_i2].trim(); if (self.properties[propName]) { props.push(propName); } } if (props.length === 0) { return null; } } return { name: name, value: props, strValue: props.length === 0 ? 'none' : props.join(', '), bypass: propIsBypass }; } else if (type.color) { var tuple = util.color2tuple(value); if (!tuple) { return null; } return { name: name, value: tuple, pfValue: tuple, strValue: '' + value, bypass: propIsBypass }; } else if (type.regex || type.regexes) { // first check enums if (type.enums) { var enumProp = checkEnums(); if (enumProp) { return enumProp; } } var regexes = type.regexes ? type.regexes : [type.regex]; for (var _i3 = 0; _i3 < regexes.length; _i3++) { var regex = new RegExp(regexes[_i3]); // make a regex from the type string var m = regex.exec(value); if (m) { // regex matches return { name: name, value: type.singleRegexMatchValue ? m[1] : m, strValue: '' + value, bypass: propIsBypass }; } } return null; // didn't match any } else if (type.string) { // just return return { name: name, value: '' + value, strValue: '' + value, bypass: propIsBypass }; } else if (type.enums) { // check enums last because it's a combo type in others return checkEnums(); } else { return null; // not a type we can handle } }; module.exports = styfn; /***/ }), /* 94 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var window = __webpack_require__(3); var math = __webpack_require__(2); var corefn = { autolock: function autolock(bool) { if (bool !== undefined) { this._private.autolock = bool ? true : false; } else { return this._private.autolock; } return this; // chaining }, autoungrabify: function autoungrabify(bool) { if (bool !== undefined) { this._private.autoungrabify = bool ? true : false; } else { return this._private.autoungrabify; } return this; // chaining }, autounselectify: function autounselectify(bool) { if (bool !== undefined) { this._private.autounselectify = bool ? true : false; } else { return this._private.autounselectify; } return this; // chaining }, panningEnabled: function panningEnabled(bool) { if (bool !== undefined) { this._private.panningEnabled = bool ? true : false; } else { return this._private.panningEnabled; } return this; // chaining }, userPanningEnabled: function userPanningEnabled(bool) { if (bool !== undefined) { this._private.userPanningEnabled = bool ? true : false; } else { return this._private.userPanningEnabled; } return this; // chaining }, zoomingEnabled: function zoomingEnabled(bool) { if (bool !== undefined) { this._private.zoomingEnabled = bool ? true : false; } else { return this._private.zoomingEnabled; } return this; // chaining }, userZoomingEnabled: function userZoomingEnabled(bool) { if (bool !== undefined) { this._private.userZoomingEnabled = bool ? true : false; } else { return this._private.userZoomingEnabled; } return this; // chaining }, boxSelectionEnabled: function boxSelectionEnabled(bool) { if (bool !== undefined) { this._private.boxSelectionEnabled = bool ? true : false; } else { return this._private.boxSelectionEnabled; } return this; // chaining }, pan: function pan() { var args = arguments; var pan = this._private.pan; var dim = void 0, val = void 0, dims = void 0, x = void 0, y = void 0; switch (args.length) { case 0: // .pan() return pan; case 1: if (is.string(args[0])) { // .pan('x') dim = args[0]; return pan[dim]; } else if (is.plainObject(args[0])) { // .pan({ x: 0, y: 100 }) if (!this._private.panningEnabled) { return this; } dims = args[0]; x = dims.x; y = dims.y; if (is.number(x)) { pan.x = x; } if (is.number(y)) { pan.y = y; } this.emit('pan viewport'); } break; case 2: // .pan('x', 100) if (!this._private.panningEnabled) { return this; } dim = args[0]; val = args[1]; if ((dim === 'x' || dim === 'y') && is.number(val)) { pan[dim] = val; } this.emit('pan viewport'); break; default: break; // invalid } this.notify({ // notify the renderer that the viewport changed type: 'viewport' }); return this; // chaining }, panBy: function panBy(arg0, arg1) { var args = arguments; var pan = this._private.pan; var dim = void 0, val = void 0, dims = void 0, x = void 0, y = void 0; if (!this._private.panningEnabled) { return this; } switch (args.length) { case 1: if (is.plainObject(arg0)) { // .panBy({ x: 0, y: 100 }) dims = args[0]; x = dims.x; y = dims.y; if (is.number(x)) { pan.x += x; } if (is.number(y)) { pan.y += y; } this.emit('pan viewport'); } break; case 2: // .panBy('x', 100) dim = arg0; val = arg1; if ((dim === 'x' || dim === 'y') && is.number(val)) { pan[dim] += val; } this.emit('pan viewport'); break; default: break; // invalid } this.notify({ // notify the renderer that the viewport changed type: 'viewport' }); return this; // chaining }, fit: function fit(elements, padding) { var viewportState = this.getFitViewport(elements, padding); if (viewportState) { var _p = this._private; _p.zoom = viewportState.zoom; _p.pan = viewportState.pan; this.emit('pan zoom viewport'); this.notify({ // notify the renderer that the viewport changed type: 'viewport' }); } return this; // chaining }, getFitViewport: function getFitViewport(elements, padding) { if (is.number(elements) && padding === undefined) { // elements is optional padding = elements; elements = undefined; } if (!this._private.panningEnabled || !this._private.zoomingEnabled) { return; } var bb = void 0; if (is.string(elements)) { var sel = elements; elements = this.$(sel); } else if (is.boundingBox(elements)) { // assume bb var bbe = elements; bb = { x1: bbe.x1, y1: bbe.y1, x2: bbe.x2, y2: bbe.y2 }; bb.w = bb.x2 - bb.x1; bb.h = bb.y2 - bb.y1; } else if (!is.elementOrCollection(elements)) { elements = this.mutableElements(); } if (is.elementOrCollection(elements) && elements.empty()) { return; } // can't fit to nothing bb = bb || elements.boundingBox(); var w = this.width(); var h = this.height(); var zoom = void 0; padding = is.number(padding) ? padding : 0; if (!isNaN(w) && !isNaN(h) && w > 0 && h > 0 && !isNaN(bb.w) && !isNaN(bb.h) && bb.w > 0 && bb.h > 0) { zoom = Math.min((w - 2 * padding) / bb.w, (h - 2 * padding) / bb.h); // crop zoom zoom = zoom > this._private.maxZoom ? this._private.maxZoom : zoom; zoom = zoom < this._private.minZoom ? this._private.minZoom : zoom; var pan = { // now pan to middle x: (w - zoom * (bb.x1 + bb.x2)) / 2, y: (h - zoom * (bb.y1 + bb.y2)) / 2 }; return { zoom: zoom, pan: pan }; } return; }, minZoom: function minZoom(zoom) { if (zoom === undefined) { return this._private.minZoom; } else if (is.number(zoom)) { this._private.minZoom = zoom; } return this; }, maxZoom: function maxZoom(zoom) { if (zoom === undefined) { return this._private.maxZoom; } else if (is.number(zoom)) { this._private.maxZoom = zoom; } return this; }, getZoomedViewport: function getZoomedViewport(params) { var _p = this._private; var currentPan = _p.pan; var currentZoom = _p.zoom; var pos = void 0; // in rendered px var zoom = void 0; var bail = false; if (!_p.zoomingEnabled) { // zooming disabled bail = true; } if (is.number(params)) { // then set the zoom zoom = params; } else if (is.plainObject(params)) { // then zoom about a point zoom = params.level; if (params.position != null) { pos = math.modelToRenderedPosition(params.position, currentZoom, currentPan); } else if (params.renderedPosition != null) { pos = params.renderedPosition; } if (pos != null && !_p.panningEnabled) { // panning disabled bail = true; } } // crop zoom zoom = zoom > _p.maxZoom ? _p.maxZoom : zoom; zoom = zoom < _p.minZoom ? _p.minZoom : zoom; // can't zoom with invalid params if (bail || !is.number(zoom) || zoom === currentZoom || pos != null && (!is.number(pos.x) || !is.number(pos.y))) { return null; } if (pos != null) { // set zoom about position var pan1 = currentPan; var zoom1 = currentZoom; var zoom2 = zoom; var pan2 = { x: -zoom2 / zoom1 * (pos.x - pan1.x) + pos.x, y: -zoom2 / zoom1 * (pos.y - pan1.y) + pos.y }; return { zoomed: true, panned: true, zoom: zoom2, pan: pan2 }; } else { // just set the zoom return { zoomed: true, panned: false, zoom: zoom, pan: currentPan }; } }, zoom: function zoom(params) { if (params === undefined) { // get return this._private.zoom; } else { // set var vp = this.getZoomedViewport(params); var _p = this._private; if (vp == null || !vp.zoomed) { return this; } _p.zoom = vp.zoom; if (vp.panned) { _p.pan.x = vp.pan.x; _p.pan.y = vp.pan.y; } this.emit('zoom' + (vp.panned ? ' pan' : '') + ' viewport'); this.notify({ // notify the renderer that the viewport changed type: 'viewport' }); return this; // chaining } }, viewport: function viewport(opts) { var _p = this._private; var zoomDefd = true; var panDefd = true; var events = []; // to trigger var zoomFailed = false; var panFailed = false; if (!opts) { return this; } if (!is.number(opts.zoom)) { zoomDefd = false; } if (!is.plainObject(opts.pan)) { panDefd = false; } if (!zoomDefd && !panDefd) { return this; } if (zoomDefd) { var z = opts.zoom; if (z < _p.minZoom || z > _p.maxZoom || !_p.zoomingEnabled) { zoomFailed = true; } else { _p.zoom = z; events.push('zoom'); } } if (panDefd && (!zoomFailed || !opts.cancelOnFailedZoom) && _p.panningEnabled) { var p = opts.pan; if (is.number(p.x)) { _p.pan.x = p.x; panFailed = false; } if (is.number(p.y)) { _p.pan.y = p.y; panFailed = false; } if (!panFailed) { events.push('pan'); } } if (events.length > 0) { events.push('viewport'); this.emit(events.join(' ')); this.notify({ type: 'viewport' }); } return this; // chaining }, center: function center(elements) { var pan = this.getCenterPan(elements); if (pan) { this._private.pan = pan; this.emit('pan viewport'); this.notify({ // notify the renderer that the viewport changed type: 'viewport' }); } return this; // chaining }, getCenterPan: function getCenterPan(elements, zoom) { if (!this._private.panningEnabled) { return; } if (is.string(elements)) { var selector = elements; elements = this.mutableElements().filter(selector); } else if (!is.elementOrCollection(elements)) { elements = this.mutableElements(); } if (elements.length === 0) { return; } // can't centre pan to nothing var bb = elements.boundingBox(); var w = this.width(); var h = this.height(); zoom = zoom === undefined ? this._private.zoom : zoom; var pan = { // middle x: (w - zoom * (bb.x1 + bb.x2)) / 2, y: (h - zoom * (bb.y1 + bb.y2)) / 2 }; return pan; }, reset: function reset() { if (!this._private.panningEnabled || !this._private.zoomingEnabled) { return this; } this.viewport({ pan: { x: 0, y: 0 }, zoom: 1 }); return this; // chaining }, invalidateSize: function invalidateSize() { this._private.sizeCache = null; }, size: function size() { var _p = this._private; var container = _p.container; return _p.sizeCache = _p.sizeCache || (container ? function () { var style = window.getComputedStyle(container); var val = function val(name) { return parseFloat(style.getPropertyValue(name)); }; return { width: container.clientWidth - val('padding-left') - val('padding-right'), height: container.clientHeight - val('padding-top') - val('padding-bottom') }; }() : { // fallback if no container (not 0 b/c can be used for dividing etc) width: 1, height: 1 }); }, width: function width() { return this.size().width; }, height: function height() { return this.size().height; }, extent: function extent() { var pan = this._private.pan; var zoom = this._private.zoom; var rb = this.renderedExtent(); var b = { x1: (rb.x1 - pan.x) / zoom, x2: (rb.x2 - pan.x) / zoom, y1: (rb.y1 - pan.y) / zoom, y2: (rb.y2 - pan.y) / zoom }; b.w = b.x2 - b.x1; b.h = b.y2 - b.y1; return b; }, renderedExtent: function renderedExtent() { var width = this.width(); var height = this.height(); return { x1: 0, y1: 0, x2: width, y2: height, w: width, h: height }; } }; // aliases corefn.centre = corefn.center; // backwards compatibility corefn.autolockNodes = corefn.autolock; corefn.autoungrabifyNodes = corefn.autoungrabify; module.exports = corefn; /***/ }), /* 95 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var define = __webpack_require__(4); var Collection = __webpack_require__(7); var Core = __webpack_require__(12); var incExts = __webpack_require__(96); var is = __webpack_require__(0); var Emitter = __webpack_require__(11); // registered extensions to cytoscape, indexed by name var extensions = {}; // registered modules for extensions, indexed by name var modules = {}; function setExtension(type, name, registrant) { var ext = registrant; var overrideErr = function overrideErr(field) { util.error('Can not register `' + name + '` for `' + type + '` since `' + field + '` already exists in the prototype and can not be overridden'); }; if (type === 'core') { if (Core.prototype[name]) { return overrideErr(name); } else { Core.prototype[name] = registrant; } } else if (type === 'collection') { if (Collection.prototype[name]) { return overrideErr(name); } else { Collection.prototype[name] = registrant; } } else if (type === 'layout') { // fill in missing layout functions in the prototype var Layout = function Layout(options) { this.options = options; registrant.call(this, options); // make sure layout has _private for use w/ std apis like .on() if (!is.plainObject(this._private)) { this._private = {}; } this._private.cy = options.cy; this._private.listeners = []; this.createEmitter(); }; var layoutProto = Layout.prototype = Object.create(registrant.prototype); var optLayoutFns = []; for (var i = 0; i < optLayoutFns.length; i++) { var fnName = optLayoutFns[i]; layoutProto[fnName] = layoutProto[fnName] || function () { return this; }; } // either .start() or .run() is defined, so autogen the other if (layoutProto.start && !layoutProto.run) { layoutProto.run = function () { this.start();return this; }; } else if (!layoutProto.start && layoutProto.run) { layoutProto.start = function () { this.run();return this; }; } var regStop = registrant.prototype.stop; layoutProto.stop = function () { var opts = this.options; if (opts && opts.animate) { var anis = this.animations; if (anis) { for (var _i = 0; _i < anis.length; _i++) { anis[_i].stop(); } } } if (regStop) { regStop.call(this); } else { this.emit('layoutstop'); } return this; }; if (!layoutProto.destroy) { layoutProto.destroy = function () { return this; }; } layoutProto.cy = function () { return this._private.cy; }; var getCy = function getCy(layout) { return layout._private.cy; }; util.assign(layoutProto, { createEmitter: function createEmitter() { this._private.emitter = new Emitter({ eventFields: function eventFields(layout) { return { layout: layout, cy: getCy(layout), target: layout }; }, bubble: function bubble() { return true; }, parent: function parent(layout) { return getCy(layout); }, context: this }); return this; }, emitter: function emitter() { return this._private.emitter; }, on: function on(evt, cb) { this.emitter().on(evt, cb);return this; }, one: function one(evt, cb) { this.emitter().one(evt, cb);return this; }, once: function once(evt, cb) { this.emitter().one(evt, cb);return this; }, removeListener: function removeListener(evt, cb) { this.emitter().removeListener(evt, cb);return this; }, emit: function emit(evt, params) { this.emitter().emit(evt, params);return this; } }); define.eventAliasesOn(layoutProto); ext = Layout; // replace with our wrapped layout } else if (type === 'renderer' && name !== 'null' && name !== 'base') { // user registered renderers inherit from base var BaseRenderer = getExtension('renderer', 'base'); var bProto = BaseRenderer.prototype; var RegistrantRenderer = registrant; var rProto = registrant.prototype; var Renderer = function Renderer() { BaseRenderer.apply(this, arguments); RegistrantRenderer.apply(this, arguments); }; var proto = Renderer.prototype; for (var pName in bProto) { var pVal = bProto[pName]; var existsInR = rProto[pName] != null; if (existsInR) { return overrideErr(pName); } proto[pName] = pVal; // take impl from base } for (var _pName in rProto) { proto[_pName] = rProto[_pName]; // take impl from registrant } bProto.clientFunctions.forEach(function (name) { proto[name] = proto[name] || function () { util.error('Renderer does not implement `renderer.' + name + '()` on its prototype'); }; }); ext = Renderer; } return util.setMap({ map: extensions, keys: [type, name], value: ext }); } function getExtension(type, name) { return util.getMap({ map: extensions, keys: [type, name] }); } function setModule(type, name, moduleType, moduleName, registrant) { return util.setMap({ map: modules, keys: [type, name, moduleType, moduleName], value: registrant }); } function getModule(type, name, moduleType, moduleName) { return util.getMap({ map: modules, keys: [type, name, moduleType, moduleName] }); } var extension = function extension() { // e.g. extension('renderer', 'svg') if (arguments.length === 2) { return getExtension.apply(null, arguments); } // e.g. extension('renderer', 'svg', { ... }) else if (arguments.length === 3) { return setExtension.apply(null, arguments); } // e.g. extension('renderer', 'svg', 'nodeShape', 'ellipse') else if (arguments.length === 4) { return getModule.apply(null, arguments); } // e.g. extension('renderer', 'svg', 'nodeShape', 'ellipse', { ... }) else if (arguments.length === 5) { return setModule.apply(null, arguments); } else { util.error('Invalid extension access syntax'); } }; // allows a core instance to access extensions internally Core.prototype.extension = extension; // included extensions incExts.forEach(function (group) { group.extensions.forEach(function (ext) { setExtension(group.type, ext.name, ext.impl); }); }); module.exports = extension; /***/ }), /* 96 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; module.exports = [{ type: 'layout', extensions: __webpack_require__(97) }, { type: 'renderer', extensions: __webpack_require__(106) }]; /***/ }), /* 97 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; module.exports = [{ name: 'breadthfirst', impl: __webpack_require__(98) }, { name: 'circle', impl: __webpack_require__(99) }, { name: 'concentric', impl: __webpack_require__(100) }, { name: 'cose', impl: __webpack_require__(101) }, { name: 'grid', impl: __webpack_require__(102) }, { name: 'null', impl: __webpack_require__(103) }, { name: 'preset', impl: __webpack_require__(104) }, { name: 'random', impl: __webpack_require__(105) }]; /***/ }), /* 98 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var math = __webpack_require__(2); var is = __webpack_require__(0); var defaults = { fit: true, // whether to fit the viewport to the graph directed: false, // whether the tree is directed downwards (or edges can point in any direction if false) padding: 30, // padding on fit circle: false, // put depths in concentric circles if true, put depths top down if false spacingFactor: 1.75, // positive spacing factor, larger => more space between nodes (N.B. n/a if causes overlap) boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space nodeDimensionsIncludeLabels: false, // Excludes the label when calculating node bounding boxes for the layout algorithm roots: undefined, // the roots of the trees maximalAdjustments: 0, // how many times to try to position the nodes in a maximal way (i.e. no backtracking) animate: false, // whether to transition the node positions animationDuration: 500, // duration of animation in ms if enabled animationEasing: undefined, // easing of animation if enabled, animateFilter: function animateFilter(node, i) { return true; }, // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts ready: undefined, // callback on layoutready stop: undefined, // callback on layoutstop transform: function transform(node, position) { return position; } // transform a given node position. Useful for changing flow direction in discrete layouts }; function BreadthFirstLayout(options) { this.options = util.extend({}, defaults, options); } BreadthFirstLayout.prototype.run = function () { var params = this.options; var options = params; var cy = params.cy; var eles = options.eles; var nodes = eles.nodes().not(':parent'); var graph = eles; var bb = math.makeBoundingBox(options.boundingBox ? options.boundingBox : { x1: 0, y1: 0, w: cy.width(), h: cy.height() }); var roots = void 0; if (is.elementOrCollection(options.roots)) { roots = options.roots; } else if (is.array(options.roots)) { var rootsArray = []; for (var i = 0; i < options.roots.length; i++) { var id = options.roots[i]; var ele = cy.getElementById(id); rootsArray.push(ele); } roots = cy.collection(rootsArray); } else if (is.string(options.roots)) { roots = cy.$(options.roots); } else { if (options.directed) { roots = nodes.roots(); } else { var components = []; var unhandledNodes = nodes; var _loop = function _loop() { var currComp = cy.collection(); eles.bfs({ roots: unhandledNodes[0], visit: function visit(node, edge, pNode, i, depth) { currComp = currComp.add(node); }, directed: false }); unhandledNodes = unhandledNodes.not(currComp); components.push(currComp); }; while (unhandledNodes.length > 0) { _loop(); } roots = cy.collection(); var _loop2 = function _loop2(_i) { var comp = components[_i]; var maxDegree = comp.maxDegree(false); var compRoots = comp.filter(function (ele) { return ele.degree(false) === maxDegree; }); roots = roots.add(compRoots); }; for (var _i = 0; _i < components.length; _i++) { _loop2(_i); } } } var depths = []; var foundByBfs = {}; var id2depth = {}; var prevNode = {}; var prevEdge = {}; var successors = {}; // find the depths of the nodes graph.bfs({ roots: roots, directed: options.directed, visit: function visit(node, edge, pNode, i, depth) { var ele = node[0]; var id = ele.id(); if (!depths[depth]) { depths[depth] = []; } depths[depth].push(ele); foundByBfs[id] = true; id2depth[id] = depth; prevNode[id] = pNode; prevEdge[id] = edge; if (pNode) { var prevId = pNode.id(); var succ = successors[prevId] = successors[prevId] || []; succ.push(node); } } }); // check for nodes not found by bfs var orphanNodes = []; for (var _i2 = 0; _i2 < nodes.length; _i2++) { var _ele = nodes[_i2]; if (foundByBfs[_ele.id()]) { continue; } else { orphanNodes.push(_ele); } } // assign orphan nodes a depth from their neighborhood var maxChecks = orphanNodes.length * 3; var checks = 0; while (orphanNodes.length !== 0 && checks < maxChecks) { var node = orphanNodes.shift(); var neighbors = node.neighborhood().nodes(); var assignedDepth = false; for (var _i3 = 0; _i3 < neighbors.length; _i3++) { var depth = id2depth[neighbors[_i3].id()]; if (depth !== undefined) { depths[depth].push(node); assignedDepth = true; break; } } if (!assignedDepth) { orphanNodes.push(node); } checks++; } // assign orphan nodes that are still left to the depth of their subgraph while (orphanNodes.length !== 0) { var _node = orphanNodes.shift(); //let subgraph = graph.bfs( node ).path; var _assignedDepth = false; // for( let i = 0; i < subgraph.length; i++ ){ // let depth = id2depth[ subgraph[i].id() ]; // if( depth !== undefined ){ // depths[depth].push( node ); // assignedDepth = true; // break; // } // } if (!_assignedDepth) { // worst case if the graph really isn't tree friendly, then just dump it in 0 if (depths.length === 0) { depths.push([]); } depths[0].push(_node); } } // assign the nodes a depth and index var assignDepthsToEles = function assignDepthsToEles() { for (var _i4 = 0; _i4 < depths.length; _i4++) { var _eles = depths[_i4]; for (var j = 0; j < _eles.length; j++) { var _ele2 = _eles[j]; if (_ele2 == null) { _eles.splice(j, 1); j--; continue; } _ele2._private.scratch.breadthfirst = { depth: _i4, index: j }; } } }; assignDepthsToEles(); var intersectsDepth = function intersectsDepth(node) { // returns true if has edges pointing in from a higher depth var edges = node.connectedEdges(function (ele) { return ele.data('target') === node.id(); }); var thisInfo = node._private.scratch.breadthfirst; var highestDepthOfOther = 0; var highestOther = void 0; for (var _i5 = 0; _i5 < edges.length; _i5++) { var edge = edges[_i5]; var otherNode = edge.source()[0]; var otherInfo = otherNode._private.scratch.breadthfirst; if (thisInfo.depth <= otherInfo.depth && highestDepthOfOther < otherInfo.depth) { highestDepthOfOther = otherInfo.depth; highestOther = otherNode; } } return highestOther; }; // make maximal if so set by adjusting depths for (var adj = 0; adj < options.maximalAdjustments; adj++) { var nDepths = depths.length; var elesToMove = []; for (var _i6 = 0; _i6 < nDepths; _i6++) { var _depth = depths[_i6]; var nDepth = _depth.length; for (var j = 0; j < nDepth; j++) { var _ele3 = _depth[j]; var info = _ele3._private.scratch.breadthfirst; var intEle = intersectsDepth(_ele3); if (intEle) { info.intEle = intEle; elesToMove.push(_ele3); } } } for (var _i7 = 0; _i7 < elesToMove.length; _i7++) { var _ele4 = elesToMove[_i7]; var _info = _ele4._private.scratch.breadthfirst; var _intEle = _info.intEle; var intInfo = _intEle._private.scratch.breadthfirst; depths[_info.depth][_info.index] = null; // remove from old depth & index (create hole to be cleaned) // add to end of new depth var newDepth = intInfo.depth + 1; while (newDepth > depths.length - 1) { depths.push([]); } depths[newDepth].push(_ele4); _info.depth = newDepth; _info.index = depths[newDepth].length - 1; } assignDepthsToEles(); } // find min distance we need to leave between nodes var minDistance = 0; if (options.avoidOverlap) { for (var _i8 = 0; _i8 < nodes.length; _i8++) { var n = nodes[_i8]; var nbb = n.layoutDimensions(options); var w = nbb.w; var h = nbb.h; minDistance = Math.max(minDistance, w, h); } } // get the weighted percent for an element based on its connectivity to other levels var cachedWeightedPercent = {}; var getWeightedPercent = function getWeightedPercent(ele) { if (cachedWeightedPercent[ele.id()]) { return cachedWeightedPercent[ele.id()]; } var eleDepth = ele._private.scratch.breadthfirst.depth; var neighbors = ele.neighborhood().nodes().not(':parent').intersection(nodes); var percent = 0; var samples = 0; for (var _i9 = 0; _i9 < neighbors.length; _i9++) { var neighbor = neighbors[_i9]; var bf = neighbor._private.scratch.breadthfirst; var index = bf.index; var _depth2 = bf.depth; var _nDepth = depths[_depth2].length; if (eleDepth > _depth2 || eleDepth === 0) { // only get influenced by elements above percent += index / _nDepth; samples++; } } samples = Math.max(1, samples); percent = percent / samples; if (samples === 0) { // so lone nodes have a "don't care" state in sorting percent = undefined; } cachedWeightedPercent[ele.id()] = percent; return percent; }; // rearrange the indices in each depth level based on connectivity var sortFn = function sortFn(a, b) { var apct = getWeightedPercent(a); var bpct = getWeightedPercent(b); return apct - bpct; }; for (var times = 0; times < 3; times++) { // do it a few times b/c the depths are dynamic and we want a more stable result for (var _i10 = 0; _i10 < depths.length; _i10++) { depths[_i10] = depths[_i10].sort(sortFn); } assignDepthsToEles(); // and update } var biggestDepthSize = 0; for (var _i11 = 0; _i11 < depths.length; _i11++) { biggestDepthSize = Math.max(depths[_i11].length, biggestDepthSize); } var center = { x: bb.x1 + bb.w / 2, y: bb.x1 + bb.h / 2 }; var getPosition = function getPosition(ele, isBottomDepth) { var info = ele._private.scratch.breadthfirst; var depth = info.depth; var index = info.index; var depthSize = depths[depth].length; var distanceX = Math.max(bb.w / (depthSize + 1), minDistance); var distanceY = Math.max(bb.h / (depths.length + 1), minDistance); var radiusStepSize = Math.min(bb.w / 2 / depths.length, bb.h / 2 / depths.length); radiusStepSize = Math.max(radiusStepSize, minDistance); if (!options.circle) { var epos = { x: center.x + (index + 1 - (depthSize + 1) / 2) * distanceX, y: (depth + 1) * distanceY }; if (isBottomDepth) { return epos; } // let succs = successors[ ele.id() ]; // if( succs ){ // epos.x = 0; // // for( let i = 0 ; i < succs.length; i++ ){ // let spos = pos[ succs[i].id() ]; // // epos.x += spos.x; // } // // epos.x /= succs.length; // } else { // //debugger; // } return epos; } else { if (options.circle) { var radius = radiusStepSize * depth + radiusStepSize - (depths.length > 0 && depths[0].length <= 3 ? radiusStepSize / 2 : 0); var theta = 2 * Math.PI / depths[depth].length * index; if (depth === 0 && depths[0].length === 1) { radius = 1; } return { x: center.x + radius * Math.cos(theta), y: center.y + radius * Math.sin(theta) }; } else { return { x: center.x + (index + 1 - (depthSize + 1) / 2) * distanceX, y: (depth + 1) * distanceY }; } } }; // get positions in reverse depth order var pos = {}; for (var _i12 = depths.length - 1; _i12 >= 0; _i12--) { var _depth3 = depths[_i12]; for (var _j = 0; _j < _depth3.length; _j++) { var _node2 = _depth3[_j]; pos[_node2.id()] = getPosition(_node2, _i12 === depths.length - 1); } } nodes.layoutPositions(this, options, function (node) { return pos[node.id()]; }); return this; // chaining }; module.exports = BreadthFirstLayout; /***/ }), /* 99 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var math = __webpack_require__(2); var is = __webpack_require__(0); var defaults = { fit: true, // whether to fit the viewport to the graph padding: 30, // the padding on fit boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } avoidOverlap: true, // prevents node overlap, may overflow boundingBox and radius if not enough space nodeDimensionsIncludeLabels: false, // Excludes the label when calculating node bounding boxes for the layout algorithm spacingFactor: undefined, // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up radius: undefined, // the radius of the circle startAngle: 3 / 2 * Math.PI, // where nodes start in radians sweep: undefined, // how many radians should be between the first and last node (defaults to full circle) clockwise: true, // whether the layout should go clockwise (true) or counterclockwise/anticlockwise (false) sort: undefined, // a sorting function to order the nodes; e.g. function(a, b){ return a.data('weight') - b.data('weight') } animate: false, // whether to transition the node positions animationDuration: 500, // duration of animation in ms if enabled animationEasing: undefined, // easing of animation if enabled animateFilter: function animateFilter(node, i) { return true; }, // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts ready: undefined, // callback on layoutready stop: undefined, // callback on layoutstop transform: function transform(node, position) { return position; } // transform a given node position. Useful for changing flow direction in discrete layouts }; function CircleLayout(options) { this.options = util.extend({}, defaults, options); } CircleLayout.prototype.run = function () { var params = this.options; var options = params; var cy = params.cy; var eles = options.eles; var clockwise = options.counterclockwise !== undefined ? !options.counterclockwise : options.clockwise; var nodes = eles.nodes().not(':parent'); if (options.sort) { nodes = nodes.sort(options.sort); } var bb = math.makeBoundingBox(options.boundingBox ? options.boundingBox : { x1: 0, y1: 0, w: cy.width(), h: cy.height() }); var center = { x: bb.x1 + bb.w / 2, y: bb.y1 + bb.h / 2 }; var sweep = options.sweep === undefined ? 2 * Math.PI - 2 * Math.PI / nodes.length : options.sweep; var dTheta = sweep / Math.max(1, nodes.length - 1); var r = void 0; var minDistance = 0; for (var i = 0; i < nodes.length; i++) { var n = nodes[i]; var nbb = n.layoutDimensions(options); var w = nbb.w; var h = nbb.h; minDistance = Math.max(minDistance, w, h); } if (is.number(options.radius)) { r = options.radius; } else if (nodes.length <= 1) { r = 0; } else { r = Math.min(bb.h, bb.w) / 2 - minDistance; } // calculate the radius if (nodes.length > 1 && options.avoidOverlap) { // but only if more than one node (can't overlap) minDistance *= 1.75; // just to have some nice spacing var dcos = Math.cos(dTheta) - Math.cos(0); var dsin = Math.sin(dTheta) - Math.sin(0); var rMin = Math.sqrt(minDistance * minDistance / (dcos * dcos + dsin * dsin)); // s.t. no nodes overlapping r = Math.max(rMin, r); } var getPos = function getPos(ele, i) { var theta = options.startAngle + i * dTheta * (clockwise ? 1 : -1); var rx = r * Math.cos(theta); var ry = r * Math.sin(theta); var pos = { x: center.x + rx, y: center.y + ry }; return pos; }; nodes.layoutPositions(this, options, getPos); return this; // chaining }; module.exports = CircleLayout; /***/ }), /* 100 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var math = __webpack_require__(2); var defaults = { fit: true, // whether to fit the viewport to the graph padding: 30, // the padding on fit startAngle: 3 / 2 * Math.PI, // where nodes start in radians sweep: undefined, // how many radians should be between the first and last node (defaults to full circle) clockwise: true, // whether the layout should go clockwise (true) or counterclockwise/anticlockwise (false) equidistant: false, // whether levels have an equal radial distance betwen them, may cause bounding box overflow minNodeSpacing: 10, // min spacing between outside of nodes (used for radius adjustment) boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space nodeDimensionsIncludeLabels: false, // Excludes the label when calculating node bounding boxes for the layout algorithm height: undefined, // height of layout area (overrides container height) width: undefined, // width of layout area (overrides container width) spacingFactor: undefined, // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up concentric: function concentric(node) { // returns numeric value for each node, placing higher nodes in levels towards the centre return node.degree(); }, levelWidth: function levelWidth(nodes) { // the letiation of concentric values in each level return nodes.maxDegree() / 4; }, animate: false, // whether to transition the node positions animationDuration: 500, // duration of animation in ms if enabled animationEasing: undefined, // easing of animation if enabled animateFilter: function animateFilter(node, i) { return true; }, // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts ready: undefined, // callback on layoutready stop: undefined, // callback on layoutstop transform: function transform(node, position) { return position; } // transform a given node position. Useful for changing flow direction in discrete layouts }; function ConcentricLayout(options) { this.options = util.extend({}, defaults, options); } ConcentricLayout.prototype.run = function () { var params = this.options; var options = params; var clockwise = options.counterclockwise !== undefined ? !options.counterclockwise : options.clockwise; var cy = params.cy; var eles = options.eles; var nodes = eles.nodes().not(':parent'); var bb = math.makeBoundingBox(options.boundingBox ? options.boundingBox : { x1: 0, y1: 0, w: cy.width(), h: cy.height() }); var center = { x: bb.x1 + bb.w / 2, y: bb.y1 + bb.h / 2 }; var nodeValues = []; // { node, value } var theta = options.startAngle; var maxNodeSize = 0; for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; var value = void 0; // calculate the node value value = options.concentric(node); nodeValues.push({ value: value, node: node }); // for style mapping node._private.scratch.concentric = value; } // in case we used the `concentric` in style nodes.updateStyle(); // calculate max size now based on potentially updated mappers for (var _i = 0; _i < nodes.length; _i++) { var _node = nodes[_i]; var nbb = _node.layoutDimensions(options); maxNodeSize = Math.max(maxNodeSize, nbb.w, nbb.h); } // sort node values in descreasing order nodeValues.sort(function (a, b) { return b.value - a.value; }); var levelWidth = options.levelWidth(nodes); // put the values into levels var levels = [[]]; var currentLevel = levels[0]; for (var _i2 = 0; _i2 < nodeValues.length; _i2++) { var val = nodeValues[_i2]; if (currentLevel.length > 0) { var diff = Math.abs(currentLevel[0].value - val.value); if (diff >= levelWidth) { currentLevel = []; levels.push(currentLevel); } } currentLevel.push(val); } // create positions from levels var minDist = maxNodeSize + options.minNodeSpacing; // min dist between nodes if (!options.avoidOverlap) { // then strictly constrain to bb var firstLvlHasMulti = levels.length > 0 && levels[0].length > 1; var maxR = Math.min(bb.w, bb.h) / 2 - minDist; var rStep = maxR / (levels.length + firstLvlHasMulti ? 1 : 0); minDist = Math.min(minDist, rStep); } // find the metrics for each level var r = 0; for (var _i3 = 0; _i3 < levels.length; _i3++) { var level = levels[_i3]; var sweep = options.sweep === undefined ? 2 * Math.PI - 2 * Math.PI / level.length : options.sweep; var dTheta = level.dTheta = sweep / Math.max(1, level.length - 1); // calculate the radius if (level.length > 1 && options.avoidOverlap) { // but only if more than one node (can't overlap) var dcos = Math.cos(dTheta) - Math.cos(0); var dsin = Math.sin(dTheta) - Math.sin(0); var rMin = Math.sqrt(minDist * minDist / (dcos * dcos + dsin * dsin)); // s.t. no nodes overlapping r = Math.max(rMin, r); } level.r = r; r += minDist; } if (options.equidistant) { var rDeltaMax = 0; var _r = 0; for (var _i4 = 0; _i4 < levels.length; _i4++) { var _level = levels[_i4]; var rDelta = _level.r - _r; rDeltaMax = Math.max(rDeltaMax, rDelta); } _r = 0; for (var _i5 = 0; _i5 < levels.length; _i5++) { var _level2 = levels[_i5]; if (_i5 === 0) { _r = _level2.r; } _level2.r = _r; _r += rDeltaMax; } } // calculate the node positions var pos = {}; // id => position for (var _i6 = 0; _i6 < levels.length; _i6++) { var _level3 = levels[_i6]; var _dTheta = _level3.dTheta; var _r2 = _level3.r; for (var j = 0; j < _level3.length; j++) { var _val = _level3[j]; var _theta = options.startAngle + (clockwise ? 1 : -1) * _dTheta * j; var p = { x: center.x + _r2 * Math.cos(_theta), y: center.y + _r2 * Math.sin(_theta) }; pos[_val.node.id()] = p; } } // position the nodes nodes.layoutPositions(this, options, function (ele) { var id = ele.id(); return pos[id]; }); return this; // chaining }; module.exports = ConcentricLayout; /***/ }), /* 101 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /* The CoSE layout was written by Gerardo Huck. https://www.linkedin.com/in/gerardohuck/ Based on the following article: http://dl.acm.org/citation.cfm?id=1498047 Modifications tracked on Github. */ var util = __webpack_require__(1); var math = __webpack_require__(2); var is = __webpack_require__(0); var Promise = __webpack_require__(5); var DEBUG; /** * @brief : default layout options */ var defaults = { // Called on `layoutready` ready: function ready() {}, // Called on `layoutstop` stop: function stop() {}, // Whether to animate while running the layout // true : Animate continuously as the layout is running // false : Just show the end result // 'end' : Animate with the end result, from the initial positions to the end positions animate: true, // Easing of the animation for animate:'end' animationEasing: undefined, // The duration of the animation for animate:'end' animationDuration: undefined, // A function that determines whether the node should be animated // All nodes animated by default on animate enabled // Non-animated nodes are positioned immediately when the layout starts animateFilter: function animateFilter(node, i) { return true; }, // The layout animates only after this many milliseconds for animate:true // (prevents flashing on fast runs) animationThreshold: 250, // Number of iterations between consecutive screen positions update // (0 -> only updated on the end) refresh: 20, // Whether to fit the network view after when done fit: true, // Padding on fit padding: 30, // Constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } boundingBox: undefined, // Excludes the label when calculating node bounding boxes for the layout algorithm nodeDimensionsIncludeLabels: false, // Randomize the initial positions of the nodes (true) or use existing positions (false) randomize: false, // Extra spacing between components in non-compound graphs componentSpacing: 40, // Node repulsion (non overlapping) multiplier nodeRepulsion: function nodeRepulsion(node) { return 2048; }, // Node repulsion (overlapping) multiplier nodeOverlap: 4, // Ideal edge (non nested) length idealEdgeLength: function idealEdgeLength(edge) { return 32; }, // Divisor to compute edge forces edgeElasticity: function edgeElasticity(edge) { return 32; }, // Nesting factor (multiplier) to compute ideal edge length for nested edges nestingFactor: 1.2, // Gravity force (constant) gravity: 1, // Maximum number of iterations to perform numIter: 1000, // Initial temperature (maximum node displacement) initialTemp: 1000, // Cooling factor (how the temperature is reduced between consecutive iterations coolingFactor: 0.99, // Lower temperature threshold (below this point the layout will end) minTemp: 1.0, // Pass a reference to weaver to use threads for calculations weaver: false }; /** * @brief : constructor * @arg options : object containing layout options */ function CoseLayout(options) { this.options = util.extend({}, defaults, options); this.options.layout = this; } /** * @brief : runs the layout */ CoseLayout.prototype.run = function () { var options = this.options; var cy = options.cy; var layout = this; var thread = this.thread; var Thread = options.weaver ? options.weaver.Thread : null; var falseThread = { // use false thread as polyfill listeners: [], on: function on(e, cb) { this.listeners.push({ event: e, callback: cb }); return this; }, trigger: function trigger(e) { if (is.string(e)) { e = { type: e }; } var matchesEvent = function matchesEvent(l) { return l.event === e.type; }; var trigger = function trigger(l) { l.callback(e); }; this.listeners.filter(matchesEvent).forEach(trigger); return this; }, pass: function pass(data) { this.pass = data; return this; }, run: function run(cb) { var pass = this.pass; return new Promise(function (resolve) { resolve(cb(pass)); }); }, stop: function stop() { return this; }, stopped: function stopped() { return true; } }; function broadcast(message) { // for false thread var e = { type: 'message', message: message }; falseThread.trigger(e); } if (!thread || thread.stopped()) { thread = this.thread = Thread ? new Thread() : falseThread; } layout.stopped = false; if (options.animate === true || options.animate === false) { layout.emit({ type: 'layoutstart', layout: layout }); } // Set DEBUG - Global variable if (true === options.debug) { DEBUG = true; } else { DEBUG = false; } // Initialize layout info var layoutInfo = createLayoutInfo(cy, layout, options); // Show LayoutInfo contents if debugging if (DEBUG) { printLayoutInfo(layoutInfo); } // If required, randomize node positions if (options.randomize) { randomizePositions(layoutInfo, cy); } var startTime = Date.now(); var refreshRequested = false; var refresh = function refresh(rOpts) { rOpts = rOpts || {}; if (refreshRequested && !rOpts.next) { return; } if (!rOpts.force && Date.now() - startTime < options.animationThreshold) { return; } refreshRequested = true; util.requestAnimationFrame(function () { refreshPositions(layoutInfo, cy, options); // Fit the graph if necessary if (true === options.fit) { cy.fit(options.padding); } refreshRequested = false; if (rOpts.next) { rOpts.next(); } }); }; thread.on('message', function (e) { var layoutNodes = e.message; layoutInfo.layoutNodes = layoutNodes; refresh(); }); thread.pass({ layoutInfo: layoutInfo, options: { animate: options.animate, refresh: options.refresh, componentSpacing: options.componentSpacing, nodeOverlap: options.nodeOverlap, nestingFactor: options.nestingFactor, gravity: options.gravity, numIter: options.numIter, initialTemp: options.initialTemp, coolingFactor: options.coolingFactor, minTemp: options.minTemp } }).run(function (pass) { var layoutInfo = pass.layoutInfo; var options = pass.options; var stopped = false; /** * @brief : Performs one iteration of the physical simulation * @arg layoutInfo : LayoutInfo object already initialized * @arg cy : Cytoscape object * @arg options : Layout options */ var step = function step(layoutInfo, options, _step) { // var s = "\n\n###############################"; // s += "\nSTEP: " + step; // s += "\n###############################\n"; // logDebug(s); // Calculate node repulsions calculateNodeForces(layoutInfo, options); // Calculate edge forces calculateEdgeForces(layoutInfo, options); // Calculate gravity forces calculateGravityForces(layoutInfo, options); // Propagate forces from parent to child propagateForces(layoutInfo, options); // Update positions based on calculated forces updatePositions(layoutInfo, options); }; /** * @brief : Computes the node repulsion forces */ var calculateNodeForces = function calculateNodeForces(layoutInfo, options) { // Go through each of the graphs in graphSet // Nodes only repel each other if they belong to the same graph // var s = 'calculateNodeForces'; // logDebug(s); for (var i = 0; i < layoutInfo.graphSet.length; i++) { var graph = layoutInfo.graphSet[i]; var numNodes = graph.length; // s = "Set: " + graph.toString(); // logDebug(s); // Now get all the pairs of nodes // Only get each pair once, (A, B) = (B, A) for (var j = 0; j < numNodes; j++) { var node1 = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[j]]]; for (var k = j + 1; k < numNodes; k++) { var node2 = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[k]]]; nodeRepulsion(node1, node2, layoutInfo, options); } } } }; var randomDistance = function randomDistance(max) { return -max + 2 * max * Math.random(); }; /** * @brief : Compute the node repulsion forces between a pair of nodes */ var nodeRepulsion = function nodeRepulsion(node1, node2, layoutInfo, options) { // var s = "Node repulsion. Node1: " + node1.id + " Node2: " + node2.id; var cmptId1 = node1.cmptId; var cmptId2 = node2.cmptId; if (cmptId1 !== cmptId2 && !layoutInfo.isCompound) { return; } // Get direction of line connecting both node centers var directionX = node2.positionX - node1.positionX; var directionY = node2.positionY - node1.positionY; var maxRandDist = 1; // s += "\ndirectionX: " + directionX + ", directionY: " + directionY; // If both centers are the same, apply a random force if (0 === directionX && 0 === directionY) { directionX = randomDistance(maxRandDist); directionY = randomDistance(maxRandDist); } var overlap = nodesOverlap(node1, node2, directionX, directionY); if (overlap > 0) { // s += "\nNodes DO overlap."; // s += "\nOverlap: " + overlap; // If nodes overlap, repulsion force is proportional // to the overlap var force = options.nodeOverlap * overlap; // Compute the module and components of the force vector var distance = Math.sqrt(directionX * directionX + directionY * directionY); // s += "\nDistance: " + distance; var forceX = force * directionX / distance; var forceY = force * directionY / distance; } else { // s += "\nNodes do NOT overlap."; // If there's no overlap, force is inversely proportional // to squared distance // Get clipping points for both nodes var point1 = findClippingPoint(node1, directionX, directionY); var point2 = findClippingPoint(node2, -1 * directionX, -1 * directionY); // Use clipping points to compute distance var distanceX = point2.x - point1.x; var distanceY = point2.y - point1.y; var distanceSqr = distanceX * distanceX + distanceY * distanceY; var distance = Math.sqrt(distanceSqr); // s += "\nDistance: " + distance; // Compute the module and components of the force vector var force = (node1.nodeRepulsion + node2.nodeRepulsion) / distanceSqr; var forceX = force * distanceX / distance; var forceY = force * distanceY / distance; } // Apply force if (!node1.isLocked) { node1.offsetX -= forceX; node1.offsetY -= forceY; } if (!node2.isLocked) { node2.offsetX += forceX; node2.offsetY += forceY; } // s += "\nForceX: " + forceX + " ForceY: " + forceY; // logDebug(s); return; }; /** * @brief : Determines whether two nodes overlap or not * @return : Amount of overlapping (0 => no overlap) */ var nodesOverlap = function nodesOverlap(node1, node2, dX, dY) { if (dX > 0) { var overlapX = node1.maxX - node2.minX; } else { var overlapX = node2.maxX - node1.minX; } if (dY > 0) { var overlapY = node1.maxY - node2.minY; } else { var overlapY = node2.maxY - node1.minY; } if (overlapX >= 0 && overlapY >= 0) { return Math.sqrt(overlapX * overlapX + overlapY * overlapY); } else { return 0; } }; /** * @brief : Finds the point in which an edge (direction dX, dY) intersects * the rectangular bounding box of it's source/target node */ var findClippingPoint = function findClippingPoint(node, dX, dY) { // Shorcuts var X = node.positionX; var Y = node.positionY; var H = node.height || 1; var W = node.width || 1; var dirSlope = dY / dX; var nodeSlope = H / W; // var s = 'Computing clipping point of node ' + node.id + // " . Height: " + H + ", Width: " + W + // "\nDirection " + dX + ", " + dY; // // Compute intersection var res = {}; // Case: Vertical direction (up) if (0 === dX && 0 < dY) { res.x = X; // s += "\nUp direction"; res.y = Y + H / 2; return res; } // Case: Vertical direction (down) if (0 === dX && 0 > dY) { res.x = X; res.y = Y + H / 2; // s += "\nDown direction"; return res; } // Case: Intersects the right border if (0 < dX && -1 * nodeSlope <= dirSlope && dirSlope <= nodeSlope) { res.x = X + W / 2; res.y = Y + W * dY / 2 / dX; // s += "\nRightborder"; return res; } // Case: Intersects the left border if (0 > dX && -1 * nodeSlope <= dirSlope && dirSlope <= nodeSlope) { res.x = X - W / 2; res.y = Y - W * dY / 2 / dX; // s += "\nLeftborder"; return res; } // Case: Intersects the top border if (0 < dY && (dirSlope <= -1 * nodeSlope || dirSlope >= nodeSlope)) { res.x = X + H * dX / 2 / dY; res.y = Y + H / 2; // s += "\nTop border"; return res; } // Case: Intersects the bottom border if (0 > dY && (dirSlope <= -1 * nodeSlope || dirSlope >= nodeSlope)) { res.x = X - H * dX / 2 / dY; res.y = Y - H / 2; // s += "\nBottom border"; return res; } // s += "\nClipping point found at " + res.x + ", " + res.y; // logDebug(s); return res; }; /** * @brief : Calculates all edge forces */ var calculateEdgeForces = function calculateEdgeForces(layoutInfo, options) { // Iterate over all edges for (var i = 0; i < layoutInfo.edgeSize; i++) { // Get edge, source & target nodes var edge = layoutInfo.layoutEdges[i]; var sourceIx = layoutInfo.idToIndex[edge.sourceId]; var source = layoutInfo.layoutNodes[sourceIx]; var targetIx = layoutInfo.idToIndex[edge.targetId]; var target = layoutInfo.layoutNodes[targetIx]; // Get direction of line connecting both node centers var directionX = target.positionX - source.positionX; var directionY = target.positionY - source.positionY; // If both centers are the same, do nothing. // A random force has already been applied as node repulsion if (0 === directionX && 0 === directionY) { continue; } // Get clipping points for both nodes var point1 = findClippingPoint(source, directionX, directionY); var point2 = findClippingPoint(target, -1 * directionX, -1 * directionY); var lx = point2.x - point1.x; var ly = point2.y - point1.y; var l = Math.sqrt(lx * lx + ly * ly); var force = Math.pow(edge.idealLength - l, 2) / edge.elasticity; if (0 !== l) { var forceX = force * lx / l; var forceY = force * ly / l; } else { var forceX = 0; var forceY = 0; } // Add this force to target and source nodes if (!source.isLocked) { source.offsetX += forceX; source.offsetY += forceY; } if (!target.isLocked) { target.offsetX -= forceX; target.offsetY -= forceY; } // var s = 'Edge force between nodes ' + source.id + ' and ' + target.id; // s += "\nDistance: " + l + " Force: (" + forceX + ", " + forceY + ")"; // logDebug(s); } }; /** * @brief : Computes gravity forces for all nodes */ var calculateGravityForces = function calculateGravityForces(layoutInfo, options) { var distThreshold = 1; // var s = 'calculateGravityForces'; // logDebug(s); for (var i = 0; i < layoutInfo.graphSet.length; i++) { var graph = layoutInfo.graphSet[i]; var numNodes = graph.length; // s = "Set: " + graph.toString(); // logDebug(s); // Compute graph center if (0 === i) { var centerX = layoutInfo.clientHeight / 2; var centerY = layoutInfo.clientWidth / 2; } else { // Get Parent node for this graph, and use its position as center var temp = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[0]]]; var parent = layoutInfo.layoutNodes[layoutInfo.idToIndex[temp.parentId]]; var centerX = parent.positionX; var centerY = parent.positionY; } // s = "Center found at: " + centerX + ", " + centerY; // logDebug(s); // Apply force to all nodes in graph for (var j = 0; j < numNodes; j++) { var node = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[j]]]; // s = "Node: " + node.id; if (node.isLocked) { continue; } var dx = centerX - node.positionX; var dy = centerY - node.positionY; var d = Math.sqrt(dx * dx + dy * dy); if (d > distThreshold) { var fx = options.gravity * dx / d; var fy = options.gravity * dy / d; node.offsetX += fx; node.offsetY += fy; // s += ": Applied force: " + fx + ", " + fy; } else {} // s += ": skypped since it's too close to center"; // logDebug(s); } } }; /** * @brief : This function propagates the existing offsets from * parent nodes to its descendents. * @arg layoutInfo : layoutInfo Object * @arg cy : cytoscape Object * @arg options : Layout options */ var propagateForces = function propagateForces(layoutInfo, options) { // Inline implementation of a queue, used for traversing the graph in BFS order var queue = []; var start = 0; // Points to the start the queue var end = -1; // Points to the end of the queue // logDebug('propagateForces'); // Start by visiting the nodes in the root graph queue.push.apply(queue, layoutInfo.graphSet[0]); end += layoutInfo.graphSet[0].length; // Traverse the graph, level by level, while (start <= end) { // Get the node to visit and remove it from queue var nodeId = queue[start++]; var nodeIndex = layoutInfo.idToIndex[nodeId]; var node = layoutInfo.layoutNodes[nodeIndex]; var children = node.children; // We only need to process the node if it's compound if (0 < children.length && !node.isLocked) { var offX = node.offsetX; var offY = node.offsetY; // var s = "Propagating offset from parent node : " + node.id + // ". OffsetX: " + offX + ". OffsetY: " + offY; // s += "\n Children: " + children.toString(); // logDebug(s); for (var i = 0; i < children.length; i++) { var childNode = layoutInfo.layoutNodes[layoutInfo.idToIndex[children[i]]]; // Propagate offset childNode.offsetX += offX; childNode.offsetY += offY; // Add children to queue to be visited queue[++end] = children[i]; } // Reset parent offsets node.offsetX = 0; node.offsetY = 0; } } }; /** * @brief : Updates the layout model positions, based on * the accumulated forces */ var updatePositions = function updatePositions(layoutInfo, options) { // var s = 'Updating positions'; // logDebug(s); // Reset boundaries for compound nodes for (var i = 0; i < layoutInfo.nodeSize; i++) { var n = layoutInfo.layoutNodes[i]; if (0 < n.children.length) { // logDebug("Resetting boundaries of compound node: " + n.id); n.maxX = undefined; n.minX = undefined; n.maxY = undefined; n.minY = undefined; } } for (var i = 0; i < layoutInfo.nodeSize; i++) { var n = layoutInfo.layoutNodes[i]; if (0 < n.children.length || n.isLocked) { // No need to set compound or locked node position // logDebug("Skipping position update of node: " + n.id); continue; } // s = "Node: " + n.id + " Previous position: (" + // n.positionX + ", " + n.positionY + ")."; // Limit displacement in order to improve stability var tempForce = limitForce(n.offsetX, n.offsetY, layoutInfo.temperature); n.positionX += tempForce.x; n.positionY += tempForce.y; n.offsetX = 0; n.offsetY = 0; n.minX = n.positionX - n.width; n.maxX = n.positionX + n.width; n.minY = n.positionY - n.height; n.maxY = n.positionY + n.height; // s += " New Position: (" + n.positionX + ", " + n.positionY + ")."; // logDebug(s); // Update ancestry boudaries updateAncestryBoundaries(n, layoutInfo); } // Update size, position of compund nodes for (var i = 0; i < layoutInfo.nodeSize; i++) { var n = layoutInfo.layoutNodes[i]; if (0 < n.children.length && !n.isLocked) { n.positionX = (n.maxX + n.minX) / 2; n.positionY = (n.maxY + n.minY) / 2; n.width = n.maxX - n.minX; n.height = n.maxY - n.minY; // s = "Updating position, size of compound node " + n.id; // s += "\nPositionX: " + n.positionX + ", PositionY: " + n.positionY; // s += "\nWidth: " + n.width + ", Height: " + n.height; // logDebug(s); } } }; /** * @brief : Limits a force (forceX, forceY) to be not * greater (in modulo) than max. 8 Preserves force direction. */ var limitForce = function limitForce(forceX, forceY, max) { // var s = "Limiting force: (" + forceX + ", " + forceY + "). Max: " + max; var force = Math.sqrt(forceX * forceX + forceY * forceY); if (force > max) { var res = { x: max * forceX / force, y: max * forceY / force }; } else { var res = { x: forceX, y: forceY }; } // s += ".\nResult: (" + res.x + ", " + res.y + ")"; // logDebug(s); return res; }; /** * @brief : Function used for keeping track of compound node * sizes, since they should bound all their subnodes. */ var updateAncestryBoundaries = function updateAncestryBoundaries(node, layoutInfo) { // var s = "Propagating new position/size of node " + node.id; var parentId = node.parentId; if (null == parentId) { // If there's no parent, we are done // s += ". No parent node."; // logDebug(s); return; } // Get Parent Node var p = layoutInfo.layoutNodes[layoutInfo.idToIndex[parentId]]; var flag = false; // MaxX if (null == p.maxX || node.maxX + p.padRight > p.maxX) { p.maxX = node.maxX + p.padRight; flag = true; // s += "\nNew maxX for parent node " + p.id + ": " + p.maxX; } // MinX if (null == p.minX || node.minX - p.padLeft < p.minX) { p.minX = node.minX - p.padLeft; flag = true; // s += "\nNew minX for parent node " + p.id + ": " + p.minX; } // MaxY if (null == p.maxY || node.maxY + p.padBottom > p.maxY) { p.maxY = node.maxY + p.padBottom; flag = true; // s += "\nNew maxY for parent node " + p.id + ": " + p.maxY; } // MinY if (null == p.minY || node.minY - p.padTop < p.minY) { p.minY = node.minY - p.padTop; flag = true; // s += "\nNew minY for parent node " + p.id + ": " + p.minY; } // If updated boundaries, propagate changes upward if (flag) { // logDebug(s); return updateAncestryBoundaries(p, layoutInfo); } // s += ". No changes in boundaries/position of parent node " + p.id; // logDebug(s); return; }; var separateComponents = function separateComponents(layutInfo, options) { var nodes = layoutInfo.layoutNodes; var components = []; for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; var cid = node.cmptId; var component = components[cid] = components[cid] || []; component.push(node); } var totalA = 0; for (var i = 0; i < components.length; i++) { var c = components[i]; if (!c) { continue; } c.x1 = Infinity; c.x2 = -Infinity; c.y1 = Infinity; c.y2 = -Infinity; for (var j = 0; j < c.length; j++) { var n = c[j]; c.x1 = Math.min(c.x1, n.positionX - n.width / 2); c.x2 = Math.max(c.x2, n.positionX + n.width / 2); c.y1 = Math.min(c.y1, n.positionY - n.height / 2); c.y2 = Math.max(c.y2, n.positionY + n.height / 2); } c.w = c.x2 - c.x1; c.h = c.y2 - c.y1; totalA += c.w * c.h; } components.sort(function (c1, c2) { return c2.w * c2.h - c1.w * c1.h; }); var x = 0; var y = 0; var usedW = 0; var rowH = 0; var maxRowW = Math.sqrt(totalA) * layoutInfo.clientWidth / layoutInfo.clientHeight; for (var i = 0; i < components.length; i++) { var c = components[i]; if (!c) { continue; } for (var j = 0; j < c.length; j++) { var n = c[j]; if (!n.isLocked) { n.positionX += x; n.positionY += y; } } x += c.w + options.componentSpacing; usedW += c.w + options.componentSpacing; rowH = Math.max(rowH, c.h); if (usedW > maxRowW) { y += rowH + options.componentSpacing; x = 0; usedW = 0; rowH = 0; } } }; var mainLoop = function mainLoop(i) { if (stopped) { // logDebug("Layout manually stopped. Stopping computation in step " + i); return false; } // Do one step in the phisical simulation step(layoutInfo, options, i); // Update temperature layoutInfo.temperature = layoutInfo.temperature * options.coolingFactor; // logDebug("New temperature: " + layoutInfo.temperature); if (layoutInfo.temperature < options.minTemp) { // logDebug("Temperature drop below minimum threshold. Stopping computation in step " + i); return false; } return true; }; var i = 0; var loopRet; do { var f = 0; while (f < options.refresh && i < options.numIter) { var loopRet = mainLoop(i); if (!loopRet) { break; } f++; i++; } if (options.animate === true) { broadcast(layoutInfo.layoutNodes); // eslint-disable-line no-undef } } while (loopRet && i + 1 < options.numIter); separateComponents(layoutInfo, options); return layoutInfo; }).then(function (layoutInfoUpdated) { layoutInfo.layoutNodes = layoutInfoUpdated.layoutNodes; // get the positions thread.stop(); done(); }); var done = function done() { if (options.animate === true || options.animate === false) { refresh({ force: true, next: function next() { // Layout has finished layout.one('layoutstop', options.stop); layout.emit({ type: 'layoutstop', layout: layout }); } }); } else { options.eles.nodes().layoutPositions(layout, options, function (node) { var lnode = layoutInfo.layoutNodes[layoutInfo.idToIndex[node.data('id')]]; return { x: lnode.positionX, y: lnode.positionY }; }); } }; return this; // chaining }; /** * @brief : called on continuous layouts to stop them before they finish */ CoseLayout.prototype.stop = function () { this.stopped = true; if (this.thread) { this.thread.stop(); } this.emit('layoutstop'); return this; // chaining }; CoseLayout.prototype.destroy = function () { if (this.thread) { this.thread.stop(); } return this; // chaining }; /** * @brief : Creates an object which is contains all the data * used in the layout process * @arg cy : cytoscape.js object * @return : layoutInfo object initialized */ var createLayoutInfo = function createLayoutInfo(cy, layout, options) { // Shortcut var edges = options.eles.edges(); var nodes = options.eles.nodes(); var layoutInfo = { isCompound: cy.hasCompoundNodes(), layoutNodes: [], idToIndex: {}, nodeSize: nodes.size(), graphSet: [], indexToGraph: [], layoutEdges: [], edgeSize: edges.size(), temperature: options.initialTemp, clientWidth: cy.width(), clientHeight: cy.width(), boundingBox: math.makeBoundingBox(options.boundingBox ? options.boundingBox : { x1: 0, y1: 0, w: cy.width(), h: cy.height() }) }; var components = options.eles.components(); var id2cmptId = {}; for (var i = 0; i < components.length; i++) { var component = components[i]; for (var j = 0; j < component.length; j++) { var node = component[j]; id2cmptId[node.id()] = i; } } // Iterate over all nodes, creating layout nodes for (var i = 0; i < layoutInfo.nodeSize; i++) { var n = nodes[i]; var nbb = n.layoutDimensions(options); var tempNode = {}; tempNode.isLocked = n.locked(); tempNode.id = n.data('id'); tempNode.parentId = n.data('parent'); tempNode.cmptId = id2cmptId[n.id()]; tempNode.children = []; tempNode.positionX = n.position('x'); tempNode.positionY = n.position('y'); tempNode.offsetX = 0; tempNode.offsetY = 0; tempNode.height = nbb.w; tempNode.width = nbb.h; tempNode.maxX = tempNode.positionX + tempNode.width / 2; tempNode.minX = tempNode.positionX - tempNode.width / 2; tempNode.maxY = tempNode.positionY + tempNode.height / 2; tempNode.minY = tempNode.positionY - tempNode.height / 2; tempNode.padLeft = parseFloat(n.style('padding')); tempNode.padRight = parseFloat(n.style('padding')); tempNode.padTop = parseFloat(n.style('padding')); tempNode.padBottom = parseFloat(n.style('padding')); // forces tempNode.nodeRepulsion = is.fn(options.nodeRepulsion) ? options.nodeRepulsion(n) : options.nodeRepulsion; // Add new node layoutInfo.layoutNodes.push(tempNode); // Add entry to id-index map layoutInfo.idToIndex[tempNode.id] = i; } // Inline implementation of a queue, used for traversing the graph in BFS order var queue = []; var start = 0; // Points to the start the queue var end = -1; // Points to the end of the queue var tempGraph = []; // Second pass to add child information and // initialize queue for hierarchical traversal for (var i = 0; i < layoutInfo.nodeSize; i++) { var n = layoutInfo.layoutNodes[i]; var p_id = n.parentId; // Check if node n has a parent node if (null != p_id) { // Add node Id to parent's list of children layoutInfo.layoutNodes[layoutInfo.idToIndex[p_id]].children.push(n.id); } else { // If a node doesn't have a parent, then it's in the root graph queue[++end] = n.id; tempGraph.push(n.id); } } // Add root graph to graphSet layoutInfo.graphSet.push(tempGraph); // Traverse the graph, level by level, while (start <= end) { // Get the node to visit and remove it from queue var node_id = queue[start++]; var node_ix = layoutInfo.idToIndex[node_id]; var node = layoutInfo.layoutNodes[node_ix]; var children = node.children; if (children.length > 0) { // Add children nodes as a new graph to graph set layoutInfo.graphSet.push(children); // Add children to que queue to be visited for (var i = 0; i < children.length; i++) { queue[++end] = children[i]; } } } // Create indexToGraph map for (var i = 0; i < layoutInfo.graphSet.length; i++) { var graph = layoutInfo.graphSet[i]; for (var j = 0; j < graph.length; j++) { var index = layoutInfo.idToIndex[graph[j]]; layoutInfo.indexToGraph[index] = i; } } // Iterate over all edges, creating Layout Edges for (var i = 0; i < layoutInfo.edgeSize; i++) { var e = edges[i]; var tempEdge = {}; tempEdge.id = e.data('id'); tempEdge.sourceId = e.data('source'); tempEdge.targetId = e.data('target'); // Compute ideal length var idealLength = is.fn(options.idealEdgeLength) ? options.idealEdgeLength(e) : options.idealEdgeLength; var elasticity = is.fn(options.edgeElasticity) ? options.edgeElasticity(e) : options.edgeElasticity; // Check if it's an inter graph edge var sourceIx = layoutInfo.idToIndex[tempEdge.sourceId]; var targetIx = layoutInfo.idToIndex[tempEdge.targetId]; var sourceGraph = layoutInfo.indexToGraph[sourceIx]; var targetGraph = layoutInfo.indexToGraph[targetIx]; if (sourceGraph != targetGraph) { // Find lowest common graph ancestor var lca = findLCA(tempEdge.sourceId, tempEdge.targetId, layoutInfo); // Compute sum of node depths, relative to lca graph var lcaGraph = layoutInfo.graphSet[lca]; var depth = 0; // Source depth var tempNode = layoutInfo.layoutNodes[sourceIx]; while (-1 === lcaGraph.indexOf(tempNode.id)) { tempNode = layoutInfo.layoutNodes[layoutInfo.idToIndex[tempNode.parentId]]; depth++; } // Target depth tempNode = layoutInfo.layoutNodes[targetIx]; while (-1 === lcaGraph.indexOf(tempNode.id)) { tempNode = layoutInfo.layoutNodes[layoutInfo.idToIndex[tempNode.parentId]]; depth++; } // logDebug('LCA of nodes ' + tempEdge.sourceId + ' and ' + tempEdge.targetId + // ". Index: " + lca + " Contents: " + lcaGraph.toString() + // ". Depth: " + depth); // Update idealLength idealLength *= depth * options.nestingFactor; } tempEdge.idealLength = idealLength; tempEdge.elasticity = elasticity; layoutInfo.layoutEdges.push(tempEdge); } // Finally, return layoutInfo object return layoutInfo; }; /** * @brief : This function finds the index of the lowest common * graph ancestor between 2 nodes in the subtree * (from the graph hierarchy induced tree) whose * root is graphIx * * @arg node1: node1's ID * @arg node2: node2's ID * @arg layoutInfo: layoutInfo object * */ var findLCA = function findLCA(node1, node2, layoutInfo) { // Find their common ancester, starting from the root graph var res = findLCA_aux(node1, node2, 0, layoutInfo); if (2 > res.count) { // If aux function couldn't find the common ancester, // then it is the root graph return 0; } else { return res.graph; } }; /** * @brief : Auxiliary function used for LCA computation * * @arg node1 : node1's ID * @arg node2 : node2's ID * @arg graphIx : subgraph index * @arg layoutInfo : layoutInfo object * * @return : object of the form {count: X, graph: Y}, where: * X is the number of ancesters (max: 2) found in * graphIx (and it's subgraphs), * Y is the graph index of the lowest graph containing * all X nodes */ var findLCA_aux = function findLCA_aux(node1, node2, graphIx, layoutInfo) { var graph = layoutInfo.graphSet[graphIx]; // If both nodes belongs to graphIx if (-1 < graph.indexOf(node1) && -1 < graph.indexOf(node2)) { return { count: 2, graph: graphIx }; } // Make recursive calls for all subgraphs var c = 0; for (var i = 0; i < graph.length; i++) { var nodeId = graph[i]; var nodeIx = layoutInfo.idToIndex[nodeId]; var children = layoutInfo.layoutNodes[nodeIx].children; // If the node has no child, skip it if (0 === children.length) { continue; } var childGraphIx = layoutInfo.indexToGraph[layoutInfo.idToIndex[children[0]]]; var result = findLCA_aux(node1, node2, childGraphIx, layoutInfo); if (0 === result.count) { // Neither node1 nor node2 are present in this subgraph continue; } else if (1 === result.count) { // One of (node1, node2) is present in this subgraph c++; if (2 === c) { // We've already found both nodes, no need to keep searching break; } } else { // Both nodes are present in this subgraph return result; } } return { count: c, graph: graphIx }; }; /** * @brief: printsLayoutInfo into js console * Only used for debbuging */ var printLayoutInfo = function printLayoutInfo(layoutInfo) { /* eslint-disable */ if (!DEBUG) { return; } console.debug('layoutNodes:'); for (var i = 0; i < layoutInfo.nodeSize; i++) { var n = layoutInfo.layoutNodes[i]; var s = '\nindex: ' + i + '\nId: ' + n.id + '\nChildren: ' + n.children.toString() + '\nparentId: ' + n.parentId + '\npositionX: ' + n.positionX + '\npositionY: ' + n.positionY + '\nOffsetX: ' + n.offsetX + '\nOffsetY: ' + n.offsetY + '\npadLeft: ' + n.padLeft + '\npadRight: ' + n.padRight + '\npadTop: ' + n.padTop + '\npadBottom: ' + n.padBottom; console.debug(s); } console.debug('idToIndex'); for (var i in layoutInfo.idToIndex) { console.debug('Id: ' + i + '\nIndex: ' + layoutInfo.idToIndex[i]); } console.debug('Graph Set'); var set = layoutInfo.graphSet; for (var i = 0; i < set.length; i++) { console.debug('Set : ' + i + ': ' + set[i].toString()); } var s = 'IndexToGraph'; for (var i = 0; i < layoutInfo.indexToGraph.length; i++) { s += '\nIndex : ' + i + ' Graph: ' + layoutInfo.indexToGraph[i]; } console.debug(s); s = 'Layout Edges'; for (var i = 0; i < layoutInfo.layoutEdges.length; i++) { var e = layoutInfo.layoutEdges[i]; s += '\nEdge Index: ' + i + ' ID: ' + e.id + ' SouceID: ' + e.sourceId + ' TargetId: ' + e.targetId + ' Ideal Length: ' + e.idealLength; } console.debug(s); s = 'nodeSize: ' + layoutInfo.nodeSize; s += '\nedgeSize: ' + layoutInfo.edgeSize; s += '\ntemperature: ' + layoutInfo.temperature; console.debug(s); return; /* eslint-enable */ }; /** * @brief : Randomizes the position of all nodes */ var randomizePositions = function randomizePositions(layoutInfo, cy) { var width = layoutInfo.clientWidth; var height = layoutInfo.clientHeight; for (var i = 0; i < layoutInfo.nodeSize; i++) { var n = layoutInfo.layoutNodes[i]; // No need to randomize compound nodes or locked nodes if (0 === n.children.length && !n.isLocked) { n.positionX = Math.random() * width; n.positionY = Math.random() * height; } } }; /** * @brief : Updates the positions of nodes in the network * @arg layoutInfo : LayoutInfo object * @arg cy : Cytoscape object * @arg options : Layout options */ var refreshPositions = function refreshPositions(layoutInfo, cy, options) { // var s = 'Refreshing positions'; // logDebug(s); var layout = options.layout; var nodes = options.eles.nodes(); var bb = layoutInfo.boundingBox; var coseBB = { x1: Infinity, x2: -Infinity, y1: Infinity, y2: -Infinity }; if (options.boundingBox) { nodes.forEach(function (node) { var lnode = layoutInfo.layoutNodes[layoutInfo.idToIndex[node.data('id')]]; coseBB.x1 = Math.min(coseBB.x1, lnode.positionX); coseBB.x2 = Math.max(coseBB.x2, lnode.positionX); coseBB.y1 = Math.min(coseBB.y1, lnode.positionY); coseBB.y2 = Math.max(coseBB.y2, lnode.positionY); }); coseBB.w = coseBB.x2 - coseBB.x1; coseBB.h = coseBB.y2 - coseBB.y1; } nodes.positions(function (ele, i) { var lnode = layoutInfo.layoutNodes[layoutInfo.idToIndex[ele.data('id')]]; // s = "Node: " + lnode.id + ". Refreshed position: (" + // lnode.positionX + ", " + lnode.positionY + ")."; // logDebug(s); if (options.boundingBox) { // then add extra bounding box constraint var pctX = (lnode.positionX - coseBB.x1) / coseBB.w; var pctY = (lnode.positionY - coseBB.y1) / coseBB.h; return { x: bb.x1 + pctX * bb.w, y: bb.y1 + pctY * bb.h }; } else { return { x: lnode.positionX, y: lnode.positionY }; } }); // Trigger layoutReady only on first call if (true !== layoutInfo.ready) { // s = 'Triggering layoutready'; // logDebug(s); layoutInfo.ready = true; layout.one('layoutready', options.ready); layout.emit({ type: 'layoutready', layout: this }); } }; /** * @brief : Logs a debug message in JS console, if DEBUG is ON */ // var logDebug = function(text) { // if (DEBUG) { // console.debug(text); // } // }; module.exports = CoseLayout; /***/ }), /* 102 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var math = __webpack_require__(2); var defaults = { fit: true, // whether to fit the viewport to the graph padding: 30, // padding used on fit boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space avoidOverlapPadding: 10, // extra spacing around nodes when avoidOverlap: true nodeDimensionsIncludeLabels: false, // Excludes the label when calculating node bounding boxes for the layout algorithm spacingFactor: undefined, // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up condense: false, // uses all available space on false, uses minimal space on true rows: undefined, // force num of rows in the grid cols: undefined, // force num of columns in the grid position: function position(node) {}, // returns { row, col } for element sort: undefined, // a sorting function to order the nodes; e.g. function(a, b){ return a.data('weight') - b.data('weight') } animate: false, // whether to transition the node positions animationDuration: 500, // duration of animation in ms if enabled animationEasing: undefined, // easing of animation if enabled animateFilter: function animateFilter(node, i) { return true; }, // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts ready: undefined, // callback on layoutready stop: undefined, // callback on layoutstop transform: function transform(node, position) { return position; } // transform a given node position. Useful for changing flow direction in discrete layouts }; function GridLayout(options) { this.options = util.extend({}, defaults, options); } GridLayout.prototype.run = function () { var params = this.options; var options = params; var cy = params.cy; var eles = options.eles; var nodes = eles.nodes().not(':parent'); if (options.sort) { nodes = nodes.sort(options.sort); } var bb = math.makeBoundingBox(options.boundingBox ? options.boundingBox : { x1: 0, y1: 0, w: cy.width(), h: cy.height() }); if (bb.h === 0 || bb.w === 0) { nodes.layoutPositions(this, options, function (ele) { return { x: bb.x1, y: bb.y1 }; }); } else { // width/height * splits^2 = cells where splits is number of times to split width var cells = nodes.size(); var splits = Math.sqrt(cells * bb.h / bb.w); var rows = Math.round(splits); var cols = Math.round(bb.w / bb.h * splits); var small = function small(val) { if (val == null) { return Math.min(rows, cols); } else { var min = Math.min(rows, cols); if (min == rows) { rows = val; } else { cols = val; } } }; var large = function large(val) { if (val == null) { return Math.max(rows, cols); } else { var max = Math.max(rows, cols); if (max == rows) { rows = val; } else { cols = val; } } }; var oRows = options.rows; var oCols = options.cols != null ? options.cols : options.columns; // if rows or columns were set in options, use those values if (oRows != null && oCols != null) { rows = oRows; cols = oCols; } else if (oRows != null && oCols == null) { rows = oRows; cols = Math.ceil(cells / rows); } else if (oRows == null && oCols != null) { cols = oCols; rows = Math.ceil(cells / cols); } // otherwise use the automatic values and adjust accordingly // if rounding was up, see if we can reduce rows or columns else if (cols * rows > cells) { var sm = small(); var lg = large(); // reducing the small side takes away the most cells, so try it first if ((sm - 1) * lg >= cells) { small(sm - 1); } else if ((lg - 1) * sm >= cells) { large(lg - 1); } } else { // if rounding was too low, add rows or columns while (cols * rows < cells) { var _sm = small(); var _lg = large(); // try to add to larger side first (adds less in multiplication) if ((_lg + 1) * _sm >= cells) { large(_lg + 1); } else { small(_sm + 1); } } } var cellWidth = bb.w / cols; var cellHeight = bb.h / rows; if (options.condense) { cellWidth = 0; cellHeight = 0; } if (options.avoidOverlap) { for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; var pos = node._private.position; if (pos.x == null || pos.y == null) { // for bb pos.x = 0; pos.y = 0; } var nbb = node.layoutDimensions(options); var p = options.avoidOverlapPadding; var w = nbb.w + p; var h = nbb.h + p; cellWidth = Math.max(cellWidth, w); cellHeight = Math.max(cellHeight, h); } } var cellUsed = {}; // e.g. 'c-0-2' => true var used = function used(row, col) { return cellUsed['c-' + row + '-' + col] ? true : false; }; var use = function use(row, col) { cellUsed['c-' + row + '-' + col] = true; }; // to keep track of current cell position var row = 0; var col = 0; var moveToNextCell = function moveToNextCell() { col++; if (col >= cols) { col = 0; row++; } }; // get a cache of all the manual positions var id2manPos = {}; for (var _i = 0; _i < nodes.length; _i++) { var _node = nodes[_i]; var rcPos = options.position(_node); if (rcPos && (rcPos.row !== undefined || rcPos.col !== undefined)) { // must have at least row or col def'd var _pos = { row: rcPos.row, col: rcPos.col }; if (_pos.col === undefined) { // find unused col _pos.col = 0; while (used(_pos.row, _pos.col)) { _pos.col++; } } else if (_pos.row === undefined) { // find unused row _pos.row = 0; while (used(_pos.row, _pos.col)) { _pos.row++; } } id2manPos[_node.id()] = _pos; use(_pos.row, _pos.col); } } var getPos = function getPos(element, i) { var x = void 0, y = void 0; if (element.locked() || element.isParent()) { return false; } // see if we have a manual position set var rcPos = id2manPos[element.id()]; if (rcPos) { x = rcPos.col * cellWidth + cellWidth / 2 + bb.x1; y = rcPos.row * cellHeight + cellHeight / 2 + bb.y1; } else { // otherwise set automatically while (used(row, col)) { moveToNextCell(); } x = col * cellWidth + cellWidth / 2 + bb.x1; y = row * cellHeight + cellHeight / 2 + bb.y1; use(row, col); moveToNextCell(); } return { x: x, y: y }; }; nodes.layoutPositions(this, options, getPos); } return this; // chaining }; module.exports = GridLayout; /***/ }), /* 103 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); // default layout options var defaults = { ready: function ready() {}, // on layoutready stop: function stop() {} // on layoutstop }; // constructor // options : object containing layout options function NullLayout(options) { this.options = util.extend({}, defaults, options); } // runs the layout NullLayout.prototype.run = function () { var options = this.options; var eles = options.eles; // elements to consider in the layout var layout = this; // cy is automatically populated for us in the constructor var cy = options.cy; // jshint ignore:line layout.emit('layoutstart'); // puts all nodes at (0, 0) eles.nodes().positions(function () { return { x: 0, y: 0 }; }); // trigger layoutready when each node has had its position set at least once layout.one('layoutready', options.ready); layout.emit('layoutready'); // trigger layoutstop when the layout stops (e.g. finishes) layout.one('layoutstop', options.stop); layout.emit('layoutstop'); return this; // chaining }; // called on continuous layouts to stop them before they finish NullLayout.prototype.stop = function () { return this; // chaining }; module.exports = NullLayout; /***/ }), /* 104 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var is = __webpack_require__(0); var defaults = { positions: undefined, // map of (node id) => (position obj); or function(node){ return somPos; } zoom: undefined, // the zoom level to set (prob want fit = false if set) pan: undefined, // the pan level to set (prob want fit = false if set) fit: true, // whether to fit to viewport padding: 30, // padding on fit animate: false, // whether to transition the node positions animationDuration: 500, // duration of animation in ms if enabled animationEasing: undefined, // easing of animation if enabled animateFilter: function animateFilter(node, i) { return true; }, // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts ready: undefined, // callback on layoutready stop: undefined, // callback on layoutstop transform: function transform(node, position) { return position; } // transform a given node position. Useful for changing flow direction in discrete layouts }; function PresetLayout(options) { this.options = util.extend({}, defaults, options); } PresetLayout.prototype.run = function () { var options = this.options; var eles = options.eles; var nodes = eles.nodes(); var posIsFn = is.fn(options.positions); function getPosition(node) { if (options.positions == null) { return null; } if (posIsFn) { return options.positions(node); } var pos = options.positions[node._private.data.id]; if (pos == null) { return null; } return pos; } nodes.layoutPositions(this, options, function (node, i) { var position = getPosition(node); if (node.locked() || position == null) { return false; } return position; }); return this; // chaining }; module.exports = PresetLayout; /***/ }), /* 105 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var math = __webpack_require__(2); var defaults = { fit: true, // whether to fit to viewport padding: 30, // fit padding boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } animate: false, // whether to transition the node positions animationDuration: 500, // duration of animation in ms if enabled animationEasing: undefined, // easing of animation if enabled animateFilter: function animateFilter(node, i) { return true; }, // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts ready: undefined, // callback on layoutready stop: undefined, // callback on layoutstop transform: function transform(node, position) { return position; } // transform a given node position. Useful for changing flow direction in discrete layouts }; function RandomLayout(options) { this.options = util.extend({}, defaults, options); } RandomLayout.prototype.run = function () { var options = this.options; var cy = options.cy; var eles = options.eles; var nodes = eles.nodes().not(':parent'); var bb = math.makeBoundingBox(options.boundingBox ? options.boundingBox : { x1: 0, y1: 0, w: cy.width(), h: cy.height() }); var getPos = function getPos(node, i) { return { x: bb.x1 + Math.round(Math.random() * bb.w), y: bb.y1 + Math.round(Math.random() * bb.h) }; }; nodes.layoutPositions(this, options, getPos); return this; // chaining }; module.exports = RandomLayout; /***/ }), /* 106 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; module.exports = [{ name: 'null', impl: __webpack_require__(107) }, { name: 'base', impl: __webpack_require__(108) }, { name: 'canvas', impl: __webpack_require__(124) }]; /***/ }), /* 107 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; function NullRenderer(options) { this.options = options; this.notifications = 0; // for testing } var noop = function noop() {}; NullRenderer.prototype = { recalculateRenderedStyle: noop, notify: function notify() { this.notifications++; }, init: noop }; module.exports = NullRenderer; /***/ }), /* 108 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var util = __webpack_require__(1); var window = __webpack_require__(3); var BaseRenderer = function BaseRenderer(options) { this.init(options); }; var BR = BaseRenderer; var BRp = BR.prototype; BRp.clientFunctions = ['redrawHint', 'render', 'renderTo', 'matchCanvasSize', 'nodeShapeImpl', 'arrowShapeImpl']; BRp.init = function (options) { var r = this; r.options = options; r.cy = options.cy; var ctr = r.container = options.cy.container(); // prepend a stylesheet in the head such that if (window) { var document = window.document; var head = document.head; var stylesheetId = '__________cytoscape_stylesheet'; var className = '__________cytoscape_container'; var stylesheetAlreadyExists = document.getElementById(stylesheetId) != null; if (ctr.className.indexOf(className) < 0) { ctr.className = (ctr.className || '') + ' ' + className; } if (!stylesheetAlreadyExists) { var stylesheet = document.createElement('style'); stylesheet.id = stylesheetId; stylesheet.innerHTML = '.' + className + ' { position: relative; }'; head.insertBefore(stylesheet, head.children[0]); // first so lowest priority } var computedStyle = window.getComputedStyle(ctr); var position = computedStyle.getPropertyValue('position'); if (position === 'static') { util.error('A Cytoscape container has style position:static and so can not use UI extensions properly'); } } r.selection = [undefined, undefined, undefined, undefined, 0]; // Coordinates for selection box, plus enabled flag r.bezierProjPcts = [0.05, 0.225, 0.4, 0.5, 0.6, 0.775, 0.95]; //--Pointer-related data r.hoverData = { down: null, last: null, downTime: null, triggerMode: null, dragging: false, initialPan: [null, null], capture: false }; r.dragData = { possibleDragElements: [] }; r.touchData = { start: null, capture: false, // These 3 fields related to tap, taphold events startPosition: [null, null, null, null, null, null], singleTouchStartTime: null, singleTouchMoved: true, now: [null, null, null, null, null, null], earlier: [null, null, null, null, null, null] }; r.redraws = 0; r.showFps = options.showFps; r.debug = options.debug; r.hideEdgesOnViewport = options.hideEdgesOnViewport; r.hideLabelsOnViewport = options.hideLabelsOnViewport; r.textureOnViewport = options.textureOnViewport; r.wheelSensitivity = options.wheelSensitivity; r.motionBlurEnabled = options.motionBlur; // on by default r.forcedPixelRatio = options.pixelRatio; r.motionBlur = options.motionBlur; // for initial kick off r.motionBlurOpacity = options.motionBlurOpacity; r.motionBlurTransparency = 1 - r.motionBlurOpacity; r.motionBlurPxRatio = 1; r.mbPxRBlurry = 1; //0.8; r.minMbLowQualFrames = 4; r.fullQualityMb = false; r.clearedForMotionBlur = []; r.desktopTapThreshold = options.desktopTapThreshold; r.desktopTapThreshold2 = options.desktopTapThreshold * options.desktopTapThreshold; r.touchTapThreshold = options.touchTapThreshold; r.touchTapThreshold2 = options.touchTapThreshold * options.touchTapThreshold; r.tapholdDuration = 500; r.bindings = []; r.beforeRenderCallbacks = []; r.beforeRenderPriorities = { // higher priority execs before lower one animations: 400, eleCalcs: 300, eleTxrDeq: 200, lyrTxrDeq: 100 }; r.registerNodeShapes(); r.registerArrowShapes(); r.registerCalculationListeners(); }; BRp.notify = function (params) { var types; var r = this; // the renderer can't be notified after it's destroyed if (this.destroyed) { return; } if (is.array(params.type)) { types = params.type; } else { types = [params.type]; } var has = {}; for (var i = 0; i < types.length; i++) { var type = types[i]; has[type] = true; } // for if (has['init']) { r.load(); return; } if (has['destroy']) { r.destroy(); return; } if (has['add'] || has['remove'] || has['load'] || has['zorder']) { r.invalidateCachedZSortedEles(); } if (has['viewport']) { r.redrawHint('select', true); } if (has['load'] || has['resize']) { r.invalidateContainerClientCoordsCache(); r.matchCanvasSize(r.container); } r.redrawHint('eles', true); r.redrawHint('drag', true); this.startRenderLoop(); this.redraw(); }; BRp.destroy = function () { var r = this; r.destroyed = true; r.cy.stopAnimationLoop(); for (var i = 0; i < r.bindings.length; i++) { var binding = r.bindings[i]; var b = binding; var tgt = b.target; (tgt.off || tgt.removeEventListener).apply(tgt, b.args); } r.bindings = []; r.beforeRenderCallbacks = []; r.onUpdateEleCalcsFns = []; if (r.removeObserver) { r.removeObserver.disconnect(); } if (r.styleObserver) { r.styleObserver.disconnect(); } if (r.labelCalcDiv) { try { document.body.removeChild(r.labelCalcDiv); // eslint-disable-line no-undef } catch (e) { // ie10 issue #1014 } } }; [__webpack_require__(109), __webpack_require__(110), __webpack_require__(120), __webpack_require__(121), __webpack_require__(122), __webpack_require__(123)].forEach(function (props) { util.extend(BRp, props); }); module.exports = BR; /***/ }), /* 109 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var math = __webpack_require__(2); var is = __webpack_require__(0); var util = __webpack_require__(1); var BRp = {}; BRp.arrowShapeWidth = 0.3; BRp.registerArrowShapes = function () { var arrowShapes = this.arrowShapes = {}; var renderer = this; // Contract for arrow shapes: // 0, 0 is arrow tip // (0, 1) is direction towards node // (1, 0) is right // // functional api: // collide: check x, y in shape // roughCollide: called before collide, no false negatives // draw: draw // spacing: dist(arrowTip, nodeBoundary) // gap: dist(edgeTip, nodeBoundary), edgeTip may != arrowTip var bbCollide = function bbCollide(x, y, size, angle, translation, edgeWidth, padding) { var x1 = translation.x - size / 2 - padding; var x2 = translation.x + size / 2 + padding; var y1 = translation.y - size / 2 - padding; var y2 = translation.y + size / 2 + padding; var inside = x1 <= x && x <= x2 && y1 <= y && y <= y2; return inside; }; var transform = function transform(x, y, size, angle, translation) { var xRotated = x * Math.cos(angle) - y * Math.sin(angle); var yRotated = x * Math.sin(angle) + y * Math.cos(angle); var xScaled = xRotated * size; var yScaled = yRotated * size; var xTranslated = xScaled + translation.x; var yTranslated = yScaled + translation.y; return { x: xTranslated, y: yTranslated }; }; var transformPoints = function transformPoints(pts, size, angle, translation) { var retPts = []; for (var i = 0; i < pts.length; i += 2) { var x = pts[i]; var y = pts[i + 1]; retPts.push(transform(x, y, size, angle, translation)); } return retPts; }; var pointsToArr = function pointsToArr(pts) { var ret = []; for (var i = 0; i < pts.length; i++) { var p = pts[i]; ret.push(p.x, p.y); } return ret; }; var standardGap = function standardGap(edge) { return edge.pstyle('width').pfValue * edge.pstyle('arrow-scale').pfValue * 2; }; var defineArrowShape = function defineArrowShape(name, defn) { if (is.string(defn)) { defn = arrowShapes[defn]; } arrowShapes[name] = util.extend({ name: name, points: [-0.15, -0.3, 0.15, -0.3, 0.15, 0.3, -0.15, 0.3], collide: function collide(x, y, size, angle, translation, padding) { var points = pointsToArr(transformPoints(this.points, size + 2 * padding, angle, translation)); var inside = math.pointInsidePolygonPoints(x, y, points); return inside; }, roughCollide: bbCollide, draw: function draw(context, size, angle, translation) { var points = transformPoints(this.points, size, angle, translation); renderer.arrowShapeImpl('polygon')(context, points); }, spacing: function spacing(edge) { return 0; }, gap: standardGap }, defn); }; defineArrowShape('none', { collide: util.falsify, roughCollide: util.falsify, draw: util.noop, spacing: util.zeroify, gap: util.zeroify }); defineArrowShape('triangle', { points: [-0.15, -0.3, 0, 0, 0.15, -0.3] }); defineArrowShape('arrow', 'triangle'); defineArrowShape('triangle-backcurve', { points: arrowShapes['triangle'].points, controlPoint: [0, -0.15], roughCollide: bbCollide, draw: function draw(context, size, angle, translation, edgeWidth) { var ptsTrans = transformPoints(this.points, size, angle, translation); var ctrlPt = this.controlPoint; var ctrlPtTrans = transform(ctrlPt[0], ctrlPt[1], size, angle, translation); renderer.arrowShapeImpl(this.name)(context, ptsTrans, ctrlPtTrans); }, gap: function gap(edge) { return standardGap(edge) * 0.8; } }); defineArrowShape('triangle-tee', { points: [-0.15, -0.3, 0, 0, 0.15, -0.3, -0.15, -0.3], pointsTee: [-0.15, -0.4, -0.15, -0.5, 0.15, -0.5, 0.15, -0.4], collide: function collide(x, y, size, angle, translation, edgeWidth, padding) { var triPts = pointsToArr(transformPoints(this.points, size + 2 * padding, angle, translation)); var teePts = pointsToArr(transformPoints(this.pointsTee, size + 2 * padding, angle, translation)); var inside = math.pointInsidePolygonPoints(x, y, triPts) || math.pointInsidePolygonPoints(x, y, teePts); return inside; }, draw: function draw(context, size, angle, translation, edgeWidth) { var triPts = transformPoints(this.points, size, angle, translation); var teePts = transformPoints(this.pointsTee, size, angle, translation); renderer.arrowShapeImpl(this.name)(context, triPts, teePts); } }); defineArrowShape('triangle-cross', { points: [-0.15, -0.3, 0, 0, 0.15, -0.3, -0.15, -0.3], baseCrossLinePts: [-0.15, -0.4, // first half of the rectangle -0.15, -0.4, 0.15, -0.4, // second half of the rectangle 0.15, -0.4], crossLinePts: function crossLinePts(size, edgeWidth) { // shift points so that the distance between the cross points matches edge width var p = this.baseCrossLinePts.slice(); var shiftFactor = edgeWidth / size; var y0 = 3; var y1 = 5; p[y0] = p[y0] - shiftFactor; p[y1] = p[y1] - shiftFactor; return p; }, collide: function collide(x, y, size, angle, translation, edgeWidth, padding) { var triPts = pointsToArr(transformPoints(this.points, size + 2 * padding, angle, translation)); var teePts = pointsToArr(transformPoints(this.crossLinePts(size, edgeWidth), size + 2 * padding, angle, translation)); var inside = math.pointInsidePolygonPoints(x, y, triPts) || math.pointInsidePolygonPoints(x, y, teePts); return inside; }, draw: function draw(context, size, angle, translation, edgeWidth) { var triPts = transformPoints(this.points, size, angle, translation); var crossLinePts = transformPoints(this.crossLinePts(size, edgeWidth), size, angle, translation); renderer.arrowShapeImpl(this.name)(context, triPts, crossLinePts); } }); defineArrowShape('vee', { points: [-0.15, -0.3, 0, 0, 0.15, -0.3, 0, -0.15], gap: function gap(edge) { return standardGap(edge) * 0.525; } }); defineArrowShape('circle', { radius: 0.15, collide: function collide(x, y, size, angle, translation, edgeWidth, padding) { var t = translation; var inside = Math.pow(t.x - x, 2) + Math.pow(t.y - y, 2) <= Math.pow((size + 2 * padding) * this.radius, 2); return inside; }, draw: function draw(context, size, angle, translation, edgeWidth) { renderer.arrowShapeImpl(this.name)(context, translation.x, translation.y, this.radius * size); }, spacing: function spacing(edge) { return renderer.getArrowWidth(edge.pstyle('width').pfValue, edge.pstyle('arrow-scale').value) * this.radius; } }); defineArrowShape('tee', { points: [-0.15, 0, -0.15, -0.1, 0.15, -0.1, 0.15, 0], spacing: function spacing(edge) { return 1; }, gap: function gap(edge) { return 1; } }); defineArrowShape('square', { points: [-0.15, 0.00, 0.15, 0.00, 0.15, -0.3, -0.15, -0.3] }); defineArrowShape('diamond', { points: [-0.15, -0.15, 0, -0.3, 0.15, -0.15, 0, 0], gap: function gap(edge) { return edge.pstyle('width').pfValue * edge.pstyle('arrow-scale').value; } }); }; module.exports = BRp; /***/ }), /* 110 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var BRp = {}; [__webpack_require__(111), __webpack_require__(112), __webpack_require__(113), __webpack_require__(114), __webpack_require__(115), __webpack_require__(116), __webpack_require__(117), __webpack_require__(118), __webpack_require__(119)].forEach(function (props) { util.extend(BRp, props); }); module.exports = BRp; /***/ }), /* 111 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var window = __webpack_require__(3); var math = __webpack_require__(2); var util = __webpack_require__(1); var window = __webpack_require__(3); var BRp = {}; // Project mouse BRp.projectIntoViewport = function (clientX, clientY) { var cy = this.cy; var offsets = this.findContainerClientCoords(); var offsetLeft = offsets[0]; var offsetTop = offsets[1]; var scale = offsets[4]; var pan = cy.pan(); var zoom = cy.zoom(); var x = ((clientX - offsetLeft) / scale - pan.x) / zoom; var y = ((clientY - offsetTop) / scale - pan.y) / zoom; return [x, y]; }; BRp.findContainerClientCoords = function () { if (this.containerBB) { return this.containerBB; } var container = this.container; var rect = container.getBoundingClientRect(); var style = window.getComputedStyle(container); var styleValue = function styleValue(name) { return parseFloat(style.getPropertyValue(name)); }; var padding = { left: styleValue('padding-left'), right: styleValue('padding-right'), top: styleValue('padding-top'), bottom: styleValue('padding-bottom') }; var border = { left: styleValue('border-left-width'), right: styleValue('border-right-width'), top: styleValue('border-top-width'), bottom: styleValue('border-bottom-width') }; var clientWidth = container.clientWidth; var clientHeight = container.clientHeight; var paddingHor = padding.left + padding.right; var paddingVer = padding.top + padding.bottom; var borderHor = border.left + border.right; var borderVer = border.top + border.bottom; var scale = rect.width / (clientWidth + borderHor); var unscaledW = clientWidth - paddingHor; var unscaledH = clientHeight - paddingVer; var scaledW = rect.width - (paddingHor + borderHor) * scale; var scaledH = rect.height - (paddingVer + borderVer) * scale; var left = rect.left + padding.left + border.left; var top = rect.top + padding.top + border.top; return this.containerBB = [left, top, unscaledW, unscaledH, scale]; }; BRp.invalidateContainerClientCoordsCache = function () { this.containerBB = null; }; BRp.findNearestElement = function (x, y, interactiveElementsOnly, isTouch) { return this.findNearestElements(x, y, interactiveElementsOnly, isTouch)[0]; }; BRp.findNearestElements = function (x, y, interactiveElementsOnly, isTouch) { var self = this; var r = this; var eles = r.getCachedZSortedEles(); var near = []; // 1 node max, 1 edge max var zoom = r.cy.zoom(); var hasCompounds = r.cy.hasCompoundNodes(); var edgeThreshold = (isTouch ? 24 : 8) / zoom; var nodeThreshold = (isTouch ? 8 : 2) / zoom; var labelThreshold = (isTouch ? 8 : 2) / zoom; var minSqDist = Infinity; var nearEdge; var nearNode; if (interactiveElementsOnly) { eles = eles.interactive; } function addEle(ele, sqDist) { if (ele.isNode()) { if (nearNode) { return; // can't replace node } else { nearNode = ele; near.push(ele); } } if (ele.isEdge() && (sqDist == null || sqDist < minSqDist)) { if (nearEdge) { // then replace existing edge // can replace only if same z-index if (nearEdge.pstyle('z-compound-depth').value === ele.pstyle('z-compound-depth').value && nearEdge.pstyle('z-compound-depth').value === ele.pstyle('z-compound-depth').value) { for (var i = 0; i < near.length; i++) { if (near[i].isEdge()) { near[i] = ele; nearEdge = ele; minSqDist = sqDist != null ? sqDist : minSqDist; break; } } } } else { near.push(ele); nearEdge = ele; minSqDist = sqDist != null ? sqDist : minSqDist; } } } function checkNode(node) { var width = node.outerWidth() + 2 * nodeThreshold; var height = node.outerHeight() + 2 * nodeThreshold; var hw = width / 2; var hh = height / 2; var pos = node.position(); if (pos.x - hw <= x && x <= pos.x + hw // bb check x && pos.y - hh <= y && y <= pos.y + hh // bb check y ) { var shape = r.nodeShapes[self.getNodeShape(node)]; if (shape.checkPoint(x, y, 0, width, height, pos.x, pos.y)) { addEle(node, 0); return true; } } } function checkEdge(edge) { var _p = edge._private; var rs = _p.rscratch; var styleWidth = edge.pstyle('width').pfValue; var scale = edge.pstyle('arrow-scale').value; var width = styleWidth / 2 + edgeThreshold; // more like a distance radius from centre var widthSq = width * width; var width2 = width * 2; var src = _p.source; var tgt = _p.target; var inEdgeBB = false; var sqDist; if (rs.edgeType === 'segments' || rs.edgeType === 'straight' || rs.edgeType === 'haystack') { var pts = rs.allpts; for (var i = 0; i + 3 < pts.length; i += 2) { if ((inEdgeBB = math.inLineVicinity(x, y, pts[i], pts[i + 1], pts[i + 2], pts[i + 3], width2)) && widthSq > (sqDist = math.sqdistToFiniteLine(x, y, pts[i], pts[i + 1], pts[i + 2], pts[i + 3]))) { addEle(edge, sqDist); return true; } } } else if (rs.edgeType === 'bezier' || rs.edgeType === 'multibezier' || rs.edgeType === 'self' || rs.edgeType === 'compound') { var pts = rs.allpts; for (var i = 0; i + 5 < rs.allpts.length; i += 4) { if ((inEdgeBB = math.inBezierVicinity(x, y, pts[i], pts[i + 1], pts[i + 2], pts[i + 3], pts[i + 4], pts[i + 5], width2)) && widthSq > (sqDist = math.sqdistToQuadraticBezier(x, y, pts[i], pts[i + 1], pts[i + 2], pts[i + 3], pts[i + 4], pts[i + 5]))) { addEle(edge, sqDist); return true; } } } // if we're close to the edge but didn't hit it, maybe we hit its arrows var src = src || _p.source; var tgt = tgt || _p.target; var arSize = self.getArrowWidth(styleWidth, scale); var arrows = [{ name: 'source', x: rs.arrowStartX, y: rs.arrowStartY, angle: rs.srcArrowAngle }, { name: 'target', x: rs.arrowEndX, y: rs.arrowEndY, angle: rs.tgtArrowAngle }, { name: 'mid-source', x: rs.midX, y: rs.midY, angle: rs.midsrcArrowAngle }, { name: 'mid-target', x: rs.midX, y: rs.midY, angle: rs.midtgtArrowAngle }]; for (var i = 0; i < arrows.length; i++) { var ar = arrows[i]; var shape = r.arrowShapes[edge.pstyle(ar.name + '-arrow-shape').value]; var edgeWidth = edge.pstyle('width').pfValue; if (shape.roughCollide(x, y, arSize, ar.angle, { x: ar.x, y: ar.y }, edgeWidth, edgeThreshold) && shape.collide(x, y, arSize, ar.angle, { x: ar.x, y: ar.y }, edgeWidth, edgeThreshold)) { addEle(edge); return true; } } // for compound graphs, hitting edge may actually want a connected node instead (b/c edge may have greater z-index precedence) if (hasCompounds && near.length > 0) { checkNode(src); checkNode(tgt); } } function preprop(obj, name, pre) { return util.getPrefixedProperty(obj, name, pre); } function checkLabel(ele, prefix) { var _p = ele._private; var th = labelThreshold; var prefixDash; if (prefix) { prefixDash = prefix + '-'; } else { prefixDash = ''; } var text = ele.pstyle(prefixDash + 'label').value; var eventsEnabled = ele.pstyle('text-events').strValue === 'yes'; if (!eventsEnabled || !text) { return; } var rstyle = _p.rstyle; var bw = ele.pstyle('text-border-width').pfValue; var pw = ele.pstyle('text-background-padding').pfValue; var lw = preprop(rstyle, 'labelWidth', prefix) + bw + 2 * th + 2 * pw; var lh = preprop(rstyle, 'labelHeight', prefix) + bw + 2 * th + 2 * pw; var lx = preprop(rstyle, 'labelX', prefix); var ly = preprop(rstyle, 'labelY', prefix); var theta = preprop(_p.rscratch, 'labelAngle', prefix); var lx1 = lx - lw / 2; var lx2 = lx + lw / 2; var ly1 = ly - lh / 2; var ly2 = ly + lh / 2; if (theta) { var cos = Math.cos(theta); var sin = Math.sin(theta); var rotate = function rotate(x, y) { x = x - lx; y = y - ly; return { x: x * cos - y * sin + lx, y: x * sin + y * cos + ly }; }; var px1y1 = rotate(lx1, ly1); var px1y2 = rotate(lx1, ly2); var px2y1 = rotate(lx2, ly1); var px2y2 = rotate(lx2, ly2); var points = [px1y1.x, px1y1.y, px2y1.x, px2y1.y, px2y2.x, px2y2.y, px1y2.x, px1y2.y]; if (math.pointInsidePolygonPoints(x, y, points)) { addEle(ele); return true; } } else { // do a cheaper bb check var bb = { w: lw, h: lh, x1: lx1, x2: lx2, y1: ly1, y2: ly2 }; if (math.inBoundingBox(bb, x, y)) { addEle(ele); return true; } } } for (var i = eles.length - 1; i >= 0; i--) { // reverse order for precedence var ele = eles[i]; if (ele.isNode()) { checkNode(ele) || checkLabel(ele); } else { // then edge checkEdge(ele) || checkLabel(ele) || checkLabel(ele, 'source') || checkLabel(ele, 'target'); } } return near; }; // 'Give me everything from this box' BRp.getAllInBox = function (x1, y1, x2, y2) { var eles = this.getCachedZSortedEles().interactive; var box = []; var x1c = Math.min(x1, x2); var x2c = Math.max(x1, x2); var y1c = Math.min(y1, y2); var y2c = Math.max(y1, y2); x1 = x1c; x2 = x2c; y1 = y1c; y2 = y2c; var boxBb = math.makeBoundingBox({ x1: x1, y1: y1, x2: x2, y2: y2 }); for (var e = 0; e < eles.length; e++) { var ele = eles[e]; if (ele.isNode()) { var node = ele; var nodeBb = node.boundingBox({ includeNodes: true, includeEdges: false, includeLabels: false }); if (math.boundingBoxesIntersect(boxBb, nodeBb) && !math.boundingBoxInBoundingBox(nodeBb, boxBb)) { box.push(node); } } else { var edge = ele; var _p = edge._private; var rs = _p.rscratch; if (rs.startX != null && rs.startY != null && !math.inBoundingBox(boxBb, rs.startX, rs.startY)) { continue; } if (rs.endX != null && rs.endY != null && !math.inBoundingBox(boxBb, rs.endX, rs.endY)) { continue; } if (rs.edgeType === 'bezier' || rs.edgeType === 'multibezier' || rs.edgeType === 'self' || rs.edgeType === 'compound' || rs.edgeType === 'segments' || rs.edgeType === 'haystack') { var pts = _p.rstyle.bezierPts || _p.rstyle.linePts || _p.rstyle.haystackPts; var allInside = true; for (var i = 0; i < pts.length; i++) { if (!math.pointInBoundingBox(boxBb, pts[i])) { allInside = false; break; } } if (allInside) { box.push(edge); } } else if (rs.edgeType === 'haystack' || rs.edgeType === 'straight') { box.push(edge); } } } return box; }; module.exports = BRp; /***/ }), /* 112 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var math = __webpack_require__(2); var BRp = {}; BRp.calculateArrowAngles = function (edge) { var rs = edge._private.rscratch; var isHaystack = rs.edgeType === 'haystack'; var isBezier = rs.edgeType === 'bezier'; var isMultibezier = rs.edgeType === 'multibezier'; var isSegments = rs.edgeType === 'segments'; var isCompound = rs.edgeType === 'compound'; var isSelf = rs.edgeType === 'self'; // Displacement gives direction for arrowhead orientation var dispX, dispY; var startX, startY, endX, endY, midX, midY; if (isHaystack) { startX = rs.haystackPts[0]; startY = rs.haystackPts[1]; endX = rs.haystackPts[2]; endY = rs.haystackPts[3]; } else { startX = rs.arrowStartX; startY = rs.arrowStartY; endX = rs.arrowEndX; endY = rs.arrowEndY; } midX = rs.midX; midY = rs.midY; // source // if (isSegments) { dispX = startX - rs.segpts[0]; dispY = startY - rs.segpts[1]; } else if (isMultibezier || isCompound || isSelf || isBezier) { var pts = rs.allpts; var bX = math.qbezierAt(pts[0], pts[2], pts[4], 0.1); var bY = math.qbezierAt(pts[1], pts[3], pts[5], 0.1); dispX = startX - bX; dispY = startY - bY; } else { dispX = startX - midX; dispY = startY - midY; } rs.srcArrowAngle = math.getAngleFromDisp(dispX, dispY); // mid target // var midX = rs.midX; var midY = rs.midY; if (isHaystack) { midX = (startX + endX) / 2; midY = (startY + endY) / 2; } dispX = endX - startX; dispY = endY - startY; if (isSegments) { var pts = rs.allpts; if (pts.length / 2 % 2 === 0) { var i2 = pts.length / 2; var i1 = i2 - 2; dispX = pts[i2] - pts[i1]; dispY = pts[i2 + 1] - pts[i1 + 1]; } else { var i2 = pts.length / 2 - 1; var i1 = i2 - 2; var i3 = i2 + 2; dispX = pts[i2] - pts[i1]; dispY = pts[i2 + 1] - pts[i1 + 1]; } } else if (isMultibezier || isCompound || isSelf) { var pts = rs.allpts; var cpts = rs.ctrlpts; var bp0x, bp0y; var bp1x, bp1y; if (cpts.length / 2 % 2 === 0) { var p0 = pts.length / 2 - 1; // startpt var ic = p0 + 2; var p1 = ic + 2; bp0x = math.qbezierAt(pts[p0], pts[ic], pts[p1], 0.0); bp0y = math.qbezierAt(pts[p0 + 1], pts[ic + 1], pts[p1 + 1], 0.0); bp1x = math.qbezierAt(pts[p0], pts[ic], pts[p1], 0.0001); bp1y = math.qbezierAt(pts[p0 + 1], pts[ic + 1], pts[p1 + 1], 0.0001); } else { var ic = pts.length / 2 - 1; // ctrpt var p0 = ic - 2; // startpt var p1 = ic + 2; // endpt bp0x = math.qbezierAt(pts[p0], pts[ic], pts[p1], 0.4999); bp0y = math.qbezierAt(pts[p0 + 1], pts[ic + 1], pts[p1 + 1], 0.4999); bp1x = math.qbezierAt(pts[p0], pts[ic], pts[p1], 0.5); bp1y = math.qbezierAt(pts[p0 + 1], pts[ic + 1], pts[p1 + 1], 0.5); } dispX = bp1x - bp0x; dispY = bp1y - bp0y; } rs.midtgtArrowAngle = math.getAngleFromDisp(dispX, dispY); rs.midDispX = dispX; rs.midDispY = dispY; // mid source // dispX *= -1; dispY *= -1; if (isSegments) { var pts = rs.allpts; if (pts.length / 2 % 2 === 0) { // already ok } else { var i2 = pts.length / 2 - 1; var i3 = i2 + 2; dispX = -(pts[i3] - pts[i2]); dispY = -(pts[i3 + 1] - pts[i2 + 1]); } } rs.midsrcArrowAngle = math.getAngleFromDisp(dispX, dispY); // target // if (isSegments) { dispX = endX - rs.segpts[rs.segpts.length - 2]; dispY = endY - rs.segpts[rs.segpts.length - 1]; } else if (isMultibezier || isCompound || isSelf || isBezier) { var pts = rs.allpts; var l = pts.length; var bX = math.qbezierAt(pts[l - 6], pts[l - 4], pts[l - 2], 0.9); var bY = math.qbezierAt(pts[l - 5], pts[l - 3], pts[l - 1], 0.9); dispX = endX - bX; dispY = endY - bY; } else { dispX = endX - midX; dispY = endY - midY; } rs.tgtArrowAngle = math.getAngleFromDisp(dispX, dispY); }; BRp.getArrowWidth = BRp.getArrowHeight = function (edgeWidth, scale) { var cache = this.arrowWidthCache = this.arrowWidthCache || {}; var cachedVal = cache[edgeWidth + ', ' + scale]; if (cachedVal) { return cachedVal; } cachedVal = Math.max(Math.pow(edgeWidth * 13.37, 0.9), 29) * scale; cache[edgeWidth + ', ' + scale] = cachedVal; return cachedVal; }; module.exports = BRp; /***/ }), /* 113 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var math = __webpack_require__(2); var is = __webpack_require__(0); var BRp = {}; BRp.findEdgeControlPoints = function (edges) { if (!edges || edges.length === 0) { return; } var r = this; var cy = r.cy; var hasCompounds = cy.hasCompoundNodes(); var hashTable = {}; var pairIds = []; var haystackEdges = []; // create a table of edge (src, tgt) => list of edges between them var pairId; for (var i = 0; i < edges.length; i++) { var edge = edges[i]; var _p = edge._private; var data = _p.data; var curveStyle = edge.pstyle('curve-style').value; var edgeIsUnbundled = curveStyle === 'unbundled-bezier' || curveStyle === 'segments'; var edgeIsBezier = curveStyle === 'unbundled-bezier' || curveStyle === 'bezier'; // ignore edges who are not to be displayed // they shouldn't take up space if (edge.pstyle('display').value === 'none') { continue; } if (curveStyle === 'haystack') { haystackEdges.push(edge); continue; } var srcId = data.source; var tgtId = data.target; pairId = srcId > tgtId ? tgtId + '$-$' + srcId : srcId + '$-$' + tgtId; if (edgeIsUnbundled) { pairId = 'unbundled' + '$-$' + data.id; } var tableEntry = hashTable[pairId]; if (tableEntry == null) { tableEntry = hashTable[pairId] = []; pairIds.push(pairId); } tableEntry.push(edge); if (edgeIsUnbundled) { tableEntry.hasUnbundled = true; } if (edgeIsBezier) { tableEntry.hasBezier = true; } } var src, tgt, srcPos, tgtPos, srcW, srcH, tgtW, tgtH, srcShape, tgtShape; var vectorNormInverse; var badBezier; // for each pair (src, tgt), create the ctrl pts // Nested for loop is OK; total number of iterations for both loops = edgeCount for (var p = 0; p < pairIds.length; p++) { pairId = pairIds[p]; var pairEdges = hashTable[pairId]; // for each pair id, the edges should be sorted by index pairEdges.sort(function (edge1, edge2) { return edge1.poolIndex() - edge2.poolIndex(); }); src = pairEdges[0]._private.source; tgt = pairEdges[0]._private.target; // make sure src/tgt distinction is consistent for bundled edges if (!pairEdges.hasUnbundled && src.id() > tgt.id()) { var temp = src; src = tgt; tgt = temp; } srcPos = src.position(); tgtPos = tgt.position(); srcW = src.outerWidth(); srcH = src.outerHeight(); tgtW = tgt.outerWidth(); tgtH = tgt.outerHeight(); srcShape = r.nodeShapes[this.getNodeShape(src)]; tgtShape = r.nodeShapes[this.getNodeShape(tgt)]; badBezier = false; var edge; var edge_p; var rs; var dirCounts = { 'north': 0, 'west': 0, 'south': 0, 'east': 0, 'northwest': 0, 'southwest': 0, 'northeast': 0, 'southeast': 0 }; var srcX2 = srcPos.x; var srcY2 = srcPos.y; var srcW2 = srcW; var srcH2 = srcH; var tgtX2 = tgtPos.x; var tgtY2 = tgtPos.y; var tgtW2 = tgtW; var tgtH2 = tgtH; var numEdges2 = pairEdges.length; for (var i = 0; i < pairEdges.length; i++) { edge = pairEdges[i]; edge_p = edge._private; rs = edge_p.rscratch; var edgeIndex1 = rs.lastEdgeIndex; var edgeIndex2 = i; var numEdges1 = rs.lastNumEdges; var curveStyle = edge.pstyle('curve-style').value; var edgeIsUnbundled = curveStyle === 'unbundled-bezier' || curveStyle === 'segments'; // whether the normalised pair order is the reverse of the edge's src-tgt order var edgeIsSwapped = src.id() !== edge.source().id(); var ctrlptDists = edge.pstyle('control-point-distances'); var loopDir = edge.pstyle('loop-direction').pfValue; var loopSwp = edge.pstyle('loop-sweep').pfValue; var ctrlptWs = edge.pstyle('control-point-weights'); var bezierN = ctrlptDists && ctrlptWs ? Math.min(ctrlptDists.value.length, ctrlptWs.value.length) : 1; var stepSize = edge.pstyle('control-point-step-size').pfValue; var ctrlptDist = ctrlptDists ? ctrlptDists.pfValue[0] : undefined; var ctrlptWeight = ctrlptWs.value[0]; var edgeDistances = edge.pstyle('edge-distances').value; var srcDistFNode = edge.pstyle('source-distance-from-node').pfValue; var tgtDistFNode = edge.pstyle('target-distance-from-node').pfValue; var segmentWs = edge.pstyle('segment-weights'); var segmentDs = edge.pstyle('segment-distances'); var segmentsN = Math.min(segmentWs.pfValue.length, segmentDs.pfValue.length); var srcEndpt = edge.pstyle('source-endpoint').value; var tgtEndpt = edge.pstyle('target-endpoint').value; var srcArrShape = edge.pstyle('source-arrow-shape').value; var tgtArrShape = edge.pstyle('target-arrow-shape').value; var arrowScale = edge.pstyle('arrow-scale').value; var lineWidth = edge.pstyle('width').pfValue; var srcX1 = rs.lastSrcCtlPtX; var srcY1 = rs.lastSrcCtlPtY; var srcW1 = rs.lastSrcCtlPtW; var srcH1 = rs.lastSrcCtlPtH; var tgtX1 = rs.lastTgtCtlPtX; var tgtY1 = rs.lastTgtCtlPtY; var tgtW1 = rs.lastTgtCtlPtW; var tgtH1 = rs.lastTgtCtlPtH; var curveStyle1 = rs.lastCurveStyle; var curveStyle2 = curveStyle; var ctrlptDists1 = rs.lastCtrlptDists; var ctrlptDists2 = ctrlptDists ? ctrlptDists.strValue : null; var ctrlptWs1 = rs.lastCtrlptWs; var ctrlptWs2 = ctrlptWs.strValue; var segmentWs1 = rs.lastSegmentWs; var segmentWs2 = segmentWs.strValue; var segmentDs1 = rs.lastSegmentDs; var segmentDs2 = segmentDs.strValue; var stepSize1 = rs.lastStepSize; var stepSize2 = stepSize; var loopDir1 = rs.lastLoopDir; var loopDir2 = loopDir; var loopSwp1 = rs.lastLoopSwp; var loopSwp2 = loopSwp; var edgeDistances1 = rs.lastEdgeDistances; var edgeDistances2 = edgeDistances; var srcDistFNode1 = rs.lastSrcDistFNode; var srcDistFNode2 = srcDistFNode; var tgtDistFNode1 = rs.lastTgtDistFNode; var tgtDistFNode2 = tgtDistFNode; var srcEndpt1 = rs.lastSrcEndpt; var srcEndpt2 = srcEndpt; var tgtEndpt1 = rs.lastTgtEndpt; var tgtEndpt2 = tgtEndpt; var srcArr1 = rs.lastSrcArr; var srcArr2 = srcArrShape; var tgtArr1 = rs.lastTgtArr; var tgtArr2 = tgtArrShape; var lineW1 = rs.lastLineW; var lineW2 = lineWidth; var arrScl1 = rs.lastArrScl; var arrScl2 = arrowScale; if (badBezier) { rs.badBezier = true; } else { rs.badBezier = false; } var ptCacheHit; if (srcX1 === srcX2 && srcY1 === srcY2 && srcW1 === srcW2 && srcH1 === srcH2 && tgtX1 === tgtX2 && tgtY1 === tgtY2 && tgtW1 === tgtW2 && tgtH1 === tgtH2 && curveStyle1 === curveStyle2 && ctrlptDists1 === ctrlptDists2 && ctrlptWs1 === ctrlptWs2 && segmentWs1 === segmentWs2 && segmentDs1 === segmentDs2 && stepSize1 === stepSize2 && loopDir1 === loopDir2 && loopSwp1 === loopSwp2 && edgeDistances1 === edgeDistances2 && srcDistFNode1 === srcDistFNode2 && tgtDistFNode1 === tgtDistFNode2 && srcEndpt1 === srcEndpt2 && tgtEndpt1 === tgtEndpt2 && srcArr1 === srcArr2 && tgtArr1 === tgtArr2 && lineW1 === lineW2 && arrScl1 === arrScl2 && (edgeIndex1 === edgeIndex2 && numEdges1 === numEdges2 || edgeIsUnbundled)) { ptCacheHit = true; // then the control points haven't changed and we can skip calculating them } else { ptCacheHit = false; rs.lastSrcCtlPtX = srcX2; rs.lastSrcCtlPtY = srcY2; rs.lastSrcCtlPtW = srcW2; rs.lastSrcCtlPtH = srcH2; rs.lastTgtCtlPtX = tgtX2; rs.lastTgtCtlPtY = tgtY2; rs.lastTgtCtlPtW = tgtW2; rs.lastTgtCtlPtH = tgtH2; rs.lastEdgeIndex = edgeIndex2; rs.lastNumEdges = numEdges2; rs.lastCurveStyle = curveStyle2; rs.lastCtrlptDists = ctrlptDists2; rs.lastCtrlptWs = ctrlptWs2; rs.lastSegmentDs = segmentDs2; rs.lastSegmentWs = segmentWs2; rs.lastStepSize = stepSize2; rs.lastLoopDir = loopDir2; rs.lastLoopSwp = loopSwp2; rs.lastEdgeDistances = edgeDistances2; rs.lastSrcDistFNode = srcDistFNode2; rs.lastTgtDistFNode = tgtDistFNode2; rs.lastSrcEndpt = srcEndpt2; rs.lastTgtEndpt = tgtEndpt2; rs.lastSrcArr = srcArr2; rs.lastTgtArr = tgtArr2; rs.lastLineW = lineW2; rs.lastArrScl = arrScl2; } if (!ptCacheHit) { if (!pairEdges.calculatedIntersection && src !== tgt && (pairEdges.hasBezier || pairEdges.hasUnbundled)) { pairEdges.calculatedIntersection = true; // pt outside src shape to calc distance/displacement from src to tgt var srcOutside = srcShape.intersectLine(srcPos.x, srcPos.y, srcW, srcH, tgtPos.x, tgtPos.y, 0); pairEdges.srcIntn = srcOutside; // pt outside tgt shape to calc distance/displacement from src to tgt var tgtOutside = tgtShape.intersectLine(tgtPos.x, tgtPos.y, tgtW, tgtH, srcPos.x, srcPos.y, 0); pairEdges.tgtIntn = tgtOutside; var midptSrcPts = { x1: srcOutside[0], x2: tgtOutside[0], y1: srcOutside[1], y2: tgtOutside[1] }; var posPts = { x1: srcPos.x, x2: tgtPos.x, y1: srcPos.y, y2: tgtPos.y }; var dy = tgtOutside[1] - srcOutside[1]; var dx = tgtOutside[0] - srcOutside[0]; var l = Math.sqrt(dx * dx + dy * dy); var vector = { x: dx, y: dy }; var vectorNorm = { x: vector.x / l, y: vector.y / l }; vectorNormInverse = { x: -vectorNorm.y, y: vectorNorm.x }; // if node shapes overlap, then no ctrl pts to draw if (tgtShape.checkPoint(srcOutside[0], srcOutside[1], 0, tgtW, tgtH, tgtPos.x, tgtPos.y) && srcShape.checkPoint(tgtOutside[0], tgtOutside[1], 0, srcW, srcH, srcPos.x, srcPos.y)) { vectorNormInverse = {}; badBezier = true; } } if (!edgeIsSwapped) { rs.srcIntn = pairEdges.srcIntn; rs.tgtIntn = pairEdges.tgtIntn; } else { // ensure that the per-edge cached value for intersections are correct for swapped bundled edges rs.srcIntn = pairEdges.tgtIntn; rs.tgtIntn = pairEdges.srcIntn; } if (src === tgt) { // Self-edge rs.edgeType = 'self'; var j = i; var loopDist = stepSize; if (edgeIsUnbundled) { j = 0; loopDist = ctrlptDist; } var loopAngle = loopDir - Math.PI / 2; var outAngle = loopAngle - loopSwp / 2; var inAngle = loopAngle + loopSwp / 2; // increase by step size for overlapping loops, keyed on direction and sweep values var dc = String(loopDir + '_' + loopSwp); j = dirCounts[dc] === undefined ? dirCounts[dc] = 0 : ++dirCounts[dc]; rs.ctrlpts = [srcPos.x + Math.cos(outAngle) * 1.4 * loopDist * (j / 3 + 1), srcPos.y + Math.sin(outAngle) * 1.4 * loopDist * (j / 3 + 1), srcPos.x + Math.cos(inAngle) * 1.4 * loopDist * (j / 3 + 1), srcPos.y + Math.sin(inAngle) * 1.4 * loopDist * (j / 3 + 1)]; } else if (hasCompounds && (src.isParent() || src.isChild() || tgt.isParent() || tgt.isChild()) && (src.parents().anySame(tgt) || tgt.parents().anySame(src))) { // Compound edge rs.edgeType = 'compound'; // because the line approximation doesn't apply for compound beziers // (loop/self edges are already elided b/c of cheap src==tgt check) rs.badBezier = false; var j = i; var loopDist = stepSize; if (edgeIsUnbundled) { j = 0; loopDist = ctrlptDist; } var loopW = 50; var loopaPos = { x: srcPos.x - srcW / 2, y: srcPos.y - srcH / 2 }; var loopbPos = { x: tgtPos.x - tgtW / 2, y: tgtPos.y - tgtH / 2 }; var loopPos = { x: Math.min(loopaPos.x, loopbPos.x), y: Math.min(loopaPos.y, loopbPos.y) }; // avoids cases with impossible beziers var minCompoundStretch = 0.5; var compoundStretchA = Math.max(minCompoundStretch, Math.log(srcW * 0.01)); var compoundStretchB = Math.max(minCompoundStretch, Math.log(tgtW * 0.01)); rs.ctrlpts = [loopPos.x, loopPos.y - (1 + Math.pow(loopW, 1.12) / 100) * loopDist * (j / 3 + 1) * compoundStretchA, loopPos.x - (1 + Math.pow(loopW, 1.12) / 100) * loopDist * (j / 3 + 1) * compoundStretchB, loopPos.y]; } else if (curveStyle === 'segments') { // Segments (multiple straight lines) rs.edgeType = 'segments'; rs.segpts = []; for (var s = 0; s < segmentsN; s++) { var w = segmentWs.pfValue[s]; var d = segmentDs.pfValue[s]; var w1 = 1 - w; var w2 = w; var midptPts = edgeDistances === 'node-position' ? posPts : midptSrcPts; var adjustedMidpt = { x: midptPts.x1 * w1 + midptPts.x2 * w2, y: midptPts.y1 * w1 + midptPts.y2 * w2 }; rs.segpts.push(adjustedMidpt.x + vectorNormInverse.x * d, adjustedMidpt.y + vectorNormInverse.y * d); } // Straight edge } else if (pairEdges.length % 2 === 1 && i === Math.floor(pairEdges.length / 2) && !edgeIsUnbundled) { rs.edgeType = 'straight'; } else { // (Multi)bezier var multi = edgeIsUnbundled; rs.edgeType = multi ? 'multibezier' : 'bezier'; rs.ctrlpts = []; for (var b = 0; b < bezierN; b++) { var normctrlptDist = (0.5 - pairEdges.length / 2 + i) * stepSize; var manctrlptDist; var sign = math.signum(normctrlptDist); if (multi) { ctrlptDist = ctrlptDists ? ctrlptDists.pfValue[b] : stepSize; // fall back on step size ctrlptWeight = ctrlptWs.value[b]; } if (edgeIsUnbundled) { // multi or single unbundled manctrlptDist = ctrlptDist; } else { manctrlptDist = ctrlptDist !== undefined ? sign * ctrlptDist : undefined; } var distanceFromMidpoint = manctrlptDist !== undefined ? manctrlptDist : normctrlptDist; var w1 = 1 - ctrlptWeight; var w2 = ctrlptWeight; if (edgeIsSwapped) { var temp = w1; w1 = w2; w2 = temp; } var midptPts = edgeDistances === 'node-position' ? posPts : midptSrcPts; var adjustedMidpt = { x: midptPts.x1 * w1 + midptPts.x2 * w2, y: midptPts.y1 * w1 + midptPts.y2 * w2 }; rs.ctrlpts.push(adjustedMidpt.x + vectorNormInverse.x * distanceFromMidpoint, adjustedMidpt.y + vectorNormInverse.y * distanceFromMidpoint); } } // find endpts for edge this.findEndpoints(edge); var badStart = !is.number(rs.startX) || !is.number(rs.startY); var badAStart = !is.number(rs.arrowStartX) || !is.number(rs.arrowStartY); var badEnd = !is.number(rs.endX) || !is.number(rs.endY); var badAEnd = !is.number(rs.arrowEndX) || !is.number(rs.arrowEndY); var minCpADistFactor = 3; var arrowW = this.getArrowWidth(edge.pstyle('width').pfValue, edge.pstyle('arrow-scale').value) * this.arrowShapeWidth; var minCpADist = minCpADistFactor * arrowW; if (rs.edgeType === 'bezier') { var startACpDist = math.dist({ x: rs.ctrlpts[0], y: rs.ctrlpts[1] }, { x: rs.startX, y: rs.startY }); var closeStartACp = startACpDist < minCpADist; var endACpDist = math.dist({ x: rs.ctrlpts[0], y: rs.ctrlpts[1] }, { x: rs.endX, y: rs.endY }); var closeEndACp = endACpDist < minCpADist; var overlapping = false; if (badStart || badAStart || closeStartACp) { overlapping = true; // project control point along line from src centre to outside the src shape // (otherwise intersection will yield nothing) var cpD = { // delta x: rs.ctrlpts[0] - srcPos.x, y: rs.ctrlpts[1] - srcPos.y }; var cpL = Math.sqrt(cpD.x * cpD.x + cpD.y * cpD.y); // length of line var cpM = { // normalised delta x: cpD.x / cpL, y: cpD.y / cpL }; var radius = Math.max(srcW, srcH); var cpProj = { // *2 radius guarantees outside shape x: rs.ctrlpts[0] + cpM.x * 2 * radius, y: rs.ctrlpts[1] + cpM.y * 2 * radius }; var srcCtrlPtIntn = srcShape.intersectLine(srcPos.x, srcPos.y, srcW, srcH, cpProj.x, cpProj.y, 0); if (closeStartACp) { rs.ctrlpts[0] = rs.ctrlpts[0] + cpM.x * (minCpADist - startACpDist); rs.ctrlpts[1] = rs.ctrlpts[1] + cpM.y * (minCpADist - startACpDist); } else { rs.ctrlpts[0] = srcCtrlPtIntn[0] + cpM.x * minCpADist; rs.ctrlpts[1] = srcCtrlPtIntn[1] + cpM.y * minCpADist; } } if (badEnd || badAEnd || closeEndACp) { overlapping = true; // project control point along line from tgt centre to outside the tgt shape // (otherwise intersection will yield nothing) var cpD = { // delta x: rs.ctrlpts[0] - tgtPos.x, y: rs.ctrlpts[1] - tgtPos.y }; var cpL = Math.sqrt(cpD.x * cpD.x + cpD.y * cpD.y); // length of line var cpM = { // normalised delta x: cpD.x / cpL, y: cpD.y / cpL }; var radius = Math.max(srcW, srcH); var cpProj = { // *2 radius guarantees outside shape x: rs.ctrlpts[0] + cpM.x * 2 * radius, y: rs.ctrlpts[1] + cpM.y * 2 * radius }; var tgtCtrlPtIntn = tgtShape.intersectLine(tgtPos.x, tgtPos.y, tgtW, tgtH, cpProj.x, cpProj.y, 0); if (closeEndACp) { rs.ctrlpts[0] = rs.ctrlpts[0] + cpM.x * (minCpADist - endACpDist); rs.ctrlpts[1] = rs.ctrlpts[1] + cpM.y * (minCpADist - endACpDist); } else { rs.ctrlpts[0] = tgtCtrlPtIntn[0] + cpM.x * minCpADist; rs.ctrlpts[1] = tgtCtrlPtIntn[1] + cpM.y * minCpADist; } } if (overlapping) { // recalc endpts this.findEndpoints(edge); } } if (rs.edgeType === 'multibezier' || rs.edgeType === 'bezier' || rs.edgeType === 'self' || rs.edgeType === 'compound') { rs.allpts = []; rs.allpts.push(rs.startX, rs.startY); for (var b = 0; b + 1 < rs.ctrlpts.length; b += 2) { // ctrl pt itself rs.allpts.push(rs.ctrlpts[b], rs.ctrlpts[b + 1]); // the midpt between ctrlpts as intermediate destination pts if (b + 3 < rs.ctrlpts.length) { rs.allpts.push((rs.ctrlpts[b] + rs.ctrlpts[b + 2]) / 2, (rs.ctrlpts[b + 1] + rs.ctrlpts[b + 3]) / 2); } } rs.allpts.push(rs.endX, rs.endY); var m, mt; if (rs.ctrlpts.length / 2 % 2 === 0) { m = rs.allpts.length / 2 - 1; rs.midX = rs.allpts[m]; rs.midY = rs.allpts[m + 1]; } else { m = rs.allpts.length / 2 - 3; mt = 0.5; rs.midX = math.qbezierAt(rs.allpts[m], rs.allpts[m + 2], rs.allpts[m + 4], mt); rs.midY = math.qbezierAt(rs.allpts[m + 1], rs.allpts[m + 3], rs.allpts[m + 5], mt); } } else if (rs.edgeType === 'straight') { // need to calc these after endpts rs.allpts = [rs.startX, rs.startY, rs.endX, rs.endY]; // default midpt for labels etc rs.midX = (rs.startX + rs.endX + rs.arrowStartX + rs.arrowEndX) / 4; rs.midY = (rs.startY + rs.endY + rs.arrowStartY + rs.arrowEndY) / 4; } else if (rs.edgeType === 'segments') { rs.allpts = []; rs.allpts.push(rs.startX, rs.startY); rs.allpts.push.apply(rs.allpts, rs.segpts); rs.allpts.push(rs.endX, rs.endY); if (rs.segpts.length % 4 === 0) { var i2 = rs.segpts.length / 2; var i1 = i2 - 2; rs.midX = (rs.segpts[i1] + rs.segpts[i2]) / 2; rs.midY = (rs.segpts[i1 + 1] + rs.segpts[i2 + 1]) / 2; } else { var i1 = rs.segpts.length / 2 - 1; rs.midX = rs.segpts[i1]; rs.midY = rs.segpts[i1 + 1]; } } this.storeEdgeProjections(edge); this.calculateArrowAngles(edge); } // if point cache miss this.recalculateEdgeLabelProjections(edge); this.calculateLabelAngles(edge); } // for pair edges } // for pair ids for (var i = 0; i < haystackEdges.length; i++) { var edge = haystackEdges[i]; var _p = edge._private; var rscratch = _p.rscratch; var rs = rscratch; if (!rscratch.haystack) { var angle = Math.random() * 2 * Math.PI; rscratch.source = { x: Math.cos(angle), y: Math.sin(angle) }; var angle = Math.random() * 2 * Math.PI; rscratch.target = { x: Math.cos(angle), y: Math.sin(angle) }; } var src = _p.source; var tgt = _p.target; var srcPos = src.position(); var tgtPos = tgt.position(); var srcW = src.width(); var tgtW = tgt.width(); var srcH = src.height(); var tgtH = tgt.height(); var radius = edge.pstyle('haystack-radius').value; var halfRadius = radius / 2; // b/c have to half width/height rs.haystackPts = rs.allpts = [rs.source.x * srcW * halfRadius + srcPos.x, rs.source.y * srcH * halfRadius + srcPos.y, rs.target.x * tgtW * halfRadius + tgtPos.x, rs.target.y * tgtH * halfRadius + tgtPos.y]; rs.midX = (rs.allpts[0] + rs.allpts[2]) / 2; rs.midY = (rs.allpts[1] + rs.allpts[3]) / 2; // always override as haystack in case set to different type previously rscratch.edgeType = rscratch.lastCurveStyle = 'haystack'; rscratch.haystack = true; this.storeEdgeProjections(edge); this.calculateArrowAngles(edge); this.recalculateEdgeLabelProjections(edge); this.calculateLabelAngles(edge); } }; function getPts(pts) { var retPts = []; if (pts == null) { return; } for (var i = 0; i < pts.length; i += 2) { var x = pts[i]; var y = pts[i + 1]; retPts.push({ x: x, y: y }); } return retPts; } BRp.getSegmentPoints = function (edge) { var rs = edge[0]._private.rscratch; var type = rs.edgeType; if (type === 'segments') { return getPts(rs.segpts); } }; BRp.getControlPoints = function (edge) { var rs = edge[0]._private.rscratch; var type = rs.edgeType; if (type === 'bezier' || type === 'multibezier' || type === 'self' || type === 'compound') { return getPts(rs.ctrlpts); } }; BRp.getEdgeMidpoint = function (edge) { var rs = edge[0]._private.rscratch; return { x: rs.midX, y: rs.midY }; }; module.exports = BRp; /***/ }), /* 114 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var math = __webpack_require__(2); var is = __webpack_require__(0); var BRp = {}; BRp.manualEndptToPx = function (node, prop) { var r = this; var npos = node.position(); var w = node.outerWidth(); var h = node.outerHeight(); if (prop.value.length === 2) { var p = [prop.pfValue[0], prop.pfValue[1]]; if (prop.units[0] === '%') { p[0] = p[0] * w; } if (prop.units[1] === '%') { p[1] = p[1] * h; } p[0] += npos.x; p[1] += npos.y; return p; } else { var angle = prop.pfValue[0]; angle = -Math.PI / 2 + angle; // start at 12 o'clock var l = 2 * Math.max(w, h); var _p = [npos.x + Math.cos(angle) * l, npos.y + Math.sin(angle) * l]; return r.nodeShapes[this.getNodeShape(node)].intersectLine(npos.x, npos.y, w, h, _p[0], _p[1], 0); } }; BRp.findEndpoints = function (edge) { var r = this; var intersect = void 0; var source = edge.source()[0]; var target = edge.target()[0]; var srcPos = source.position(); var tgtPos = target.position(); var tgtArShape = edge.pstyle('target-arrow-shape').value; var srcArShape = edge.pstyle('source-arrow-shape').value; var tgtDist = edge.pstyle('target-distance-from-node').pfValue; var srcDist = edge.pstyle('source-distance-from-node').pfValue; var rs = edge._private.rscratch; var et = rs.edgeType; var self = et === 'self' || et === 'compound'; var bezier = et === 'bezier' || et === 'multibezier' || self; var multi = et !== 'bezier'; var lines = et === 'straight' || et === 'segments'; var segments = et === 'segments'; var hasEndpts = bezier || multi || lines; var srcManEndpt = edge.pstyle('source-endpoint'); var srcManEndptVal = self ? 'outside-to-node' : srcManEndpt.value; var tgtManEndpt = edge.pstyle('target-endpoint'); var tgtManEndptVal = self ? 'outside-to-node' : tgtManEndpt.value; rs.srcManEndpt = srcManEndpt; rs.tgtManEndpt = tgtManEndpt; var p1 = void 0; // last known point of edge on target side var p2 = void 0; // last known point of edge on source side var p1_i = void 0; // point to intersect with target shape var p2_i = void 0; // point to intersect with source shape if (bezier) { var cpStart = [rs.ctrlpts[0], rs.ctrlpts[1]]; var cpEnd = multi ? [rs.ctrlpts[rs.ctrlpts.length - 2], rs.ctrlpts[rs.ctrlpts.length - 1]] : cpStart; p1 = cpEnd; p2 = cpStart; } else if (lines) { var srcArrowFromPt = !segments ? [tgtPos.x, tgtPos.y] : rs.segpts.slice(0, 2); var tgtArrowFromPt = !segments ? [srcPos.x, srcPos.y] : rs.segpts.slice(rs.segpts.length - 2); p1 = tgtArrowFromPt; p2 = srcArrowFromPt; } if (tgtManEndptVal === 'inside-to-node') { intersect = [tgtPos.x, tgtPos.y]; } else if (tgtManEndpt.units) { intersect = this.manualEndptToPx(target, tgtManEndpt); } else if (tgtManEndptVal === 'outside-to-line') { intersect = rs.tgtIntn; // use cached value from ctrlpt calc } else { if (tgtManEndptVal === 'outside-to-node') { p1_i = p1; } else if (tgtManEndptVal === 'outside-to-line') { p1_i = [srcPos.x, srcPos.y]; } intersect = r.nodeShapes[this.getNodeShape(target)].intersectLine(tgtPos.x, tgtPos.y, target.outerWidth(), target.outerHeight(), p1_i[0], p1_i[1], 0); } var arrowEnd = math.shortenIntersection(intersect, p1, r.arrowShapes[tgtArShape].spacing(edge) + tgtDist); var edgeEnd = math.shortenIntersection(intersect, p1, r.arrowShapes[tgtArShape].gap(edge) + tgtDist); rs.endX = edgeEnd[0]; rs.endY = edgeEnd[1]; rs.arrowEndX = arrowEnd[0]; rs.arrowEndY = arrowEnd[1]; if (srcManEndptVal === 'inside-to-node') { intersect = [srcPos.x, srcPos.y]; } else if (srcManEndpt.units) { intersect = this.manualEndptToPx(source, srcManEndpt); } else if (srcManEndptVal === 'outside-to-line') { intersect = rs.srcIntn; // use cached value from ctrlpt calc } else { if (srcManEndptVal === 'outside-to-node') { p2_i = p2; } else if (srcManEndptVal === 'outside-to-line') { p2_i = [tgtPos.x, tgtPos.y]; } intersect = r.nodeShapes[this.getNodeShape(source)].intersectLine(srcPos.x, srcPos.y, source.outerWidth(), source.outerHeight(), p2_i[0], p2_i[1], 0); } var arrowStart = math.shortenIntersection(intersect, p2, r.arrowShapes[srcArShape].spacing(edge) + srcDist); var edgeStart = math.shortenIntersection(intersect, p2, r.arrowShapes[srcArShape].gap(edge) + srcDist); rs.startX = edgeStart[0]; rs.startY = edgeStart[1]; rs.arrowStartX = arrowStart[0]; rs.arrowStartY = arrowStart[1]; if (hasEndpts) { if (!is.number(rs.startX) || !is.number(rs.startY) || !is.number(rs.endX) || !is.number(rs.endY)) { rs.badLine = true; } else { rs.badLine = false; } } }; BRp.getSourceEndpoint = function (edge) { var rs = edge[0]._private.rscratch; switch (rs.edgeType) { case 'haystack': return { x: rs.haystackPts[0], y: rs.haystackPts[1] }; default: return { x: rs.arrowStartX, y: rs.arrowStartY }; } }; BRp.getTargetEndpoint = function (edge) { var rs = edge[0]._private.rscratch; switch (rs.edgeType) { case 'haystack': return { x: rs.haystackPts[2], y: rs.haystackPts[3] }; default: return { x: rs.arrowEndX, y: rs.arrowEndY }; } }; module.exports = BRp; /***/ }), /* 115 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var math = __webpack_require__(2); var BRp = {}; function pushBezierPts(r, edge, pts) { var qbezierAt = function qbezierAt(p1, p2, p3, t) { return math.qbezierAt(p1, p2, p3, t); }; var _p = edge._private; var bpts = _p.rstyle.bezierPts; for (var i = 0; i < r.bezierProjPcts.length; i++) { var p = r.bezierProjPcts[i]; bpts.push({ x: qbezierAt(pts[0], pts[2], pts[4], p), y: qbezierAt(pts[1], pts[3], pts[5], p) }); } } BRp.storeEdgeProjections = function (edge) { var _p = edge._private; var rs = _p.rscratch; var et = rs.edgeType; // clear the cached points state _p.rstyle.bezierPts = null; _p.rstyle.linePts = null; _p.rstyle.haystackPts = null; if (et === 'multibezier' || et === 'bezier' || et === 'self' || et === 'compound') { var bpts = _p.rstyle.bezierPts = []; // jshint ignore:line for (var i = 0; i + 5 < rs.allpts.length; i += 4) { pushBezierPts(this, edge, rs.allpts.slice(i, i + 6)); } } else if (et === 'segments') { var lpts = _p.rstyle.linePts = []; for (var i = 0; i + 1 < rs.allpts.length; i += 2) { lpts.push({ x: rs.allpts[i], y: rs.allpts[i + 1] }); } } else if (et === 'haystack') { var hpts = rs.haystackPts; _p.rstyle.haystackPts = [{ x: hpts[0], y: hpts[1] }, { x: hpts[2], y: hpts[3] }]; } _p.rstyle.arrowWidth = this.getArrowWidth(edge.pstyle('width').pfValue, edge.pstyle('arrow-scale').value) * this.arrowShapeWidth; }; BRp.recalculateEdgeProjections = function (edges) { this.findEdgeControlPoints(edges); }; module.exports = BRp; /***/ }), /* 116 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var math = __webpack_require__(2); var is = __webpack_require__(0); var util = __webpack_require__(1); var BRp = {}; BRp.recalculateNodeLabelProjection = function (node) { var content = node.pstyle('label').strValue; if (is.emptyString(content)) { return; } var textX, textY; var _p = node._private; var nodeWidth = node.width(); var nodeHeight = node.height(); var padding = node.padding(); var nodePos = node.position(); var textHalign = node.pstyle('text-halign').strValue; var textValign = node.pstyle('text-valign').strValue; var rs = _p.rscratch; var rstyle = _p.rstyle; switch (textHalign) { case 'left': textX = nodePos.x - nodeWidth / 2 - padding; break; case 'right': textX = nodePos.x + nodeWidth / 2 + padding; break; default: // e.g. center textX = nodePos.x; } switch (textValign) { case 'top': textY = nodePos.y - nodeHeight / 2 - padding; break; case 'bottom': textY = nodePos.y + nodeHeight / 2 + padding; break; default: // e.g. middle textY = nodePos.y; } rs.labelX = textX; rs.labelY = textY; rstyle.labelX = textX; rstyle.labelY = textY; this.applyLabelDimensions(node); }; var lineAngleFromDelta = function lineAngleFromDelta(dx, dy) { var angle = Math.atan(dy / dx); if (dx === 0 && angle < 0) { angle = angle * -1; } return angle; }; var lineAngle = function lineAngle(p0, p1) { var dx = p1.x - p0.x; var dy = p1.y - p0.y; return lineAngleFromDelta(dx, dy); }; var bezierAngle = function bezierAngle(p0, p1, p2, t) { var t0 = math.bound(0, t - 0.001, 1); var t1 = math.bound(0, t + 0.001, 1); var lp0 = math.qbezierPtAt(p0, p1, p2, t0); var lp1 = math.qbezierPtAt(p0, p1, p2, t1); return lineAngle(lp0, lp1); }; BRp.recalculateEdgeLabelProjections = function (edge) { var p; var _p = edge._private; var rs = _p.rscratch; var r = this; var content = { mid: edge.pstyle('label').strValue, source: edge.pstyle('source-label').strValue, target: edge.pstyle('target-label').strValue }; if (content.mid || content.source || content.target) { // then we have to calculate... } else { return; // no labels => no calcs } // add center point to style so bounding box calculations can use it // p = { x: rs.midX, y: rs.midY }; var setRs = function setRs(propName, prefix, value) { util.setPrefixedProperty(_p.rscratch, propName, prefix, value); util.setPrefixedProperty(_p.rstyle, propName, prefix, value); }; setRs('labelX', null, p.x); setRs('labelY', null, p.y); var midAngle = lineAngleFromDelta(rs.midDispX, rs.midDispY); setRs('labelAutoAngle', null, midAngle); var createControlPointInfo = function createControlPointInfo() { if (createControlPointInfo.cache) { return createControlPointInfo.cache; } // use cache so only 1x per edge var ctrlpts = []; // store each ctrlpt info init for (var i = 0; i + 5 < rs.allpts.length; i += 4) { var p0 = { x: rs.allpts[i], y: rs.allpts[i + 1] }; var p1 = { x: rs.allpts[i + 2], y: rs.allpts[i + 3] }; // ctrlpt var p2 = { x: rs.allpts[i + 4], y: rs.allpts[i + 5] }; ctrlpts.push({ p0: p0, p1: p1, p2: p2, startDist: 0, length: 0, segments: [] }); } var bpts = _p.rstyle.bezierPts; var nProjs = r.bezierProjPcts.length; function addSegment(cp, p0, p1, t0, t1) { var length = math.dist(p0, p1); var prevSegment = cp.segments[cp.segments.length - 1]; var segment = { p0: p0, p1: p1, t0: t0, t1: t1, startDist: prevSegment ? prevSegment.startDist + prevSegment.length : 0, length: length }; cp.segments.push(segment); cp.length += length; } // update each ctrlpt with segment info for (var i = 0; i < ctrlpts.length; i++) { var cp = ctrlpts[i]; var prevCp = ctrlpts[i - 1]; if (prevCp) { cp.startDist = prevCp.startDist + prevCp.length; } addSegment(cp, cp.p0, bpts[i * nProjs], 0, r.bezierProjPcts[0]); // first for (var j = 0; j < nProjs - 1; j++) { addSegment(cp, bpts[i * nProjs + j], bpts[i * nProjs + j + 1], r.bezierProjPcts[j], r.bezierProjPcts[j + 1]); } addSegment(cp, bpts[i * nProjs + nProjs - 1], cp.p2, r.bezierProjPcts[nProjs - 1], 1); // last } return createControlPointInfo.cache = ctrlpts; }; var calculateEndProjection = function calculateEndProjection(prefix) { var angle; var isSrc = prefix === 'source'; if (!content[prefix]) { return; } var offset = edge.pstyle(prefix + '-text-offset').pfValue; switch (rs.edgeType) { case 'self': case 'compound': case 'bezier': case 'multibezier': var cps = createControlPointInfo(); var selected; var startDist = 0; var totalDist = 0; // find the segment we're on for (var i = 0; i < cps.length; i++) { var cp = cps[isSrc ? i : cps.length - 1 - i]; for (var j = 0; j < cp.segments.length; j++) { var seg = cp.segments[isSrc ? j : cp.segments.length - 1 - j]; var lastSeg = i === cps.length - 1 && j === cp.segments.length - 1; startDist = totalDist; totalDist += seg.length; if (totalDist >= offset || lastSeg) { selected = { cp: cp, segment: seg }; break; } } if (selected) { break; } } var cp = selected.cp; var seg = selected.segment; var tSegment = (offset - startDist) / seg.length; var segDt = seg.t1 - seg.t0; var t = isSrc ? seg.t0 + segDt * tSegment : seg.t1 - segDt * tSegment; t = math.bound(0, t, 1); p = math.qbezierPtAt(cp.p0, cp.p1, cp.p2, t); angle = bezierAngle(cp.p0, cp.p1, cp.p2, t, p); break; case 'straight': case 'segments': case 'haystack': var d = 0, di, d0; var p0, p1; var l = rs.allpts.length; for (var i = 0; i + 3 < l; i += 2) { if (isSrc) { p0 = { x: rs.allpts[i], y: rs.allpts[i + 1] }; p1 = { x: rs.allpts[i + 2], y: rs.allpts[i + 3] }; } else { p0 = { x: rs.allpts[l - 2 - i], y: rs.allpts[l - 1 - i] }; p1 = { x: rs.allpts[l - 4 - i], y: rs.allpts[l - 3 - i] }; } di = math.dist(p0, p1); d0 = d; d += di; if (d >= offset) { break; } } var pD = offset - d0; var t = pD / di; t = math.bound(0, t, 1); p = math.lineAt(p0, p1, t); angle = lineAngle(p0, p1); break; } setRs('labelX', prefix, p.x); setRs('labelY', prefix, p.y); setRs('labelAutoAngle', prefix, angle); }; calculateEndProjection('source'); calculateEndProjection('target'); this.applyLabelDimensions(edge); }; BRp.applyLabelDimensions = function (ele) { this.applyPrefixedLabelDimensions(ele); if (ele.isEdge()) { this.applyPrefixedLabelDimensions(ele, 'source'); this.applyPrefixedLabelDimensions(ele, 'target'); } }; BRp.applyPrefixedLabelDimensions = function (ele, prefix) { var _p = ele._private; var text = this.getLabelText(ele, prefix); var labelDims = this.calculateLabelDimensions(ele, text); util.setPrefixedProperty(_p.rstyle, 'labelWidth', prefix, labelDims.width); util.setPrefixedProperty(_p.rscratch, 'labelWidth', prefix, labelDims.width); util.setPrefixedProperty(_p.rstyle, 'labelHeight', prefix, labelDims.height); util.setPrefixedProperty(_p.rscratch, 'labelHeight', prefix, labelDims.height); }; BRp.getLabelText = function (ele, prefix) { var _p = ele._private; var pfd = prefix ? prefix + '-' : ''; var text = ele.pstyle(pfd + 'label').strValue; var textTransform = ele.pstyle('text-transform').value; var rscratch = function rscratch(propName, value) { if (value) { util.setPrefixedProperty(_p.rscratch, propName, prefix, value); return value; } else { return util.getPrefixedProperty(_p.rscratch, propName, prefix); } }; // for empty text, skip all processing if (!text) { return ''; } if (textTransform == 'none') { // passthrough } else if (textTransform == 'uppercase') { text = text.toUpperCase(); } else if (textTransform == 'lowercase') { text = text.toLowerCase(); } var wrapStyle = ele.pstyle('text-wrap').value; if (wrapStyle === 'wrap') { //console.log('wrap'); var labelKey = rscratch('labelKey'); // save recalc if the label is the same as before if (labelKey && rscratch('labelWrapKey') === labelKey) { // console.log('wrap cache hit'); return rscratch('labelWrapCachedText'); } // console.log('wrap cache miss'); var lines = text.split('\n'); var maxW = ele.pstyle('text-max-width').pfValue; var wrappedLines = []; for (var l = 0; l < lines.length; l++) { var line = lines[l]; var lineDims = this.calculateLabelDimensions(ele, line, 'line=' + line); var lineW = lineDims.width; if (lineW > maxW) { // line is too long var words = line.split(/\s+/); // NB: assume collapsed whitespace into single space var subline = ''; for (var w = 0; w < words.length; w++) { var word = words[w]; var testLine = subline.length === 0 ? word : subline + ' ' + word; var testDims = this.calculateLabelDimensions(ele, testLine, 'testLine=' + testLine); var testW = testDims.width; if (testW <= maxW) { // word fits on current line subline += word + ' '; } else { // word starts new line wrappedLines.push(subline); subline = word + ' '; } } // if there's remaining text, put it in a wrapped line if (!subline.match(/^\s+$/)) { wrappedLines.push(subline); } } else { // line is already short enough wrappedLines.push(line); } } // for rscratch('labelWrapCachedLines', wrappedLines); text = rscratch('labelWrapCachedText', wrappedLines.join('\n')); rscratch('labelWrapKey', labelKey); // console.log(text) } else if (wrapStyle === 'ellipsis') { var maxW = ele.pstyle('text-max-width').pfValue; var ellipsized = ''; var ellipsis = '\u2026'; var incLastCh = false; for (var i = 0; i < text.length; i++) { var widthWithNextCh = this.calculateLabelDimensions(ele, ellipsized + text[i] + ellipsis).width; if (widthWithNextCh > maxW) { break; } ellipsized += text[i]; if (i === text.length - 1) { incLastCh = true; } } if (!incLastCh) { ellipsized += ellipsis; } return ellipsized; } // if ellipsize return text; }; BRp.calculateLabelDimensions = function (ele, text, extraKey) { var r = this; var cacheKey = ele._private.labelStyleKey + '$@$' + text; if (extraKey) { cacheKey += '$@$' + extraKey; } var cache = r.labelDimCache || (r.labelDimCache = {}); if (cache[cacheKey]) { return cache[cacheKey]; } var sizeMult = 1; // increase the scale to increase accuracy w.r.t. zoomed text var fStyle = ele.pstyle('font-style').strValue; var size = sizeMult * ele.pstyle('font-size').pfValue + 'px'; var family = ele.pstyle('font-family').strValue; var weight = ele.pstyle('font-weight').strValue; var div = this.labelCalcDiv; if (!div) { div = this.labelCalcDiv = document.createElement('div'); // eslint-disable-line no-undef document.body.appendChild(div); // eslint-disable-line no-undef } var ds = div.style; // from ele style ds.fontFamily = family; ds.fontStyle = fStyle; ds.fontSize = size; ds.fontWeight = weight; // forced style ds.position = 'absolute'; ds.left = '-9999px'; ds.top = '-9999px'; ds.zIndex = '-1'; ds.visibility = 'hidden'; ds.pointerEvents = 'none'; ds.padding = '0'; ds.lineHeight = '1'; if (ele.pstyle('text-wrap').value === 'wrap') { ds.whiteSpace = 'pre'; // so newlines are taken into account } else { ds.whiteSpace = 'normal'; } // put label content in div div.textContent = text; cache[cacheKey] = { width: Math.ceil(div.clientWidth / sizeMult), height: Math.ceil(div.clientHeight / sizeMult) }; return cache[cacheKey]; }; BRp.calculateLabelAngles = function (ele) { var _p = ele._private; var rs = _p.rscratch; var isEdge = ele.isEdge(); var rot = ele.pstyle('text-rotation'); var rotStr = rot.strValue; if (rotStr === 'none') { rs.labelAngle = rs.sourceLabelAngle = rs.targetLabelAngle = 0; } else if (isEdge && rotStr === 'autorotate') { rs.labelAngle = rs.labelAutoAngle; rs.sourceLabelAngle = rs.sourceLabelAutoAngle; rs.targetLabelAngle = rs.targetLabelAutoAngle; } else if (rotStr === 'autorotate') { rs.labelAngle = rs.sourceLabelAngle = rs.targetLabelAngle = 0; } else { rs.labelAngle = rs.sourceLabelAngle = rs.targetLabelAngle = rot.pfValue; } }; module.exports = BRp; /***/ }), /* 117 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var BRp = {}; BRp.getNodeShape = function (node) { var r = this; var shape = node.pstyle('shape').value; if (node.isParent()) { if (shape === 'rectangle' || shape === 'roundrectangle' || shape === 'cutrectangle' || shape === 'barrel') { return shape; } else { return 'rectangle'; } } if (shape === 'polygon') { var points = node.pstyle('shape-polygon-points').value; return r.nodeShapes.makePolygon(points).name; } return shape; }; module.exports = BRp; /***/ }), /* 118 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var BRp = {}; BRp.registerCalculationListeners = function () { var cy = this.cy; var elesToUpdate = cy.collection(); var r = this; var enqueue = function enqueue(eles, e) { var dirtyStyleCaches = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; elesToUpdate.merge(eles); for (var i = 0; i < eles.length; i++) { var ele = eles[i]; var _p = ele._private; var rstyle = _p.rstyle; if (dirtyStyleCaches) { rstyle.clean = false; _p.bbCache = null; } var evts = rstyle.dirtyEvents = rstyle.dirtyEvents || { length: 0 }; if (!evts[e.type]) { evts[e.type] = true; evts.length++; } } }; r.binder(cy) // nodes .on('position.* style.* free.* bounds.*', 'node', function onDirtyModNode(e) { var node = e.target; enqueue(node, e); enqueue(node.connectedEdges(), e); }).on('add.*', 'node', function onDirtyAddNode(e) { var ele = e.target; enqueue(ele, e); }).on('background.*', 'node', function onDirtyBgNode(e) { var ele = e.target; enqueue(ele, e, false); }) // edges .on('add.* style.*', 'edge', function onDirtyEdge(e) { var edge = e.target; enqueue(edge, e); enqueue(edge.parallelEdges(), e); }).on('remove.*', 'edge', function onDirtyRemoveEdge(e) { var edge = e.target; var pEdges = edge.parallelEdges(); for (var i = 0; i < pEdges.length; i++) { var pEdge = pEdges[i]; if (!pEdge.removed()) { enqueue(pEdge, e); } } }) // manual dirtying .on('dirty.*', 'node', function onDirtyEle(e) { var ele = e.target; enqueue(ele, e); }); var updateEleCalcs = function updateEleCalcs(willDraw) { if (willDraw) { var fns = r.onUpdateEleCalcsFns; if (fns) { for (var i = 0; i < fns.length; i++) { var fn = fns[i]; fn(willDraw, elesToUpdate); } } r.recalculateRenderedStyle(elesToUpdate, false); for (var i = 0; i < elesToUpdate.length; i++) { elesToUpdate[i]._private.rstyle.dirtyEvents = null; } elesToUpdate = cy.collection(); } }; r.beforeRender(updateEleCalcs, r.beforeRenderPriorities.eleCalcs); }; BRp.onUpdateEleCalcs = function (fn) { var fns = this.onUpdateEleCalcsFns = this.onUpdateEleCalcsFns || []; fns.push(fn); }; BRp.recalculateRenderedStyle = function (eles, useCache) { var edges = []; var nodes = []; // the renderer can't be used for calcs when destroyed, e.g. ele.boundingBox() if (this.destroyed) { return; } // use cache by default for perf if (useCache === undefined) { useCache = true; } for (var i = 0; i < eles.length; i++) { var ele = eles[i]; var _p = ele._private; var rstyle = _p.rstyle; // only update if dirty and in graph if (useCache && rstyle.clean || ele.removed()) { continue; } // only update if not display: none if (ele.pstyle('display').value === 'none') { continue; } if (_p.group === 'nodes') { nodes.push(ele); } else { // edges edges.push(ele); } rstyle.clean = true; // rstyle.dirtyEvents = null; } // update node data from projections for (var i = 0; i < nodes.length; i++) { var ele = nodes[i]; var _p = ele._private; var rstyle = _p.rstyle; var pos = ele.position(); this.recalculateNodeLabelProjection(ele); rstyle.nodeX = pos.x; rstyle.nodeY = pos.y; rstyle.nodeW = ele.pstyle('width').pfValue; rstyle.nodeH = ele.pstyle('height').pfValue; } this.recalculateEdgeProjections(edges); // update edge data from projections for (var i = 0; i < edges.length; i++) { var ele = edges[i]; var _p = ele._private; var rstyle = _p.rstyle; var rs = _p.rscratch; this.recalculateEdgeLabelProjections(ele); // update rstyle positions rstyle.srcX = rs.arrowStartX; rstyle.srcY = rs.arrowStartY; rstyle.tgtX = rs.arrowEndX; rstyle.tgtY = rs.arrowEndY; rstyle.midX = rs.midX; rstyle.midY = rs.midY; rstyle.labelAngle = rs.labelAngle; rstyle.sourceLabelAngle = rs.sourceLabelAngle; rstyle.targetLabelAngle = rs.targetLabelAngle; } }; module.exports = BRp; /***/ }), /* 119 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var zIndexSort = __webpack_require__(17); var BRp = {}; BRp.updateCachedGrabbedEles = function () { var eles = this.cachedZSortedEles; if (!eles) { // just let this be recalculated on the next z sort tick return; } eles.drag = []; eles.nondrag = []; var grabTargets = []; for (var i = 0; i < eles.length; i++) { var ele = eles[i]; var rs = ele._private.rscratch; if (ele.grabbed() && !ele.isParent()) { grabTargets.push(ele); } else if (rs.inDragLayer) { eles.drag.push(ele); } else { eles.nondrag.push(ele); } } // put the grab target nodes last so it's on top of its neighbourhood for (var i = 0; i < grabTargets.length; i++) { var ele = grabTargets[i]; eles.drag.push(ele); } }; BRp.invalidateCachedZSortedEles = function () { this.cachedZSortedEles = null; }; BRp.getCachedZSortedEles = function (forceRecalc) { if (forceRecalc || !this.cachedZSortedEles) { //console.time('cachezorder') var eles = this.cy.mutableElements().toArray(); eles.sort(zIndexSort); eles.interactive = eles.filter(function (ele) { return ele.interactive(); }); this.cachedZSortedEles = eles; this.updateCachedGrabbedEles(); } else { eles = this.cachedZSortedEles; } return eles; }; module.exports = BRp; /***/ }), /* 120 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var BRp = {}; BRp.getCachedImage = function (url, crossOrigin, onLoad) { var r = this; var imageCache = r.imageCache = r.imageCache || {}; var cache = imageCache[url]; if (cache) { if (!cache.image.complete) { cache.image.addEventListener('load', onLoad); } return cache.image; } else { cache = imageCache[url] = imageCache[url] || {}; var image = cache.image = new Image(); // eslint-disable-line no-undef image.addEventListener('load', onLoad); image.addEventListener('error', function () { image.error = true; }); // #1582 safari doesn't load data uris with crossOrigin properly // https://bugs.webkit.org/show_bug.cgi?id=123978 var dataUriPrefix = 'data:'; var isDataUri = url.substring(0, dataUriPrefix.length).toLowerCase() === dataUriPrefix; if (!isDataUri) { image.crossOrigin = crossOrigin; // prevent tainted canvas } image.src = url; return image; } }; module.exports = BRp; /***/ }), /* 121 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var util = __webpack_require__(1); var math = __webpack_require__(2); var Event = __webpack_require__(16); var BRp = {}; BRp.registerBinding = function (target, event, handler, useCapture) { var args = Array.prototype.slice.apply(arguments, [1]); // copy var b = this.binder(target); return b.on.apply(b, args); }; BRp.binder = function (tgt) { var r = this; var tgtIsDom = tgt === window || tgt === document || tgt === document.body || is.domElement(tgt); if (r.supportsPassiveEvents == null) { // from https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection var supportsPassive = false; try { var opts = Object.defineProperty({}, 'passive', { get: function get() { supportsPassive = true; } }); window.addEventListener('test', null, opts); } catch (err) {} r.supportsPassiveEvents = supportsPassive; } var on = function on(event, handler, useCapture) { var args = Array.prototype.slice.call(arguments); if (tgtIsDom && r.supportsPassiveEvents) { // replace useCapture w/ opts obj args[2] = { capture: useCapture != null ? useCapture : false, passive: false, once: false }; } r.bindings.push({ target: tgt, args: args }); (tgt.addEventListener || tgt.on).apply(tgt, args); return this; }; return { on: on, addEventListener: on, addListener: on, bind: on }; }; BRp.nodeIsDraggable = function (node) { return node && node.isNode() && !node.locked() && node.grabbable(); }; BRp.nodeIsGrabbable = function (node) { return this.nodeIsDraggable(node) && node.interactive(); }; BRp.load = function () { var r = this; var triggerEvents = function triggerEvents(target, names, e, props) { if (target == null) { target = r.cy; } for (var i = 0; i < names.length; i++) { var name = names[i]; target.emit(util.extend({ originalEvent: e, type: name }, props)); } }; var isMultSelKeyDown = function isMultSelKeyDown(e) { return e.shiftKey || e.metaKey || e.ctrlKey; // maybe e.altKey }; var allowPanningPassthrough = function allowPanningPassthrough(down, downs) { var allowPassthrough = true; if (r.cy.hasCompoundNodes() && down && down.isEdge()) { // a compound node below the edge => no passthrough panning for (var i = 0; downs && i < downs.length; i++) { var down = downs[i]; if (down.isNode() && down.isParent()) { allowPassthrough = false; break; } } } else { allowPassthrough = true; } return allowPassthrough; }; var getDragListIds = function getDragListIds(opts) { var listHasId; if (opts.addToList && r.cy.hasCompoundNodes()) { // only needed for compound graphs if (!opts.addToList.hasId) { // build ids lookup if doesn't already exist opts.addToList.hasId = {}; for (var i = 0; i < opts.addToList.length; i++) { var ele = opts.addToList[i]; opts.addToList.hasId[ele.id()] = true; } } listHasId = opts.addToList.hasId; } return listHasId || {}; }; var setGrabbed = function setGrabbed(ele) { ele[0]._private.grabbed = true; }; var setFreed = function setFreed(ele) { ele[0]._private.grabbed = false; }; var setInDragLayer = function setInDragLayer(ele) { ele[0]._private.rscratch.inDragLayer = true; }; var setOutDragLayer = function setOutDragLayer(ele) { ele[0]._private.rscratch.inDragLayer = false; }; var setGrabTarget = function setGrabTarget(ele) { ele[0]._private.rscratch.isGrabTarget = true; }; var removeGrabTarget = function removeGrabTarget(ele) { ele[0]._private.rscratch.isGrabTarget = false; }; var addToDragList = function addToDragList(ele, opts) { var listHasId = getDragListIds(opts); if (!listHasId[ele.id()]) { opts.addToList.push(ele); listHasId[ele.id()] = true; setGrabbed(ele); } }; // helper function to determine which child nodes and inner edges // of a compound node to be dragged as well as the grabbed and selected nodes var addDescendantsToDrag = function addDescendantsToDrag(node, opts) { if (!node.cy().hasCompoundNodes()) { return; } if (opts.inDragLayer == null && opts.addToList == null) { return; } // nothing to do var innerNodes = node.descendants(); if (opts.inDragLayer) { innerNodes.forEach(setInDragLayer); innerNodes.connectedEdges().forEach(setInDragLayer); } if (opts.addToList) { innerNodes.forEach(function (ele) { addToDragList(ele, opts); }); } }; // adds the given nodes and its neighbourhood to the drag layer var addNodesToDrag = function addNodesToDrag(nodes, opts) { opts = opts || {}; var hasCompoundNodes = nodes.cy().hasCompoundNodes(); if (opts.inDragLayer) { nodes.forEach(setInDragLayer); nodes.neighborhood().stdFilter(function (ele) { return !hasCompoundNodes || ele.isEdge(); }).forEach(setInDragLayer); } if (opts.addToList) { nodes.forEach(function (ele) { addToDragList(ele, opts); }); } addDescendantsToDrag(nodes, opts); // always add to drag // also add nodes and edges related to the topmost ancestor updateAncestorsInDragLayer(nodes, { inDragLayer: opts.inDragLayer }); r.updateCachedGrabbedEles(); }; var addNodeToDrag = addNodesToDrag; var freeDraggedElements = function freeDraggedElements(grabbedEles) { if (!grabbedEles) { return; } grabbedEles.hasId = {}; // clear the id list // just go over all elements rather than doing a bunch of (possibly expensive) traversals r.getCachedZSortedEles().forEach(function (ele) { setFreed(ele); setOutDragLayer(ele); removeGrabTarget(ele); }); r.updateCachedGrabbedEles(); }; // helper function to determine which ancestor nodes and edges should go // to the drag layer (or should be removed from drag layer). var updateAncestorsInDragLayer = function updateAncestorsInDragLayer(node, opts) { if (opts.inDragLayer == null && opts.addToList == null) { return; } // nothing to do if (!node.cy().hasCompoundNodes()) { return; } // find top-level parent var parent = node.ancestors().orphans(); // no parent node: no nodes to add to the drag layer if (parent.same(node)) { return; } var nodes = parent.descendants().spawnSelf().merge(parent).unmerge(node).unmerge(node.descendants()); var edges = nodes.connectedEdges(); if (opts.inDragLayer) { edges.forEach(setInDragLayer); nodes.forEach(setInDragLayer); } if (opts.addToList) { nodes.forEach(function (ele) { addToDragList(ele, opts); }); } }; var blurActiveDomElement = function blurActiveDomElement() { if (document.activeElement != null && document.activeElement.blur != null) { document.activeElement.blur(); } }; var haveMutationsApi = typeof MutationObserver !== 'undefined'; // watch for when the cy container is removed from the dom if (haveMutationsApi) { r.removeObserver = new MutationObserver(function (mutns) { // eslint-disable-line no-undef for (var i = 0; i < mutns.length; i++) { var mutn = mutns[i]; var rNodes = mutn.removedNodes; if (rNodes) { for (var j = 0; j < rNodes.length; j++) { var rNode = rNodes[j]; if (rNode === r.container) { r.destroy(); break; } } } } }); if (r.container.parentNode) { r.removeObserver.observe(r.container.parentNode, { childList: true }); } } else { r.registerBinding(r.container, 'DOMNodeRemoved', function (e) { r.destroy(); }); } var onResize = util.debounce(function () { r.cy.resize(); }, 100); if (haveMutationsApi) { r.styleObserver = new MutationObserver(onResize); // eslint-disable-line no-undef r.styleObserver.observe(r.container, { attributes: true }); } // auto resize r.registerBinding(window, 'resize', onResize); // eslint-disable-line no-undef var forEachUp = function forEachUp(domEle, fn) { while (domEle != null) { fn(domEle); domEle = domEle.parentNode; } }; var invalidateCoords = function invalidateCoords() { r.invalidateContainerClientCoordsCache(); }; forEachUp(r.container, function (domEle) { r.registerBinding(domEle, 'transitionend', invalidateCoords); r.registerBinding(domEle, 'animationend', invalidateCoords); r.registerBinding(domEle, 'scroll', invalidateCoords); }); // stop right click menu from appearing on cy r.registerBinding(r.container, 'contextmenu', function (e) { e.preventDefault(); }); var inBoxSelection = function inBoxSelection() { return r.selection[4] !== 0; }; var eventInContainer = function eventInContainer(e) { // save cycles if mouse events aren't to be captured var containerPageCoords = r.findContainerClientCoords(); var x = containerPageCoords[0]; var y = containerPageCoords[1]; var width = containerPageCoords[2]; var height = containerPageCoords[3]; var positions = e.touches ? e.touches : [e]; var atLeastOnePosInside = false; for (var i = 0; i < positions.length; i++) { var p = positions[i]; if (x <= p.clientX && p.clientX <= x + width && y <= p.clientY && p.clientY <= y + height) { atLeastOnePosInside = true; break; } } if (!atLeastOnePosInside) { return false; } var container = r.container; var target = e.target; var tParent = target.parentNode; var containerIsTarget = false; while (tParent) { if (tParent === container) { containerIsTarget = true; break; } tParent = tParent.parentNode; } if (!containerIsTarget) { return false; } // if target is outisde cy container, then this event is not for us return true; }; // Primary key r.registerBinding(r.container, 'mousedown', function mousedownHandler(e) { if (!eventInContainer(e)) { return; } e.preventDefault(); blurActiveDomElement(); r.hoverData.capture = true; r.hoverData.which = e.which; var cy = r.cy; var gpos = [e.clientX, e.clientY]; var pos = r.projectIntoViewport(gpos[0], gpos[1]); var select = r.selection; var nears = r.findNearestElements(pos[0], pos[1], true, false); var near = nears[0]; var draggedElements = r.dragData.possibleDragElements; r.hoverData.mdownPos = pos; r.hoverData.mdownGPos = gpos; var checkForTaphold = function checkForTaphold() { r.hoverData.tapholdCancelled = false; clearTimeout(r.hoverData.tapholdTimeout); r.hoverData.tapholdTimeout = setTimeout(function () { if (r.hoverData.tapholdCancelled) { return; } else { var ele = r.hoverData.down; if (ele) { ele.emit({ originalEvent: e, type: 'taphold', position: { x: pos[0], y: pos[1] } }); } else { cy.emit({ originalEvent: e, type: 'taphold', position: { x: pos[0], y: pos[1] } }); } } }, r.tapholdDuration); }; // Right click button if (e.which == 3) { r.hoverData.cxtStarted = true; var cxtEvt = { originalEvent: e, type: 'cxttapstart', position: { x: pos[0], y: pos[1] } }; if (near) { near.activate(); near.emit(cxtEvt); r.hoverData.down = near; } else { cy.emit(cxtEvt); } r.hoverData.downTime = new Date().getTime(); r.hoverData.cxtDragged = false; // Primary button } else if (e.which == 1) { if (near) { near.activate(); } // Element dragging { // If something is under the cursor and it is draggable, prepare to grab it if (near != null) { if (r.nodeIsGrabbable(near)) { var makeEvent = function makeEvent(type) { return { originalEvent: e, type: type, position: { x: pos[0], y: pos[1] } }; }; var triggerGrab = function triggerGrab(ele) { ele.emit(makeEvent('grab')); }; setGrabTarget(near); if (!near.selected()) { draggedElements = r.dragData.possibleDragElements = []; addNodeToDrag(near, { addToList: draggedElements }); near.emit(makeEvent('grabon')).emit(makeEvent('grab')); } else { draggedElements = r.dragData.possibleDragElements = []; var selectedNodes = cy.$(function (ele) { return ele.isNode() && ele.selected() && r.nodeIsGrabbable(ele); }); addNodesToDrag(selectedNodes, { addToList: draggedElements }); near.emit(makeEvent('grabon')); selectedNodes.forEach(triggerGrab); } r.redrawHint('eles', true); r.redrawHint('drag', true); } } r.hoverData.down = near; r.hoverData.downs = nears; r.hoverData.downTime = new Date().getTime(); } triggerEvents(near, ['mousedown', 'tapstart', 'vmousedown'], e, { position: { x: pos[0], y: pos[1] } }); if (near == null) { select[4] = 1; r.data.bgActivePosistion = { x: pos[0], y: pos[1] }; r.redrawHint('select', true); r.redraw(); } else if (near.isEdge()) { select[4] = 1; // for future pan } checkForTaphold(); } // Initialize selection box coordinates select[0] = select[2] = pos[0]; select[1] = select[3] = pos[1]; }, false); r.registerBinding(window, 'mousemove', function mousemoveHandler(e) { // eslint-disable-line no-undef var capture = r.hoverData.capture; if (!capture && !eventInContainer(e)) { return; } var preventDefault = false; var cy = r.cy; var zoom = cy.zoom(); var gpos = [e.clientX, e.clientY]; var pos = r.projectIntoViewport(gpos[0], gpos[1]); var mdownPos = r.hoverData.mdownPos; var mdownGPos = r.hoverData.mdownGPos; var select = r.selection; var near = null; if (!r.hoverData.draggingEles && !r.hoverData.dragging && !r.hoverData.selecting) { near = r.findNearestElement(pos[0], pos[1], true, false); } var last = r.hoverData.last; var down = r.hoverData.down; var disp = [pos[0] - select[2], pos[1] - select[3]]; var draggedElements = r.dragData.possibleDragElements; var isOverThresholdDrag; if (mdownGPos) { var dx = gpos[0] - mdownGPos[0]; var dx2 = dx * dx; var dy = gpos[1] - mdownGPos[1]; var dy2 = dy * dy; var dist2 = dx2 + dy2; r.hoverData.isOverThresholdDrag = isOverThresholdDrag = dist2 >= r.desktopTapThreshold2; } var multSelKeyDown = isMultSelKeyDown(e); if (isOverThresholdDrag) { r.hoverData.tapholdCancelled = true; } var updateDragDelta = function updateDragDelta() { var dragDelta = r.hoverData.dragDelta = r.hoverData.dragDelta || []; if (dragDelta.length === 0) { dragDelta.push(disp[0]); dragDelta.push(disp[1]); } else { dragDelta[0] += disp[0]; dragDelta[1] += disp[1]; } }; preventDefault = true; triggerEvents(near, ['mousemove', 'vmousemove', 'tapdrag'], e, { position: { x: pos[0], y: pos[1] } }); var goIntoBoxMode = function goIntoBoxMode() { r.data.bgActivePosistion = undefined; if (!r.hoverData.selecting) { cy.emit('boxstart'); } select[4] = 1; r.hoverData.selecting = true; r.redrawHint('select', true); r.redraw(); }; // trigger context drag if rmouse down if (r.hoverData.which === 3) { // but only if over threshold if (isOverThresholdDrag) { var cxtEvt = { originalEvent: e, type: 'cxtdrag', position: { x: pos[0], y: pos[1] } }; if (down) { down.emit(cxtEvt); } else { cy.emit(cxtEvt); } r.hoverData.cxtDragged = true; if (!r.hoverData.cxtOver || near !== r.hoverData.cxtOver) { if (r.hoverData.cxtOver) { r.hoverData.cxtOver.emit({ originalEvent: e, type: 'cxtdragout', position: { x: pos[0], y: pos[1] } }); } r.hoverData.cxtOver = near; if (near) { near.emit({ originalEvent: e, type: 'cxtdragover', position: { x: pos[0], y: pos[1] } }); } } } // Check if we are drag panning the entire graph } else if (r.hoverData.dragging) { preventDefault = true; if (cy.panningEnabled() && cy.userPanningEnabled()) { var deltaP; if (r.hoverData.justStartedPan) { var mdPos = r.hoverData.mdownPos; deltaP = { x: (pos[0] - mdPos[0]) * zoom, y: (pos[1] - mdPos[1]) * zoom }; r.hoverData.justStartedPan = false; } else { deltaP = { x: disp[0] * zoom, y: disp[1] * zoom }; } cy.panBy(deltaP); r.hoverData.dragged = true; } // Needs reproject due to pan changing viewport pos = r.projectIntoViewport(e.clientX, e.clientY); // Checks primary button down & out of time & mouse not moved much } else if (select[4] == 1 && (down == null || down.isEdge())) { if (isOverThresholdDrag) { if (!r.hoverData.dragging && cy.boxSelectionEnabled() && (multSelKeyDown || !cy.panningEnabled() || !cy.userPanningEnabled())) { goIntoBoxMode(); } else if (!r.hoverData.selecting && cy.panningEnabled() && cy.userPanningEnabled()) { var allowPassthrough = allowPanningPassthrough(down, r.hoverData.downs); if (allowPassthrough) { r.hoverData.dragging = true; r.hoverData.justStartedPan = true; select[4] = 0; r.data.bgActivePosistion = math.array2point(mdownPos); r.redrawHint('select', true); r.redraw(); } } if (down && down.isEdge() && down.active()) { down.unactivate(); } } } else { if (down && down.isEdge() && down.active()) { down.unactivate(); } if ((!down || !down.grabbed()) && near != last) { if (last) { triggerEvents(last, ['mouseout', 'tapdragout'], e, { position: { x: pos[0], y: pos[1] } }); } if (near) { triggerEvents(near, ['mouseover', 'tapdragover'], e, { position: { x: pos[0], y: pos[1] } }); } r.hoverData.last = near; } if (down) { if (isOverThresholdDrag) { // then we can take action if (cy.boxSelectionEnabled() && multSelKeyDown) { // then selection overrides if (down && down.grabbed()) { freeDraggedElements(draggedElements); down.emit('free'); } goIntoBoxMode(); } else if (down && down.grabbed() && r.nodeIsDraggable(down)) { // drag node var justStartedDrag = !r.dragData.didDrag; if (justStartedDrag) { r.redrawHint('eles', true); } r.dragData.didDrag = true; // indicate that we actually did drag the node var toTrigger = []; // now, add the elements to the drag layer if not done already if (!r.hoverData.draggingEles) { addNodesToDrag(cy.collection(draggedElements), { inDragLayer: true }); } for (var i = 0; i < draggedElements.length; i++) { var dEle = draggedElements[i]; // Locked nodes not draggable, as well as non-visible nodes if (r.nodeIsDraggable(dEle) && dEle.grabbed()) { var dPos = dEle.position(); toTrigger.push(dEle); if (is.number(disp[0]) && is.number(disp[1])) { dPos.x += disp[0]; dPos.y += disp[1]; if (justStartedDrag) { var dragDelta = r.hoverData.dragDelta; if (dragDelta && is.number(dragDelta[0]) && is.number(dragDelta[1])) { dPos.x += dragDelta[0]; dPos.y += dragDelta[1]; } } } } } r.hoverData.draggingEles = true; var tcol = cy.collection(toTrigger); tcol.dirtyCompoundBoundsCache(); tcol.emit('position drag'); r.redrawHint('drag', true); r.redraw(); } } else { // otherwise save drag delta for when we actually start dragging so the relative grab pos is constant updateDragDelta(); } } // prevent the dragging from triggering text selection on the page preventDefault = true; } select[2] = pos[0];select[3] = pos[1]; if (preventDefault) { if (e.stopPropagation) e.stopPropagation(); if (e.preventDefault) e.preventDefault(); return false; } }, false); r.registerBinding(window, 'mouseup', function mouseupHandler(e) { // eslint-disable-line no-undef var capture = r.hoverData.capture; if (!capture) { return; } r.hoverData.capture = false; var cy = r.cy;var pos = r.projectIntoViewport(e.clientX, e.clientY);var select = r.selection; var near = r.findNearestElement(pos[0], pos[1], true, false); var draggedElements = r.dragData.possibleDragElements;var down = r.hoverData.down; var multSelKeyDown = isMultSelKeyDown(e); if (r.data.bgActivePosistion) { r.redrawHint('select', true); r.redraw(); } r.hoverData.tapholdCancelled = true; r.data.bgActivePosistion = undefined; // not active bg now if (down) { down.unactivate(); } if (r.hoverData.which === 3) { var cxtEvt = { originalEvent: e, type: 'cxttapend', position: { x: pos[0], y: pos[1] } }; if (down) { down.emit(cxtEvt); } else { cy.emit(cxtEvt); } if (!r.hoverData.cxtDragged) { var cxtTap = { originalEvent: e, type: 'cxttap', position: { x: pos[0], y: pos[1] } }; if (down) { down.emit(cxtTap); } else { cy.emit(cxtTap); } } r.hoverData.cxtDragged = false; r.hoverData.which = null; } else if (r.hoverData.which === 1) { // Deselect all elements if nothing is currently under the mouse cursor and we aren't dragging something if (down == null && // not mousedown on node !r.dragData.didDrag // didn't move the node around && !r.hoverData.selecting // not box selection && !r.hoverData.dragged // didn't pan && !isMultSelKeyDown(e)) { cy.$(function (ele) { return ele.selected(); }).unselect(); if (draggedElements.length > 0) { r.redrawHint('eles', true); } r.dragData.possibleDragElements = draggedElements = []; } triggerEvents(near, ['mouseup', 'tapend', 'vmouseup'], e, { position: { x: pos[0], y: pos[1] } }); if (!r.dragData.didDrag // didn't move a node around && !r.hoverData.dragged // didn't pan && !r.hoverData.selecting // not box selection && !r.hoverData.isOverThresholdDrag // didn't move too much ) { triggerEvents(down, ['click', 'tap', 'vclick'], e, { position: { x: pos[0], y: pos[1] } }); } // Single selection if (near == down && !r.dragData.didDrag && !r.hoverData.selecting) { if (near != null && near._private.selectable) { if (r.hoverData.dragging) { // if panning, don't change selection state } else if (cy.selectionType() === 'additive' || multSelKeyDown) { if (near.selected()) { near.unselect(); } else { near.select(); } } else { if (!multSelKeyDown) { cy.$(':selected').unmerge(near).unselect(); near.select(); } } r.redrawHint('eles', true); } } if (r.hoverData.selecting) { var box = cy.collection(r.getAllInBox(select[0], select[1], select[2], select[3])); r.redrawHint('select', true); if (box.length > 0) { r.redrawHint('eles', true); } cy.emit('boxend'); var eleWouldBeSelected = function eleWouldBeSelected(ele) { return ele.selectable() && !ele.selected(); }; if (cy.selectionType() === 'additive') { box.emit('box').stdFilter(eleWouldBeSelected).select().emit('boxselect'); } else { if (!multSelKeyDown) { cy.$(':selected').unmerge(box).unselect(); } box.emit('box').stdFilter(eleWouldBeSelected).select().emit('boxselect'); } // always need redraw in case eles unselectable r.redraw(); } // Cancel drag pan if (r.hoverData.dragging) { r.hoverData.dragging = false; r.redrawHint('select', true); r.redrawHint('eles', true); r.redraw(); } if (!select[4]) { r.redrawHint('drag', true); r.redrawHint('eles', true); var downWasGrabbed = down && down.grabbed(); freeDraggedElements(draggedElements); if (downWasGrabbed) { down.emit('free'); } } } // else not right mouse select[4] = 0;r.hoverData.down = null; r.hoverData.cxtStarted = false; r.hoverData.draggingEles = false; r.hoverData.selecting = false; r.hoverData.isOverThresholdDrag = false; r.dragData.didDrag = false; r.hoverData.dragged = false; r.hoverData.dragDelta = []; r.hoverData.mdownPos = null; r.hoverData.mdownGPos = null; }, false); var wheelHandler = function wheelHandler(e) { if (r.scrollingPage) { return; } // while scrolling, ignore wheel-to-zoom var cy = r.cy; var pos = r.projectIntoViewport(e.clientX, e.clientY); var rpos = [pos[0] * cy.zoom() + cy.pan().x, pos[1] * cy.zoom() + cy.pan().y]; if (r.hoverData.draggingEles || r.hoverData.dragging || r.hoverData.cxtStarted || inBoxSelection()) { // if pan dragging or cxt dragging, wheel movements make no zoom e.preventDefault(); return; } if (cy.panningEnabled() && cy.userPanningEnabled() && cy.zoomingEnabled() && cy.userZoomingEnabled()) { e.preventDefault(); r.data.wheelZooming = true; clearTimeout(r.data.wheelTimeout); r.data.wheelTimeout = setTimeout(function () { r.data.wheelZooming = false; r.redrawHint('eles', true); r.redraw(); }, 150); var diff; if (e.deltaY != null) { diff = e.deltaY / -250; } else if (e.wheelDeltaY != null) { diff = e.wheelDeltaY / 1000; } else { diff = e.wheelDelta / 1000; } diff = diff * r.wheelSensitivity; var needsWheelFix = e.deltaMode === 1; if (needsWheelFix) { // fixes slow wheel events on ff/linux and ff/windows diff *= 33; } cy.zoom({ level: cy.zoom() * Math.pow(10, diff), renderedPosition: { x: rpos[0], y: rpos[1] } }); } }; // Functions to help with whether mouse wheel should trigger zooming // -- r.registerBinding(r.container, 'wheel', wheelHandler, true); // disable nonstandard wheel events // r.registerBinding(r.container, 'mousewheel', wheelHandler, true); // r.registerBinding(r.container, 'DOMMouseScroll', wheelHandler, true); // r.registerBinding(r.container, 'MozMousePixelScroll', wheelHandler, true); // older firefox r.registerBinding(window, 'scroll', function scrollHandler(e) { // eslint-disable-line no-undef r.scrollingPage = true; clearTimeout(r.scrollingPageTimeout); r.scrollingPageTimeout = setTimeout(function () { r.scrollingPage = false; }, 250); }, true); // Functions to help with handling mouseout/mouseover on the Cytoscape container // Handle mouseout on Cytoscape container r.registerBinding(r.container, 'mouseout', function mouseOutHandler(e) { var pos = r.projectIntoViewport(e.clientX, e.clientY); r.cy.emit({ originalEvent: e, type: 'mouseout', position: { x: pos[0], y: pos[1] } }); }, false); r.registerBinding(r.container, 'mouseover', function mouseOverHandler(e) { var pos = r.projectIntoViewport(e.clientX, e.clientY); r.cy.emit({ originalEvent: e, type: 'mouseover', position: { x: pos[0], y: pos[1] } }); }, false); var f1x1, f1y1, f2x1, f2y1; // starting points for pinch-to-zoom var distance1, distance1Sq; // initial distance between finger 1 and finger 2 for pinch-to-zoom var center1, modelCenter1; // center point on start pinch to zoom var offsetLeft, offsetTop; var containerWidth, containerHeight; var twoFingersStartInside; var distance = function distance(x1, y1, x2, y2) { return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); }; var distanceSq = function distanceSq(x1, y1, x2, y2) { return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); }; var touchstartHandler; r.registerBinding(r.container, 'touchstart', touchstartHandler = function touchstartHandler(e) { if (!eventInContainer(e)) { return; } blurActiveDomElement(); r.touchData.capture = true; r.data.bgActivePosistion = undefined; var cy = r.cy; var now = r.touchData.now; var earlier = r.touchData.earlier; if (e.touches[0]) { var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY);now[0] = pos[0];now[1] = pos[1]; } if (e.touches[1]) { var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY);now[2] = pos[0];now[3] = pos[1]; } if (e.touches[2]) { var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY);now[4] = pos[0];now[5] = pos[1]; } // record starting points for pinch-to-zoom if (e.touches[1]) { freeDraggedElements(r.dragData.touchDragEles); var offsets = r.findContainerClientCoords(); offsetLeft = offsets[0]; offsetTop = offsets[1]; containerWidth = offsets[2]; containerHeight = offsets[3]; f1x1 = e.touches[0].clientX - offsetLeft; f1y1 = e.touches[0].clientY - offsetTop; f2x1 = e.touches[1].clientX - offsetLeft; f2y1 = e.touches[1].clientY - offsetTop; twoFingersStartInside = 0 <= f1x1 && f1x1 <= containerWidth && 0 <= f2x1 && f2x1 <= containerWidth && 0 <= f1y1 && f1y1 <= containerHeight && 0 <= f2y1 && f2y1 <= containerHeight; var pan = cy.pan(); var zoom = cy.zoom(); distance1 = distance(f1x1, f1y1, f2x1, f2y1); distance1Sq = distanceSq(f1x1, f1y1, f2x1, f2y1); center1 = [(f1x1 + f2x1) / 2, (f1y1 + f2y1) / 2]; modelCenter1 = [(center1[0] - pan.x) / zoom, (center1[1] - pan.y) / zoom]; // consider context tap var cxtDistThreshold = 200; var cxtDistThresholdSq = cxtDistThreshold * cxtDistThreshold; if (distance1Sq < cxtDistThresholdSq && !e.touches[2]) { var near1 = r.findNearestElement(now[0], now[1], true, true); var near2 = r.findNearestElement(now[2], now[3], true, true); if (near1 && near1.isNode()) { near1.activate().emit({ originalEvent: e, type: 'cxttapstart', position: { x: now[0], y: now[1] } }); r.touchData.start = near1; } else if (near2 && near2.isNode()) { near2.activate().emit({ originalEvent: e, type: 'cxttapstart', position: { x: now[0], y: now[1] } }); r.touchData.start = near2; } else { cy.emit({ originalEvent: e, type: 'cxttapstart', position: { x: now[0], y: now[1] } }); } if (r.touchData.start) { r.touchData.start._private.grabbed = false; } r.touchData.cxt = true; r.touchData.cxtDragged = false; r.data.bgActivePosistion = undefined; r.redraw(); return; } } if (e.touches[2]) { // ignore } else if (e.touches[1]) { // ignore } else if (e.touches[0]) { var nears = r.findNearestElements(now[0], now[1], true, true); var near = nears[0]; if (near != null) { near.activate(); r.touchData.start = near; r.touchData.starts = nears; if (r.nodeIsGrabbable(near)) { var draggedEles = r.dragData.touchDragEles = []; var selectedNodes = null; r.redrawHint('eles', true); r.redrawHint('drag', true); if (near.selected()) { // reset drag elements, since near will be added again selectedNodes = cy.$(function (ele) { return ele.selected() && r.nodeIsGrabbable(ele); }); addNodesToDrag(selectedNodes, { addToList: draggedEles }); } else { addNodeToDrag(near, { addToList: draggedEles }); } setGrabTarget(near); var makeEvent = function makeEvent(type) { return { originalEvent: e, type: type, position: { x: now[0], y: now[1] } }; }; near.emit(makeEvent('grabon')); if (selectedNodes) { selectedNodes.forEach(function (n) { n.emit(makeEvent('grab')); }); } else { near.emit(makeEvent('grab')); } } } triggerEvents(near, ['touchstart', 'tapstart', 'vmousedown'], e, { position: { x: now[0], y: now[1] } }); if (near == null) { r.data.bgActivePosistion = { x: pos[0], y: pos[1] }; r.redrawHint('select', true); r.redraw(); } // Tap, taphold // ----- r.touchData.singleTouchMoved = false; r.touchData.singleTouchStartTime = +new Date(); clearTimeout(r.touchData.tapholdTimeout); r.touchData.tapholdTimeout = setTimeout(function () { if (r.touchData.singleTouchMoved === false && !r.pinching // if pinching, then taphold unselect shouldn't take effect && !r.touchData.selecting // box selection shouldn't allow taphold through ) { triggerEvents(r.touchData.start, ['taphold'], e, { position: { x: now[0], y: now[1] } }); if (!r.touchData.start) { cy.$(':selected').unselect(); } } }, r.tapholdDuration); } if (e.touches.length >= 1) { var sPos = r.touchData.startPosition = []; for (var i = 0; i < now.length; i++) { sPos[i] = earlier[i] = now[i]; } var touch0 = e.touches[0]; r.touchData.startGPosition = [touch0.clientX, touch0.clientY]; } }, false); var touchmoveHandler; r.registerBinding(window, 'touchmove', touchmoveHandler = function touchmoveHandler(e) { // eslint-disable-line no-undef var capture = r.touchData.capture; if (!capture && !eventInContainer(e)) { return; } var select = r.selection; var cy = r.cy; var now = r.touchData.now; var earlier = r.touchData.earlier; var zoom = cy.zoom(); if (e.touches[0]) { var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY);now[0] = pos[0];now[1] = pos[1]; } if (e.touches[1]) { var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY);now[2] = pos[0];now[3] = pos[1]; } if (e.touches[2]) { var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY);now[4] = pos[0];now[5] = pos[1]; } var startGPos = r.touchData.startGPosition; var isOverThresholdDrag; if (capture && e.touches[0] && startGPos) { var disp = [];for (var j = 0; j < now.length; j++) { disp[j] = now[j] - earlier[j]; } var dx = e.touches[0].clientX - startGPos[0]; var dx2 = dx * dx; var dy = e.touches[0].clientY - startGPos[1]; var dy2 = dy * dy; var dist2 = dx2 + dy2; isOverThresholdDrag = dist2 >= r.touchTapThreshold2; } // context swipe cancelling if (capture && r.touchData.cxt) { e.preventDefault(); var f1x2 = e.touches[0].clientX - offsetLeft, f1y2 = e.touches[0].clientY - offsetTop; var f2x2 = e.touches[1].clientX - offsetLeft, f2y2 = e.touches[1].clientY - offsetTop; // var distance2 = distance( f1x2, f1y2, f2x2, f2y2 ); var distance2Sq = distanceSq(f1x2, f1y2, f2x2, f2y2); var factorSq = distance2Sq / distance1Sq; var distThreshold = 150; var distThresholdSq = distThreshold * distThreshold; var factorThreshold = 1.5; var factorThresholdSq = factorThreshold * factorThreshold; // cancel ctx gestures if the distance b/t the fingers increases if (factorSq >= factorThresholdSq || distance2Sq >= distThresholdSq) { r.touchData.cxt = false; r.data.bgActivePosistion = undefined; r.redrawHint('select', true); var cxtEvt = { originalEvent: e, type: 'cxttapend', position: { x: now[0], y: now[1] } }; if (r.touchData.start) { r.touchData.start.unactivate().emit(cxtEvt); r.touchData.start = null; } else { cy.emit(cxtEvt); } } } // context swipe if (capture && r.touchData.cxt) { var cxtEvt = { originalEvent: e, type: 'cxtdrag', position: { x: now[0], y: now[1] } }; r.data.bgActivePosistion = undefined; r.redrawHint('select', true); if (r.touchData.start) { r.touchData.start.emit(cxtEvt); } else { cy.emit(cxtEvt); } if (r.touchData.start) { r.touchData.start._private.grabbed = false; } r.touchData.cxtDragged = true; var near = r.findNearestElement(now[0], now[1], true, true); if (!r.touchData.cxtOver || near !== r.touchData.cxtOver) { if (r.touchData.cxtOver) { r.touchData.cxtOver.emit({ originalEvent: e, type: 'cxtdragout', position: { x: now[0], y: now[1] } }); } r.touchData.cxtOver = near; if (near) { near.emit({ originalEvent: e, type: 'cxtdragover', position: { x: now[0], y: now[1] } }); } } // box selection } else if (capture && e.touches[2] && cy.boxSelectionEnabled()) { e.preventDefault(); r.data.bgActivePosistion = undefined; this.lastThreeTouch = +new Date(); if (!r.touchData.selecting) { cy.emit('boxstart'); } r.touchData.selecting = true; r.redrawHint('select', true); if (!select || select.length === 0 || select[0] === undefined) { select[0] = (now[0] + now[2] + now[4]) / 3; select[1] = (now[1] + now[3] + now[5]) / 3; select[2] = (now[0] + now[2] + now[4]) / 3 + 1; select[3] = (now[1] + now[3] + now[5]) / 3 + 1; } else { select[2] = (now[0] + now[2] + now[4]) / 3; select[3] = (now[1] + now[3] + now[5]) / 3; } select[4] = 1; r.touchData.selecting = true; r.redraw(); // pinch to zoom } else if (capture && e.touches[1] && cy.zoomingEnabled() && cy.panningEnabled() && cy.userZoomingEnabled() && cy.userPanningEnabled()) { // two fingers => pinch to zoom e.preventDefault(); r.data.bgActivePosistion = undefined; r.redrawHint('select', true); var draggedEles = r.dragData.touchDragEles; if (draggedEles) { r.redrawHint('drag', true); for (var i = 0; i < draggedEles.length; i++) { var de_p = draggedEles[i]._private; de_p.grabbed = false; de_p.rscratch.inDragLayer = false; } } // (x2, y2) for fingers 1 and 2 var f1x2 = e.touches[0].clientX - offsetLeft, f1y2 = e.touches[0].clientY - offsetTop; var f2x2 = e.touches[1].clientX - offsetLeft, f2y2 = e.touches[1].clientY - offsetTop; var distance2 = distance(f1x2, f1y2, f2x2, f2y2); // var distance2Sq = distanceSq( f1x2, f1y2, f2x2, f2y2 ); // var factor = Math.sqrt( distance2Sq ) / Math.sqrt( distance1Sq ); var factor = distance2 / distance1; if (twoFingersStartInside) { // delta finger1 var df1x = f1x2 - f1x1; var df1y = f1y2 - f1y1; // delta finger 2 var df2x = f2x2 - f2x1; var df2y = f2y2 - f2y1; // translation is the normalised vector of the two fingers movement // i.e. so pinching cancels out and moving together pans var tx = (df1x + df2x) / 2; var ty = (df1y + df2y) / 2; // adjust factor by the speed multiplier // var speed = 1.5; // if( factor > 1 ){ // factor = (factor - 1) * speed + 1; // } else { // factor = 1 - (1 - factor) * speed; // } // now calculate the zoom var zoom1 = cy.zoom(); var zoom2 = zoom1 * factor; var pan1 = cy.pan(); // the model center point converted to the current rendered pos var ctrx = modelCenter1[0] * zoom1 + pan1.x; var ctry = modelCenter1[1] * zoom1 + pan1.y; var pan2 = { x: -zoom2 / zoom1 * (ctrx - pan1.x - tx) + ctrx, y: -zoom2 / zoom1 * (ctry - pan1.y - ty) + ctry }; // remove dragged eles if (r.touchData.start && r.touchData.start.active()) { var draggedEles = r.dragData.touchDragEles; freeDraggedElements(draggedEles); r.redrawHint('drag', true); r.redrawHint('eles', true); r.touchData.start.unactivate().emit('free'); } cy.viewport({ zoom: zoom2, pan: pan2, cancelOnFailedZoom: true }); distance1 = distance2; f1x1 = f1x2; f1y1 = f1y2; f2x1 = f2x2; f2y1 = f2y2; r.pinching = true; } // Re-project if (e.touches[0]) { var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY);now[0] = pos[0];now[1] = pos[1]; } if (e.touches[1]) { var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY);now[2] = pos[0];now[3] = pos[1]; } if (e.touches[2]) { var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY);now[4] = pos[0];now[5] = pos[1]; } } else if (e.touches[0]) { var start = r.touchData.start; var last = r.touchData.last; var near; if (!r.hoverData.draggingEles && !r.swipePanning) { near = r.findNearestElement(now[0], now[1], true, true); } if (capture && start != null) { e.preventDefault(); } // dragging nodes if (capture && start != null && r.nodeIsDraggable(start)) { if (isOverThresholdDrag) { // then dragging can happen var draggedEles = r.dragData.touchDragEles; var justStartedDrag = !r.dragData.didDrag; if (justStartedDrag) { addNodesToDrag(cy.collection(draggedEles), { inDragLayer: true }); } for (var k = 0; k < draggedEles.length; k++) { var draggedEle = draggedEles[k]; if (r.nodeIsDraggable(draggedEle) && draggedEle.grabbed()) { r.dragData.didDrag = true; var dPos = draggedEle.position(); if (is.number(disp[0]) && is.number(disp[1])) { dPos.x += disp[0]; dPos.y += disp[1]; } if (justStartedDrag) { r.redrawHint('eles', true); var dragDelta = r.touchData.dragDelta; if (dragDelta && is.number(dragDelta[0]) && is.number(dragDelta[1])) { dPos.x += dragDelta[0]; dPos.y += dragDelta[1]; } } } } var tcol = cy.collection(draggedEles); tcol.dirtyCompoundBoundsCache(); tcol.emit('position drag'); r.hoverData.draggingEles = true; r.redrawHint('drag', true); if (r.touchData.startPosition[0] == earlier[0] && r.touchData.startPosition[1] == earlier[1]) { r.redrawHint('eles', true); } r.redraw(); } else { // otherise keep track of drag delta for later var dragDelta = r.touchData.dragDelta = r.touchData.dragDelta || []; if (dragDelta.length === 0) { dragDelta.push(disp[0]); dragDelta.push(disp[1]); } else { dragDelta[0] += disp[0]; dragDelta[1] += disp[1]; } } } // touchmove { triggerEvents(start || near, ['touchmove', 'tapdrag', 'vmousemove'], e, { position: { x: now[0], y: now[1] } }); if ((!start || !start.grabbed()) && near != last) { if (last) { last.emit({ originalEvent: e, type: 'tapdragout', position: { x: now[0], y: now[1] } }); } if (near) { near.emit({ originalEvent: e, type: 'tapdragover', position: { x: now[0], y: now[1] } }); } } r.touchData.last = near; } // check to cancel taphold if (capture) { for (var i = 0; i < now.length; i++) { if (now[i] && r.touchData.startPosition[i] && isOverThresholdDrag) { r.touchData.singleTouchMoved = true; } } } // panning if (capture && (start == null || start.isEdge()) && cy.panningEnabled() && cy.userPanningEnabled()) { var allowPassthrough = allowPanningPassthrough(start, r.touchData.starts); if (allowPassthrough) { e.preventDefault(); if (r.swipePanning) { cy.panBy({ x: disp[0] * zoom, y: disp[1] * zoom }); } else if (isOverThresholdDrag) { r.swipePanning = true; cy.panBy({ x: dx * zoom, y: dy * zoom }); if (start) { start.unactivate(); if (!r.data.bgActivePosistion) { r.data.bgActivePosistion = math.array2point(r.touchData.startPosition); } r.redrawHint('select', true); r.touchData.start = null; } } } // Re-project var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY); now[0] = pos[0];now[1] = pos[1]; } } for (var j = 0; j < now.length; j++) { earlier[j] = now[j]; } //r.redraw(); // the active bg indicator should be removed when making a swipe that is neither for dragging nodes or panning if (capture && e.touches.length > 0 && !r.hoverData.draggingEles && !r.swipePanning && r.data.bgActivePosistion != null) { r.data.bgActivePosistion = undefined; r.redrawHint('select', true); r.redraw(); } }, false); var touchcancelHandler; r.registerBinding(window, 'touchcancel', touchcancelHandler = function touchcancelHandler(e) { // eslint-disable-line no-undef var start = r.touchData.start; r.touchData.capture = false; if (start) { start.unactivate(); } }); var touchendHandler; r.registerBinding(window, 'touchend', touchendHandler = function touchendHandler(e) { // eslint-disable-line no-undef var start = r.touchData.start; var capture = r.touchData.capture; if (capture) { if (e.touches.length === 0) { r.touchData.capture = false; } e.preventDefault(); } else { return; } var select = r.selection; r.swipePanning = false; r.hoverData.draggingEles = false; var cy = r.cy; var zoom = cy.zoom(); var now = r.touchData.now; var earlier = r.touchData.earlier; if (e.touches[0]) { var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY);now[0] = pos[0];now[1] = pos[1]; } if (e.touches[1]) { var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY);now[2] = pos[0];now[3] = pos[1]; } if (e.touches[2]) { var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY);now[4] = pos[0];now[5] = pos[1]; } if (start) { start.unactivate(); } var ctxTapend; if (r.touchData.cxt) { ctxTapend = { originalEvent: e, type: 'cxttapend', position: { x: now[0], y: now[1] } }; if (start) { start.emit(ctxTapend); } else { cy.emit(ctxTapend); } if (!r.touchData.cxtDragged) { var ctxTap = { originalEvent: e, type: 'cxttap', position: { x: now[0], y: now[1] } }; if (start) { start.emit(ctxTap); } else { cy.emit(ctxTap); } } if (r.touchData.start) { r.touchData.start._private.grabbed = false; } r.touchData.cxt = false; r.touchData.start = null; r.redraw(); return; } // no more box selection if we don't have three fingers if (!e.touches[2] && cy.boxSelectionEnabled() && r.touchData.selecting) { r.touchData.selecting = false; var box = cy.collection(r.getAllInBox(select[0], select[1], select[2], select[3])); select[0] = undefined; select[1] = undefined; select[2] = undefined; select[3] = undefined; select[4] = 0; r.redrawHint('select', true); cy.emit('boxend'); var eleWouldBeSelected = function eleWouldBeSelected(ele) { return ele.selectable() && !ele.selected(); }; box.emit('box').stdFilter(eleWouldBeSelected).select().emit('boxselect'); if (box.nonempty()) { r.redrawHint('eles', true); } r.redraw(); } if (start != null) { start.unactivate(); } if (e.touches[2]) { r.data.bgActivePosistion = undefined; r.redrawHint('select', true); } else if (e.touches[1]) { // ignore } else if (e.touches[0]) { // ignore // Last touch released } else if (!e.touches[0]) { r.data.bgActivePosistion = undefined; r.redrawHint('select', true); var draggedEles = r.dragData.touchDragEles; if (start != null) { var startWasGrabbed = start._private.grabbed; freeDraggedElements(draggedEles); r.redrawHint('drag', true); r.redrawHint('eles', true); if (startWasGrabbed) { start.emit('free'); } triggerEvents(start, ['touchend', 'tapend', 'vmouseup', 'tapdragout'], e, { position: { x: now[0], y: now[1] } }); start.unactivate(); r.touchData.start = null; } else { var near = r.findNearestElement(now[0], now[1], true, true); triggerEvents(near, ['touchend', 'tapend', 'vmouseup', 'tapdragout'], e, { position: { x: now[0], y: now[1] } }); } var dx = r.touchData.startPosition[0] - now[0]; var dx2 = dx * dx; var dy = r.touchData.startPosition[1] - now[1]; var dy2 = dy * dy; var dist2 = dx2 + dy2; var rdist2 = dist2 * zoom * zoom; // Prepare to select the currently touched node, only if it hasn't been dragged past a certain distance if (start != null && !r.dragData.didDrag // didn't drag nodes around && start._private.selectable && rdist2 < r.touchTapThreshold2 && !r.pinching // pinch to zoom should not affect selection ) { if (cy.selectionType() === 'single') { cy.$(':selected').unmerge(start).unselect(); start.select(); } else { if (start.selected()) { start.unselect(); } else { start.select(); } } r.redrawHint('eles', true); } // Tap event, roughly same as mouse click event for touch if (!r.touchData.singleTouchMoved) { triggerEvents(start, ['tap', 'vclick'], e, { position: { x: now[0], y: now[1] } }); } r.touchData.singleTouchMoved = true; } for (var j = 0; j < now.length; j++) { earlier[j] = now[j]; } r.dragData.didDrag = false; // reset for next mousedown if (e.touches.length === 0) { r.touchData.dragDelta = []; r.touchData.startPosition = null; r.touchData.startGPosition = null; } if (e.touches.length < 2) { r.pinching = false; r.redrawHint('eles', true); r.redraw(); } //r.redraw(); }, false); // fallback compatibility layer for ms pointer events if (typeof TouchEvent === 'undefined') { var pointers = []; var makeTouch = function makeTouch(e) { return { clientX: e.clientX, clientY: e.clientY, force: 1, identifier: e.pointerId, pageX: e.pageX, pageY: e.pageY, radiusX: e.width / 2, radiusY: e.height / 2, screenX: e.screenX, screenY: e.screenY, target: e.target }; }; var makePointer = function makePointer(e) { return { event: e, touch: makeTouch(e) }; }; var addPointer = function addPointer(e) { pointers.push(makePointer(e)); }; var removePointer = function removePointer(e) { for (var i = 0; i < pointers.length; i++) { var p = pointers[i]; if (p.event.pointerId === e.pointerId) { pointers.splice(i, 1); return; } } }; var updatePointer = function updatePointer(e) { var p = pointers.filter(function (p) { return p.event.pointerId === e.pointerId; })[0]; p.event = e; p.touch = makeTouch(e); }; var addTouchesToEvent = function addTouchesToEvent(e) { e.touches = pointers.map(function (p) { return p.touch; }); }; var pointerIsMouse = function pointerIsMouse(e) { return e.pointerType === 'mouse' || e.pointerType === 4; }; r.registerBinding(r.container, 'pointerdown', function (e) { if (pointerIsMouse(e)) { return; } // mouse already handled e.preventDefault(); addPointer(e); addTouchesToEvent(e); touchstartHandler(e); }); r.registerBinding(r.container, 'pointerup', function (e) { if (pointerIsMouse(e)) { return; } // mouse already handled removePointer(e); addTouchesToEvent(e); touchendHandler(e); }); r.registerBinding(r.container, 'pointercancel', function (e) { if (pointerIsMouse(e)) { return; } // mouse already handled removePointer(e); addTouchesToEvent(e); touchcancelHandler(e); }); r.registerBinding(r.container, 'pointermove', function (e) { if (pointerIsMouse(e)) { return; } // mouse already handled e.preventDefault(); updatePointer(e); addTouchesToEvent(e); touchmoveHandler(e); }); } }; module.exports = BRp; /***/ }), /* 122 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var math = __webpack_require__(2); var BRp = {}; BRp.generatePolygon = function (name, points) { return this.nodeShapes[name] = { renderer: this, name: name, points: points, draw: function draw(context, centerX, centerY, width, height) { this.renderer.nodeShapeImpl('polygon', context, centerX, centerY, width, height, this.points); }, intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding) { return math.polygonIntersectLine(x, y, this.points, nodeX, nodeY, width / 2, height / 2, padding); }, checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY) { return math.pointInsidePolygon(x, y, this.points, centerX, centerY, width, height, [0, -1], padding); } }; }; BRp.generateEllipse = function () { return this.nodeShapes['ellipse'] = { renderer: this, name: 'ellipse', draw: function draw(context, centerX, centerY, width, height) { this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height); }, intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding) { return math.intersectLineEllipse(x, y, nodeX, nodeY, width / 2 + padding, height / 2 + padding); }, checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY) { return math.checkInEllipse(x, y, width, height, centerX, centerY, padding); } }; }; BRp.generateRoundRectangle = function () { return this.nodeShapes['roundrectangle'] = { renderer: this, name: 'roundrectangle', points: math.generateUnitNgonPointsFitToSquare(4, 0), draw: function draw(context, centerX, centerY, width, height) { this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height); }, intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding) { return math.roundRectangleIntersectLine(x, y, nodeX, nodeY, width, height, padding); }, checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY) { var cornerRadius = math.getRoundRectangleRadius(width, height); var diam = cornerRadius * 2; // Check hBox if (math.pointInsidePolygon(x, y, this.points, centerX, centerY, width, height - diam, [0, -1], padding)) { return true; } // Check vBox if (math.pointInsidePolygon(x, y, this.points, centerX, centerY, width - diam, height, [0, -1], padding)) { return true; } // Check top left quarter circle if (math.checkInEllipse(x, y, diam, diam, centerX - width / 2 + cornerRadius, centerY - height / 2 + cornerRadius, padding)) { return true; } // Check top right quarter circle if (math.checkInEllipse(x, y, diam, diam, centerX + width / 2 - cornerRadius, centerY - height / 2 + cornerRadius, padding)) { return true; } // Check bottom right quarter circle if (math.checkInEllipse(x, y, diam, diam, centerX + width / 2 - cornerRadius, centerY + height / 2 - cornerRadius, padding)) { return true; } // Check bottom left quarter circle if (math.checkInEllipse(x, y, diam, diam, centerX - width / 2 + cornerRadius, centerY + height / 2 - cornerRadius, padding)) { return true; } return false; } }; }; BRp.generateCutRectangle = function () { return this.nodeShapes['cutrectangle'] = { renderer: this, name: 'cutrectangle', cornerLength: math.getCutRectangleCornerLength(), points: math.generateUnitNgonPointsFitToSquare(4, 0), draw: function draw(context, centerX, centerY, width, height) { this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height); }, generateCutTrianglePts: function generateCutTrianglePts(width, height, centerX, centerY) { var cl = this.cornerLength; var hh = height / 2; var hw = width / 2; var xBegin = centerX - hw; var xEnd = centerX + hw; var yBegin = centerY - hh; var yEnd = centerY + hh; // points are in clockwise order, inner (imaginary) triangle pt on [4, 5] return { topLeft: [xBegin, yBegin + cl, xBegin + cl, yBegin, xBegin + cl, yBegin + cl], topRight: [xEnd - cl, yBegin, xEnd, yBegin + cl, xEnd - cl, yBegin + cl], bottomRight: [xEnd, yEnd - cl, xEnd - cl, yEnd, xEnd - cl, yEnd - cl], bottomLeft: [xBegin + cl, yEnd, xBegin, yEnd - cl, xBegin + cl, yEnd - cl] }; }, intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding) { var cPts = this.generateCutTrianglePts(width + 2 * padding, height + 2 * padding, nodeX, nodeY); var pts = [].concat.apply([], [cPts.topLeft.splice(0, 4), cPts.topRight.splice(0, 4), cPts.bottomRight.splice(0, 4), cPts.bottomLeft.splice(0, 4)]); return math.polygonIntersectLine(x, y, pts, nodeX, nodeY); }, checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY) { // Check hBox if (math.pointInsidePolygon(x, y, this.points, centerX, centerY, width, height - 2 * this.cornerLength, [0, -1], padding)) { return true; } // Check vBox if (math.pointInsidePolygon(x, y, this.points, centerX, centerY, width - 2 * this.cornerLength, height, [0, -1], padding)) { return true; } var cutTrianglePts = this.generateCutTrianglePts(width, height, centerX, centerY); return math.pointInsidePolygonPoints(x, y, cutTrianglePts.topLeft) || math.pointInsidePolygonPoints(x, y, cutTrianglePts.topRight) || math.pointInsidePolygonPoints(x, y, cutTrianglePts.bottomRight) || math.pointInsidePolygonPoints(x, y, cutTrianglePts.bottomLeft); } }; }; BRp.generateBarrel = function () { return this.nodeShapes['barrel'] = { renderer: this, name: 'barrel', points: math.generateUnitNgonPointsFitToSquare(4, 0), draw: function draw(context, centerX, centerY, width, height) { this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height); }, intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding) { // use two fixed t values for the bezier curve approximation var t0 = 0.15; var t1 = 0.5; var t2 = 0.85; var bPts = this.generateBarrelBezierPts(width + 2 * padding, height + 2 * padding, nodeX, nodeY); var approximateBarrelCurvePts = function approximateBarrelCurvePts(pts) { // approximate curve pts based on the two t values var m0 = math.qbezierPtAt({ x: pts[0], y: pts[1] }, { x: pts[2], y: pts[3] }, { x: pts[4], y: pts[5] }, t0); var m1 = math.qbezierPtAt({ x: pts[0], y: pts[1] }, { x: pts[2], y: pts[3] }, { x: pts[4], y: pts[5] }, t1); var m2 = math.qbezierPtAt({ x: pts[0], y: pts[1] }, { x: pts[2], y: pts[3] }, { x: pts[4], y: pts[5] }, t2); return [pts[0], pts[1], m0.x, m0.y, m1.x, m1.y, m2.x, m2.y, pts[4], pts[5]]; }; var pts = [].concat(approximateBarrelCurvePts(bPts.topLeft), approximateBarrelCurvePts(bPts.topRight), approximateBarrelCurvePts(bPts.bottomRight), approximateBarrelCurvePts(bPts.bottomLeft)); return math.polygonIntersectLine(x, y, pts, nodeX, nodeY); }, generateBarrelBezierPts: function generateBarrelBezierPts(width, height, centerX, centerY) { var hh = height / 2; var hw = width / 2; var xBegin = centerX - hw; var xEnd = centerX + hw; var yBegin = centerY - hh; var yEnd = centerY + hh; var curveConstants = math.getBarrelCurveConstants(width, height); var hOffset = curveConstants.heightOffset; var wOffset = curveConstants.widthOffset; var ctrlPtXOffset = curveConstants.ctrlPtOffsetPct * width; // points are in clockwise order, inner (imaginary) control pt on [4, 5] var pts = { topLeft: [xBegin, yBegin + hOffset, xBegin + ctrlPtXOffset, yBegin, xBegin + wOffset, yBegin], topRight: [xEnd - wOffset, yBegin, xEnd - ctrlPtXOffset, yBegin, xEnd, yBegin + hOffset], bottomRight: [xEnd, yEnd - hOffset, xEnd - ctrlPtXOffset, yEnd, xEnd - wOffset, yEnd], bottomLeft: [xBegin + wOffset, yEnd, xBegin + ctrlPtXOffset, yEnd, xBegin, yEnd - hOffset] }; pts.topLeft.isTop = true; pts.topRight.isTop = true; pts.bottomLeft.isBottom = true; pts.bottomRight.isBottom = true; return pts; }, checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY) { var curveConstants = math.getBarrelCurveConstants(width, height); var hOffset = curveConstants.heightOffset; var wOffset = curveConstants.widthOffset; // Check hBox if (math.pointInsidePolygon(x, y, this.points, centerX, centerY, width, height - 2 * hOffset, [0, -1], padding)) { return true; } // Check vBox if (math.pointInsidePolygon(x, y, this.points, centerX, centerY, width - 2 * wOffset, height, [0, -1], padding)) { return true; } var barrelCurvePts = this.generateBarrelBezierPts(width, height, centerX, centerY); var getCurveT = function getCurveT(x, y, curvePts) { var x0 = curvePts[4]; var x1 = curvePts[2]; var x2 = curvePts[0]; var y0 = curvePts[5]; // var y1 = curvePts[ 3 ]; var y2 = curvePts[1]; var xMin = Math.min(x0, x2); var xMax = Math.max(x0, x2); var yMin = Math.min(y0, y2); var yMax = Math.max(y0, y2); if (xMin <= x && x <= xMax && yMin <= y && y <= yMax) { var coeff = math.bezierPtsToQuadCoeff(x0, x1, x2); var roots = math.solveQuadratic(coeff[0], coeff[1], coeff[2], x); var validRoots = roots.filter(function (r) { return 0 <= r && r <= 1; }); if (validRoots.length > 0) { return validRoots[0]; } } return null; }; var curveRegions = Object.keys(barrelCurvePts); for (var i = 0; i < curveRegions.length; i++) { var corner = curveRegions[i]; var cornerPts = barrelCurvePts[corner]; var t = getCurveT(x, y, cornerPts); if (t == null) { continue; } var y0 = cornerPts[5]; var y1 = cornerPts[3]; var y2 = cornerPts[1]; var bezY = math.qbezierAt(y0, y1, y2, t); if (cornerPts.isTop && bezY <= y) { return true; } if (cornerPts.isBottom && y <= bezY) { return true; } } return false; } }; }; BRp.generateBottomRoundrectangle = function () { return this.nodeShapes['bottomroundrectangle'] = { renderer: this, name: 'bottomroundrectangle', points: math.generateUnitNgonPointsFitToSquare(4, 0), draw: function draw(context, centerX, centerY, width, height) { this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height); }, intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding) { var topStartX = nodeX - (width / 2 + padding); var topStartY = nodeY - (height / 2 + padding); var topEndY = topStartY; var topEndX = nodeX + (width / 2 + padding); var topIntersections = math.finiteLinesIntersect(x, y, nodeX, nodeY, topStartX, topStartY, topEndX, topEndY, false); if (topIntersections.length > 0) { return topIntersections; } return math.roundRectangleIntersectLine(x, y, nodeX, nodeY, width, height, padding); }, checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY) { var cornerRadius = math.getRoundRectangleRadius(width, height); var diam = 2 * cornerRadius; // Check hBox if (math.pointInsidePolygon(x, y, this.points, centerX, centerY, width, height - diam, [0, -1], padding)) { return true; } // Check vBox if (math.pointInsidePolygon(x, y, this.points, centerX, centerY, width - diam, height, [0, -1], padding)) { return true; } // check non-rounded top side var outerWidth = width / 2 + 2 * padding; var outerHeight = height / 2 + 2 * padding; var points = [centerX - outerWidth, centerY - outerHeight, centerX - outerWidth, centerY, centerX + outerWidth, centerY, centerX + outerWidth, centerY - outerHeight]; if (math.pointInsidePolygonPoints(x, y, points)) { return true; } // Check bottom right quarter circle if (math.checkInEllipse(x, y, diam, diam, centerX + width / 2 - cornerRadius, centerY + height / 2 - cornerRadius, padding)) { return true; } // Check bottom left quarter circle if (math.checkInEllipse(x, y, diam, diam, centerX - width / 2 + cornerRadius, centerY + height / 2 - cornerRadius, padding)) { return true; } return false; } }; }; BRp.registerNodeShapes = function () { var nodeShapes = this.nodeShapes = {}; var renderer = this; this.generateEllipse(); this.generatePolygon('triangle', math.generateUnitNgonPointsFitToSquare(3, 0)); this.generatePolygon('rectangle', math.generateUnitNgonPointsFitToSquare(4, 0)); nodeShapes['square'] = nodeShapes['rectangle']; this.generateRoundRectangle(); this.generateCutRectangle(); this.generateBarrel(); this.generateBottomRoundrectangle(); this.generatePolygon('diamond', [0, 1, 1, 0, 0, -1, -1, 0]); this.generatePolygon('pentagon', math.generateUnitNgonPointsFitToSquare(5, 0)); this.generatePolygon('hexagon', math.generateUnitNgonPointsFitToSquare(6, 0)); this.generatePolygon('heptagon', math.generateUnitNgonPointsFitToSquare(7, 0)); this.generatePolygon('octagon', math.generateUnitNgonPointsFitToSquare(8, 0)); var star5Points = new Array(20); { var outerPoints = math.generateUnitNgonPoints(5, 0); var innerPoints = math.generateUnitNgonPoints(5, Math.PI / 5); // Outer radius is 1; inner radius of star is smaller var innerRadius = 0.5 * (3 - Math.sqrt(5)); innerRadius *= 1.57; for (var i = 0; i < innerPoints.length / 2; i++) { innerPoints[i * 2] *= innerRadius; innerPoints[i * 2 + 1] *= innerRadius; } for (var i = 0; i < 20 / 4; i++) { star5Points[i * 4] = outerPoints[i * 2]; star5Points[i * 4 + 1] = outerPoints[i * 2 + 1]; star5Points[i * 4 + 2] = innerPoints[i * 2]; star5Points[i * 4 + 3] = innerPoints[i * 2 + 1]; } } star5Points = math.fitPolygonToSquare(star5Points); this.generatePolygon('star', star5Points); this.generatePolygon('vee', [-1, -1, 0, -0.333, 1, -1, 0, 1]); this.generatePolygon('rhomboid', [-1, -1, 0.333, -1, 1, 1, -0.333, 1]); this.generatePolygon('concavehexagon', [-1, -0.95, -0.75, 0, -1, 0.95, 1, 0.95, 0.75, 0, 1, -0.95]); this.generatePolygon('tag', [-1, -1, 0.25, -1, 1, 0, 0.25, 1, -1, 1]); nodeShapes.makePolygon = function (points) { // use caching on user-specified polygons so they are as fast as native shapes var key = points.join('$'); var name = 'polygon-' + key; var shape; if (shape = this[name]) { // got cached shape return shape; } // create and cache new shape return renderer.generatePolygon(name, points); }; }; module.exports = BRp; /***/ }), /* 123 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var BRp = {}; BRp.timeToRender = function () { return this.redrawTotalTime / this.redrawCount; }; BRp.redraw = function (options) { options = options || util.staticEmptyObject(); var r = this; if (r.averageRedrawTime === undefined) { r.averageRedrawTime = 0; } if (r.lastRedrawTime === undefined) { r.lastRedrawTime = 0; } if (r.lastDrawTime === undefined) { r.lastDrawTime = 0; } r.requestedFrame = true; r.renderOptions = options; }; BRp.beforeRender = function (fn, priority) { // the renderer can't add tick callbacks when destroyed if (this.destroyed) { return; } priority = priority || 0; var cbs = this.beforeRenderCallbacks; cbs.push({ fn: fn, priority: priority }); // higher priority callbacks executed first cbs.sort(function (a, b) { return b.priority - a.priority; }); }; var beforeRenderCallbacks = function beforeRenderCallbacks(r, willDraw, startTime) { var cbs = r.beforeRenderCallbacks; for (var i = 0; i < cbs.length; i++) { cbs[i].fn(willDraw, startTime); } }; BRp.startRenderLoop = function () { var r = this; if (r.renderLoopStarted) { return; } else { r.renderLoopStarted = true; } var renderFn = function renderFn(requestTime) { if (r.destroyed) { return; } if (r.requestedFrame && !r.skipFrame) { beforeRenderCallbacks(r, true, requestTime); var startTime = util.performanceNow(); r.render(r.renderOptions); var endTime = r.lastDrawTime = util.performanceNow(); if (r.averageRedrawTime === undefined) { r.averageRedrawTime = endTime - startTime; } if (r.redrawCount === undefined) { r.redrawCount = 0; } r.redrawCount++; if (r.redrawTotalTime === undefined) { r.redrawTotalTime = 0; } var duration = endTime - startTime; r.redrawTotalTime += duration; r.lastRedrawTime = duration; // use a weighted average with a bias from the previous average so we don't spike so easily r.averageRedrawTime = r.averageRedrawTime / 2 + duration / 2; r.requestedFrame = false; } else { beforeRenderCallbacks(r, false, requestTime); } r.skipFrame = false; util.requestAnimationFrame(renderFn); }; util.requestAnimationFrame(renderFn); }; module.exports = BRp; /***/ }), /* 124 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /* The canvas renderer was written by Yue Dong. Modifications tracked on Github. */ var util = __webpack_require__(1); var is = __webpack_require__(0); var ElementTextureCache = __webpack_require__(125); var LayeredTextureCache = __webpack_require__(126); var CR = CanvasRenderer; var CRp = CanvasRenderer.prototype; CRp.CANVAS_LAYERS = 3; // CRp.SELECT_BOX = 0; CRp.DRAG = 1; CRp.NODE = 2; CRp.BUFFER_COUNT = 3; // CRp.TEXTURE_BUFFER = 0; CRp.MOTIONBLUR_BUFFER_NODE = 1; CRp.MOTIONBLUR_BUFFER_DRAG = 2; function CanvasRenderer(options) { var r = this; r.data = { canvases: new Array(CRp.CANVAS_LAYERS), contexts: new Array(CRp.CANVAS_LAYERS), canvasNeedsRedraw: new Array(CRp.CANVAS_LAYERS), bufferCanvases: new Array(CRp.BUFFER_COUNT), bufferContexts: new Array(CRp.CANVAS_LAYERS) }; var tapHlOff = '-webkit-tap-highlight-color: rgba(0,0,0,0);'; r.data.canvasContainer = document.createElement('div'); // eslint-disable-line no-undef var containerStyle = r.data.canvasContainer.style; r.data.canvasContainer.setAttribute('style', tapHlOff); containerStyle.position = 'relative'; containerStyle.zIndex = '0'; containerStyle.overflow = 'hidden'; var container = options.cy.container(); container.appendChild(r.data.canvasContainer); if ((container.getAttribute('style') || '').indexOf(tapHlOff) < 0) { container.setAttribute('style', (container.getAttribute('style') || '') + tapHlOff); } for (var i = 0; i < CRp.CANVAS_LAYERS; i++) { var canvas = r.data.canvases[i] = document.createElement('canvas'); // eslint-disable-line no-undef r.data.contexts[i] = canvas.getContext('2d'); canvas.setAttribute('style', '-webkit-user-select: none; -moz-user-select: -moz-none; user-select: none; -webkit-tap-highlight-color: rgba(0,0,0,0); outline-style: none;' + (is.ms() ? ' -ms-touch-action: none; touch-action: none; ' : '')); canvas.style.position = 'absolute'; canvas.setAttribute('data-id', 'layer' + i); canvas.style.zIndex = String(CRp.CANVAS_LAYERS - i); r.data.canvasContainer.appendChild(canvas); r.data.canvasNeedsRedraw[i] = false; } r.data.topCanvas = r.data.canvases[0]; r.data.canvases[CRp.NODE].setAttribute('data-id', 'layer' + CRp.NODE + '-node'); r.data.canvases[CRp.SELECT_BOX].setAttribute('data-id', 'layer' + CRp.SELECT_BOX + '-selectbox'); r.data.canvases[CRp.DRAG].setAttribute('data-id', 'layer' + CRp.DRAG + '-drag'); for (var i = 0; i < CRp.BUFFER_COUNT; i++) { r.data.bufferCanvases[i] = document.createElement('canvas'); // eslint-disable-line no-undef r.data.bufferContexts[i] = r.data.bufferCanvases[i].getContext('2d'); r.data.bufferCanvases[i].style.position = 'absolute'; r.data.bufferCanvases[i].setAttribute('data-id', 'buffer' + i); r.data.bufferCanvases[i].style.zIndex = String(-i - 1); r.data.bufferCanvases[i].style.visibility = 'hidden'; //r.data.canvasContainer.appendChild(r.data.bufferCanvases[i]); } r.pathsEnabled = true; r.data.eleTxrCache = new ElementTextureCache(r); r.data.lyrTxrCache = new LayeredTextureCache(r, r.data.eleTxrCache); r.onUpdateEleCalcs(function invalidateTextureCaches(willDraw, eles) { for (var i = 0; i < eles.length; i++) { var ele = eles[i]; var rs = ele._private.rstyle; var de = rs.dirtyEvents; if (ele.isNode() && de && de.length === 1 && de['position']) { // then keep cached ele texture } else { r.data.eleTxrCache.invalidateElement(ele); // NB this block of code should not be ported to 3.3 (unstable branch). // - This check is unneccesary in 3.3 as caches will be stored without respect to opacity. // - This fix may result in lowered performance for compound graphs. // - Ref : Opacity of child node is not updated for certain zoom levels after parent opacity is overriden #2078 if (ele.isParent() && de['style']) { var op1 = rs.prevParentOpacity; var op2 = ele.pstyle('opacity').pfValue; rs.prevParentOpacity = op2; if (op1 !== op2) { var descs = ele.descendants(); for (var j = 0; j < descs.length; j++) { r.data.eleTxrCache.invalidateElement(descs[j]); } } } } } if (eles.length > 0) { r.data.lyrTxrCache.invalidateElements(eles); } }); } CRp.redrawHint = function (group, bool) { var r = this; switch (group) { case 'eles': r.data.canvasNeedsRedraw[CRp.NODE] = bool; break; case 'drag': r.data.canvasNeedsRedraw[CRp.DRAG] = bool; break; case 'select': r.data.canvasNeedsRedraw[CRp.SELECT_BOX] = bool; break; } }; // whether to use Path2D caching for drawing var pathsImpld = typeof Path2D !== 'undefined'; CRp.path2dEnabled = function (on) { if (on === undefined) { return this.pathsEnabled; } this.pathsEnabled = on ? true : false; }; CRp.usePaths = function () { return pathsImpld && this.pathsEnabled; }; [__webpack_require__(127), __webpack_require__(128), __webpack_require__(129), __webpack_require__(130), __webpack_require__(131), __webpack_require__(132), __webpack_require__(133), __webpack_require__(134), __webpack_require__(135), __webpack_require__(136)].forEach(function (props) { util.extend(CRp, props); }); module.exports = CR; /***/ }), /* 125 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var math = __webpack_require__(2); var util = __webpack_require__(1); var Heap = __webpack_require__(9); var defs = __webpack_require__(19); var minTxrH = 25; // the size of the texture cache for small height eles (special case) var txrStepH = 50; // the min size of the regular cache, and the size it increases with each step up var minLvl = -4; // when scaling smaller than that we don't need to re-render var maxLvl = 2; // when larger than this scale just render directly (caching is not helpful) var maxZoom = 3.99; // beyond this zoom level, layered textures are not used var eleTxrSpacing = 8; // spacing between elements on textures to avoid blitting overlaps var defTxrWidth = 1024; // default/minimum texture width var maxTxrW = 1024; // the maximum width of a texture var maxTxrH = 1024; // the maximum height of a texture var minUtility = 0.5; // if usage of texture is less than this, it is retired var maxFullness = 0.8; // fullness of texture after which queue removal is checked var maxFullnessChecks = 10; // dequeued after this many checks var allowEdgeTxrCaching = false; // whether edges can be cached as textures (TODO maybe better on if webgl supported?) var allowParentTxrCaching = false; // whether parent nodes can be cached as textures (TODO maybe better on if webgl supported?) var deqCost = 0.15; // % of add'l rendering cost allowed for dequeuing ele caches each frame var deqAvgCost = 0.1; // % of add'l rendering cost compared to average overall redraw time var deqNoDrawCost = 0.9; // % of avg frame time that can be used for dequeueing when not drawing var deqFastCost = 0.9; // % of frame time to be used when >60fps var deqRedrawThreshold = 100; // time to batch redraws together from dequeueing to allow more dequeueing calcs to happen in the meanwhile var maxDeqSize = 1; // number of eles to dequeue and render at higher texture in each batch var getTxrReasons = { dequeue: 'dequeue', downscale: 'downscale', highQuality: 'highQuality' }; var ElementTextureCache = function ElementTextureCache(renderer) { var self = this; self.renderer = renderer; self.onDequeues = []; self.setupDequeueing(); }; var ETCp = ElementTextureCache.prototype; ETCp.reasons = getTxrReasons; // the list of textures in which new subtextures for elements can be placed ETCp.getTextureQueue = function (txrH) { var self = this; self.eleImgCaches = self.eleImgCaches || {}; return self.eleImgCaches[txrH] = self.eleImgCaches[txrH] || []; }; // the list of usused textures which can be recycled (in use in texture queue) ETCp.getRetiredTextureQueue = function (txrH) { var self = this; var rtxtrQs = self.eleImgCaches.retired = self.eleImgCaches.retired || {}; var rtxtrQ = rtxtrQs[txrH] = rtxtrQs[txrH] || []; return rtxtrQ; }; // queue of element draw requests at different scale levels ETCp.getElementQueue = function () { var self = this; var q = self.eleCacheQueue = self.eleCacheQueue || new Heap(function (a, b) { return b.reqs - a.reqs; }); return q; }; // queue of element draw requests at different scale levels (element id lookup) ETCp.getElementIdToQueue = function () { var self = this; var id2q = self.eleIdToCacheQueue = self.eleIdToCacheQueue || {}; return id2q; }; ETCp.getElement = function (ele, bb, pxRatio, lvl, reason) { var self = this; var r = this.renderer; var rs = ele._private.rscratch; var zoom = r.cy.zoom(); if (bb.w === 0 || bb.h === 0 || !ele.visible()) { return null; } if (lvl == null) { lvl = Math.ceil(math.log2(zoom * pxRatio)); } if (lvl < minLvl) { lvl = minLvl; } else if (zoom >= maxZoom || lvl > maxLvl) { return null; } var scale = Math.pow(2, lvl); var eleScaledH = bb.h * scale; var eleScaledW = bb.w * scale; var caches = rs.imgCaches = rs.imgCaches || {}; var eleCache = caches[lvl]; if (eleCache) { return eleCache; } var txrH; // which texture height this ele belongs to if (eleScaledH <= minTxrH) { txrH = minTxrH; } else if (eleScaledH <= txrStepH) { txrH = txrStepH; } else { txrH = Math.ceil(eleScaledH / txrStepH) * txrStepH; } if (eleScaledH > maxTxrH || eleScaledW > maxTxrW || !allowEdgeTxrCaching && ele.isEdge() || !allowParentTxrCaching && ele.isParent()) { return null; // caching large elements is not efficient } var txrQ = self.getTextureQueue(txrH); // first try the second last one in case it has space at the end var txr = txrQ[txrQ.length - 2]; var addNewTxr = function addNewTxr() { return self.recycleTexture(txrH, eleScaledW) || self.addTexture(txrH, eleScaledW); }; // try the last one if there is no second last one if (!txr) { txr = txrQ[txrQ.length - 1]; } // if the last one doesn't exist, we need a first one if (!txr) { txr = addNewTxr(); } // if there's no room in the current texture, we need a new one if (txr.width - txr.usedWidth < eleScaledW) { txr = addNewTxr(); } var scaledLabelShown = r.eleTextBiggerThanMin(ele, scale); var scalableFrom = function scalableFrom(otherCache) { return otherCache && otherCache.scaledLabelShown === scaledLabelShown; }; var deqing = reason && reason === getTxrReasons.dequeue; var highQualityReq = reason && reason === getTxrReasons.highQuality; var downscaleReq = reason && reason === getTxrReasons.downscale; var higherCache; // the nearest cache with a higher level for (var l = lvl + 1; l <= maxLvl; l++) { var c = caches[l]; if (c) { higherCache = c;break; } } var oneUpCache = higherCache && higherCache.level === lvl + 1 ? higherCache : null; var downscale = function downscale() { txr.context.drawImage(oneUpCache.texture.canvas, oneUpCache.x, 0, oneUpCache.width, oneUpCache.height, txr.usedWidth, 0, eleScaledW, eleScaledH); }; // reset ele area in texture txr.context.setTransform(1, 0, 0, 1, 0, 0); txr.context.clearRect(txr.usedWidth, 0, eleScaledW, txrH); if (scalableFrom(oneUpCache)) { // then we can relatively cheaply rescale the existing image w/o rerendering downscale(); } else if (scalableFrom(higherCache)) { // then use the higher cache for now and queue the next level down // to cheaply scale towards the smaller level if (highQualityReq) { for (var l = higherCache.level; l > lvl; l--) { oneUpCache = self.getElement(ele, bb, pxRatio, l, getTxrReasons.downscale); } downscale(); } else { self.queueElement(ele, higherCache.level - 1); return higherCache; } } else { var lowerCache; // the nearest cache with a lower level if (!deqing && !highQualityReq && !downscaleReq) { for (var l = lvl - 1; l >= minLvl; l--) { var c = caches[l]; if (c) { lowerCache = c;break; } } } if (scalableFrom(lowerCache)) { // then use the lower quality cache for now and queue the better one for later self.queueElement(ele, lvl); return lowerCache; } txr.context.translate(txr.usedWidth, 0); txr.context.scale(scale, scale); r.drawElement(txr.context, ele, bb, scaledLabelShown); txr.context.scale(1 / scale, 1 / scale); txr.context.translate(-txr.usedWidth, 0); } eleCache = caches[lvl] = { ele: ele, x: txr.usedWidth, texture: txr, level: lvl, scale: scale, width: eleScaledW, height: eleScaledH, scaledLabelShown: scaledLabelShown }; txr.usedWidth += Math.ceil(eleScaledW + eleTxrSpacing); txr.eleCaches.push(eleCache); self.checkTextureFullness(txr); return eleCache; }; ETCp.invalidateElement = function (ele) { var self = this; var caches = ele._private.rscratch.imgCaches; if (caches) { for (var lvl = minLvl; lvl <= maxLvl; lvl++) { var cache = caches[lvl]; if (cache) { var txr = cache.texture; // remove space from the texture it belongs to txr.invalidatedWidth += cache.width; // remove refs with the element caches[lvl] = null; util.removeFromArray(txr.eleCaches, cache); // remove from queue since the old req was for the old state self.removeFromQueue(ele); // might have to remove the entire texture if it's not efficiently using its space self.checkTextureUtility(txr); } } } }; ETCp.checkTextureUtility = function (txr) { // invalidate all entries in the cache if the cache size is small if (txr.invalidatedWidth >= minUtility * txr.width) { this.retireTexture(txr); } }; ETCp.checkTextureFullness = function (txr) { // if texture has been mostly filled and passed over several times, remove // it from the queue so we don't need to waste time looking at it to put new things var self = this; var txrQ = self.getTextureQueue(txr.height); if (txr.usedWidth / txr.width > maxFullness && txr.fullnessChecks >= maxFullnessChecks) { util.removeFromArray(txrQ, txr); } else { txr.fullnessChecks++; } }; ETCp.retireTexture = function (txr) { var self = this; var txrH = txr.height; var txrQ = self.getTextureQueue(txrH); // retire the texture from the active / searchable queue: util.removeFromArray(txrQ, txr); txr.retired = true; // remove the refs from the eles to the caches: var eleCaches = txr.eleCaches; for (var i = 0; i < eleCaches.length; i++) { var eleCache = eleCaches[i]; var ele = eleCache.ele; var lvl = eleCache.level; var imgCaches = ele._private.rscratch.imgCaches; if (imgCaches) { imgCaches[lvl] = null; } } util.clearArray(eleCaches); // add the texture to a retired queue so it can be recycled in future: var rtxtrQ = self.getRetiredTextureQueue(txrH); rtxtrQ.push(txr); }; ETCp.addTexture = function (txrH, minW) { var self = this; var txrQ = self.getTextureQueue(txrH); var txr = {}; txrQ.push(txr); txr.eleCaches = []; txr.height = txrH; txr.width = Math.max(defTxrWidth, minW); txr.usedWidth = 0; txr.invalidatedWidth = 0; txr.fullnessChecks = 0; txr.canvas = document.createElement('canvas'); // eslint-disable-line no-undef txr.canvas.width = txr.width; txr.canvas.height = txr.height; txr.context = txr.canvas.getContext('2d'); return txr; }; ETCp.recycleTexture = function (txrH, minW) { var self = this; var txrQ = self.getTextureQueue(txrH); var rtxtrQ = self.getRetiredTextureQueue(txrH); for (var i = 0; i < rtxtrQ.length; i++) { var txr = rtxtrQ[i]; if (txr.width >= minW) { txr.retired = false; txr.usedWidth = 0; txr.invalidatedWidth = 0; txr.fullnessChecks = 0; util.clearArray(txr.eleCaches); txr.context.setTransform(1, 0, 0, 1, 0, 0); txr.context.clearRect(0, 0, txr.width, txr.height); util.removeFromArray(rtxtrQ, txr); txrQ.push(txr); return txr; } } }; ETCp.queueElement = function (ele, lvl) { var self = this; var q = self.getElementQueue(); var id2q = self.getElementIdToQueue(); var id = ele.id(); var existingReq = id2q[id]; if (existingReq) { // use the max lvl b/c in between lvls are cheap to make existingReq.level = Math.max(existingReq.level, lvl); existingReq.reqs++; q.updateItem(existingReq); } else { var req = { ele: ele, level: lvl, reqs: 1 }; q.push(req); id2q[id] = req; } }; ETCp.dequeue = function (pxRatio /*, extent*/) { var self = this; var q = self.getElementQueue(); var id2q = self.getElementIdToQueue(); var dequeued = []; for (var i = 0; i < maxDeqSize; i++) { if (q.size() > 0) { var req = q.pop(); var ele = req.ele; var caches = ele._private.rscratch.imgCaches; // dequeueing isn't necessary when an existing cache exists if (caches[req.level] != null) { continue; } id2q[ele.id()] = null; dequeued.push(req); var bb = ele.boundingBox(); self.getElement(ele, bb, pxRatio, req.level, getTxrReasons.dequeue); } else { break; } } return dequeued; }; ETCp.removeFromQueue = function (ele) { var self = this; var q = self.getElementQueue(); var id2q = self.getElementIdToQueue(); var req = id2q[ele.id()]; if (req != null) { // bring to front of queue req.reqs = util.MAX_INT; q.updateItem(req); q.pop(); // remove from queue id2q[ele.id()] = null; // remove from lookup map } }; ETCp.onDequeue = function (fn) { this.onDequeues.push(fn); }; ETCp.offDequeue = function (fn) { util.removeFromArray(this.onDequeues, fn); }; ETCp.setupDequeueing = defs.setupDequeueing({ deqRedrawThreshold: deqRedrawThreshold, deqCost: deqCost, deqAvgCost: deqAvgCost, deqNoDrawCost: deqNoDrawCost, deqFastCost: deqFastCost, deq: function deq(self, pxRatio, extent) { return self.dequeue(pxRatio, extent); }, onDeqd: function onDeqd(self, deqd) { for (var i = 0; i < self.onDequeues.length; i++) { var fn = self.onDequeues[i]; fn(deqd); } }, shouldRedraw: function shouldRedraw(self, deqd, pxRatio, extent) { for (var i = 0; i < deqd.length; i++) { var bb = deqd[i].ele.boundingBox(); if (math.boundingBoxesIntersect(bb, extent)) { return true; } } return false; }, priority: function priority(self) { return self.renderer.beforeRenderPriorities.eleTxrDeq; } }); module.exports = ElementTextureCache; /***/ }), /* 126 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var math = __webpack_require__(2); var Heap = __webpack_require__(9); var is = __webpack_require__(0); var defs = __webpack_require__(19); var defNumLayers = 1; // default number of layers to use var minLvl = -4; // when scaling smaller than that we don't need to re-render var maxLvl = 2; // when larger than this scale just render directly (caching is not helpful) var maxZoom = 3.99; // beyond this zoom level, layered textures are not used var deqRedrawThreshold = 50; // time to batch redraws together from dequeueing to allow more dequeueing calcs to happen in the meanwhile var refineEleDebounceTime = 50; // time to debounce sharper ele texture updates var disableEleImgSmoothing = true; // when drawing eles on layers from an ele cache ; crisper and more performant when true var deqCost = 0.15; // % of add'l rendering cost allowed for dequeuing ele caches each frame var deqAvgCost = 0.1; // % of add'l rendering cost compared to average overall redraw time var deqNoDrawCost = 0.9; // % of avg frame time that can be used for dequeueing when not drawing var deqFastCost = 0.9; // % of frame time to be used when >60fps var maxDeqSize = 1; // number of eles to dequeue and render at higher texture in each batch var invalidThreshold = 250; // time threshold for disabling b/c of invalidations var maxLayerArea = 4000 * 4000; // layers can't be bigger than this var alwaysQueue = true; // never draw all the layers in a level on a frame; draw directly until all dequeued var useHighQualityEleTxrReqs = true; // whether to use high quality ele txr requests (generally faster and cheaper in the longterm) var useEleTxrCaching = true; // whether to use individual ele texture caching underneath this cache // var log = function(){ console.log.apply( console, arguments ); }; var LayeredTextureCache = function LayeredTextureCache(renderer, eleTxrCache) { var self = this; var r = self.renderer = renderer; self.layersByLevel = {}; // e.g. 2 => [ layer1, layer2, ..., layerN ] self.firstGet = true; self.lastInvalidationTime = util.performanceNow() - 2 * invalidThreshold; self.skipping = false; r.beforeRender(function (willDraw, now) { if (now - self.lastInvalidationTime <= invalidThreshold) { self.skipping = true; } else { self.skipping = false; } }); var qSort = function qSort(a, b) { return b.reqs - a.reqs; }; self.layersQueue = new Heap(qSort); self.eleTxrCache = eleTxrCache; self.setupEleCacheInvalidation(); self.setupDequeueing(); }; var LTCp = LayeredTextureCache.prototype; var layerIdPool = 0; var MAX_INT = Math.pow(2, 53) - 1; LTCp.makeLayer = function (bb, lvl) { var scale = Math.pow(2, lvl); var w = Math.ceil(bb.w * scale); var h = Math.ceil(bb.h * scale); var canvas = document.createElement('canvas'); // eslint-disable-line no-undef canvas.width = w; canvas.height = h; var layer = { id: layerIdPool = ++layerIdPool % MAX_INT, bb: bb, level: lvl, width: w, height: h, canvas: canvas, context: canvas.getContext('2d'), eles: [], elesQueue: [], reqs: 0 }; // log('make layer %s with w %s and h %s and lvl %s', layer.id, layer.width, layer.height, layer.level); var cxt = layer.context; var dx = -layer.bb.x1; var dy = -layer.bb.y1; // do the transform on creation to save cycles (it's the same for all eles) cxt.scale(scale, scale); cxt.translate(dx, dy); return layer; }; LTCp.getLayers = function (eles, pxRatio, lvl) { var self = this; var r = self.renderer; var cy = r.cy; var zoom = cy.zoom(); var firstGet = self.firstGet; self.firstGet = false; // log('--\nget layers with %s eles', eles.length); //log eles.map(function(ele){ return ele.id() }) ); if (lvl == null) { lvl = Math.ceil(math.log2(zoom * pxRatio)); if (lvl < minLvl) { lvl = minLvl; } else if (zoom >= maxZoom || lvl > maxLvl) { return null; } } self.validateLayersElesOrdering(lvl, eles); var layersByLvl = self.layersByLevel; var scale = Math.pow(2, lvl); var layers = layersByLvl[lvl] = layersByLvl[lvl] || []; var bb; var lvlComplete = self.levelIsComplete(lvl, eles); var tmpLayers; var checkTempLevels = function checkTempLevels() { var canUseAsTmpLvl = function canUseAsTmpLvl(l) { self.validateLayersElesOrdering(l, eles); if (self.levelIsComplete(l, eles)) { tmpLayers = layersByLvl[l]; return true; } }; var checkLvls = function checkLvls(dir) { if (tmpLayers) { return; } for (var l = lvl + dir; minLvl <= l && l <= maxLvl; l += dir) { if (canUseAsTmpLvl(l)) { break; } } }; checkLvls(+1); checkLvls(-1); // remove the invalid layers; they will be replaced as needed later in this function for (var i = layers.length - 1; i >= 0; i--) { var layer = layers[i]; if (layer.invalid) { util.removeFromArray(layers, layer); } } }; if (!lvlComplete) { // if the current level is incomplete, then use the closest, best quality layerset temporarily // and later queue the current layerset so we can get the proper quality level soon checkTempLevels(); } else { // log('level complete, using existing layers\n--'); return layers; } var getBb = function getBb() { if (!bb) { bb = math.makeBoundingBox(); for (var i = 0; i < eles.length; i++) { math.updateBoundingBox(bb, eles[i].boundingBox()); } } return bb; }; var makeLayer = function makeLayer(opts) { opts = opts || {}; var after = opts.after; getBb(); var area = bb.w * scale * (bb.h * scale); if (area > maxLayerArea) { return null; } var layer = self.makeLayer(bb, lvl); if (after != null) { var index = layers.indexOf(after) + 1; layers.splice(index, 0, layer); } else if (opts.insert === undefined || opts.insert) { // no after specified => first layer made so put at start layers.unshift(layer); } // if( tmpLayers ){ //self.queueLayer( layer ); // } return layer; }; if (self.skipping && !firstGet) { // log('skip layers'); return null; } // log('do layers'); var layer = null; var maxElesPerLayer = eles.length / defNumLayers; var allowLazyQueueing = alwaysQueue && !firstGet; for (var i = 0; i < eles.length; i++) { var ele = eles[i]; var rs = ele._private.rscratch; var caches = rs.imgLayerCaches = rs.imgLayerCaches || {}; // log('look at ele', ele.id()); var existingLayer = caches[lvl]; if (existingLayer) { // reuse layer for later eles // log('reuse layer for', ele.id()); layer = existingLayer; continue; } if (!layer || layer.eles.length >= maxElesPerLayer || !math.boundingBoxInBoundingBox(layer.bb, ele.boundingBox())) { // log('make new layer for ele %s', ele.id()); layer = makeLayer({ insert: true, after: layer }); // if now layer can be built then we can't use layers at this level if (!layer) { return null; } // log('new layer with id %s', layer.id); } if (tmpLayers || allowLazyQueueing) { // log('queue ele %s in layer %s', ele.id(), layer.id); self.queueLayer(layer, ele); } else { // log('draw ele %s in layer %s', ele.id(), layer.id); self.drawEleInLayer(layer, ele, lvl, pxRatio); } layer.eles.push(ele); caches[lvl] = layer; } // log('--'); if (tmpLayers) { // then we only queued the current layerset and can't draw it yet return tmpLayers; } if (allowLazyQueueing) { // log('lazy queue level', lvl); return null; } return layers; }; // a layer may want to use an ele cache of a higher level to avoid blurriness // so the layer level might not equal the ele level LTCp.getEleLevelForLayerLevel = function (lvl, pxRatio) { return lvl; }; function imgSmoothing(context, bool) { if (context.imageSmoothingEnabled != null) { context.imageSmoothingEnabled = bool; } else { context.webkitImageSmoothingEnabled = bool; context.mozImageSmoothingEnabled = bool; context.msImageSmoothingEnabled = bool; } } LTCp.drawEleInLayer = function (layer, ele, lvl, pxRatio) { var self = this; var r = this.renderer; var context = layer.context; var bb = ele.boundingBox(); if (bb.w === 0 || bb.h === 0 || !ele.visible()) { return; } var eleCache = self.eleTxrCache; var reason = useHighQualityEleTxrReqs ? eleCache.reasons.highQuality : undefined; lvl = self.getEleLevelForLayerLevel(lvl, pxRatio); var cache = useEleTxrCaching ? eleCache.getElement(ele, bb, null, lvl, reason) : null; if (cache) { if (disableEleImgSmoothing) { imgSmoothing(context, false); } context.drawImage(cache.texture.canvas, cache.x, 0, cache.width, cache.height, bb.x1, bb.y1, bb.w, bb.h); if (disableEleImgSmoothing) { imgSmoothing(context, true); } } else { // if the element is not cacheable, then draw directly r.drawElement(context, ele); } }; LTCp.levelIsComplete = function (lvl, eles) { var self = this; var layers = self.layersByLevel[lvl]; if (!layers || layers.length === 0) { return false; } var numElesInLayers = 0; for (var i = 0; i < layers.length; i++) { var layer = layers[i]; // if there are any eles needed to be drawn yet, the level is not complete if (layer.reqs > 0) { return false; } // if the layer is invalid, the level is not complete if (layer.invalid) { return false; } numElesInLayers += layer.eles.length; } // we should have exactly the number of eles passed in to be complete if (numElesInLayers !== eles.length) { return false; } return true; }; LTCp.validateLayersElesOrdering = function (lvl, eles) { var layers = this.layersByLevel[lvl]; if (!layers) { return; } // if in a layer the eles are not in the same order, then the layer is invalid // (i.e. there is an ele in between the eles in the layer) for (var i = 0; i < layers.length; i++) { var layer = layers[i]; var offset = -1; // find the offset for (var j = 0; j < eles.length; j++) { if (layer.eles[0] === eles[j]) { offset = j; break; } } if (offset < 0) { // then the layer has nonexistant elements and is invalid this.invalidateLayer(layer); continue; } // the eles in the layer must be in the same continuous order, else the layer is invalid var o = offset; for (var j = 0; j < layer.eles.length; j++) { if (layer.eles[j] !== eles[o + j]) { // log('invalidate based on ordering', layer.id); this.invalidateLayer(layer); break; } } } }; LTCp.updateElementsInLayers = function (eles, update) { var self = this; var isEles = is.element(eles[0]); // collect udpated elements (cascaded from the layers) and update each // layer itself along the way for (var i = 0; i < eles.length; i++) { var req = isEles ? null : eles[i]; var ele = isEles ? eles[i] : eles[i].ele; var rs = ele._private.rscratch; var caches = rs.imgLayerCaches = rs.imgLayerCaches || {}; for (var l = minLvl; l <= maxLvl; l++) { var layer = caches[l]; if (!layer) { continue; } // if update is a request from the ele cache, then it affects only // the matching level if (req && self.getEleLevelForLayerLevel(layer.level) !== req.level) { continue; } update(layer, ele, req); } } }; LTCp.haveLayers = function () { var self = this; var haveLayers = false; for (var l = minLvl; l <= maxLvl; l++) { var layers = self.layersByLevel[l]; if (layers && layers.length > 0) { haveLayers = true; break; } } return haveLayers; }; LTCp.invalidateElements = function (eles) { var self = this; self.lastInvalidationTime = util.performanceNow(); // log('update invalidate layer time from eles'); if (eles.length === 0 || !self.haveLayers()) { return; } self.updateElementsInLayers(eles, function invalAssocLayers(layer, ele, req) { self.invalidateLayer(layer); }); }; LTCp.invalidateLayer = function (layer) { // log('update invalidate layer time'); this.lastInvalidationTime = util.performanceNow(); if (layer.invalid) { return; } // save cycles var lvl = layer.level; var eles = layer.eles; var layers = this.layersByLevel[lvl]; // log('invalidate layer', layer.id ); util.removeFromArray(layers, layer); // layer.eles = []; layer.elesQueue = []; layer.invalid = true; if (layer.replacement) { layer.replacement.invalid = true; } for (var i = 0; i < eles.length; i++) { var caches = eles[i]._private.rscratch.imgLayerCaches; if (caches) { caches[lvl] = null; } } }; LTCp.refineElementTextures = function (eles) { var self = this; // log('refine', eles.length); self.updateElementsInLayers(eles, function refineEachEle(layer, ele, req) { var rLyr = layer.replacement; if (!rLyr) { rLyr = layer.replacement = self.makeLayer(layer.bb, layer.level); rLyr.replaces = layer; rLyr.eles = layer.eles; // log('make replacement layer %s for %s with level %s', rLyr.id, layer.id, rLyr.level); } if (!rLyr.reqs) { for (var i = 0; i < rLyr.eles.length; i++) { self.queueLayer(rLyr, rLyr.eles[i]); } // log('queue replacement layer refinement', rLyr.id); } }); }; LTCp.setupEleCacheInvalidation = function () { var self = this; var eleDeqs = []; if (!useEleTxrCaching) { return; } var updatedElesInLayers = util.debounce(function () { self.refineElementTextures(eleDeqs); eleDeqs = []; }, refineEleDebounceTime); self.eleTxrCache.onDequeue(function (reqs) { for (var i = 0; i < reqs.length; i++) { eleDeqs.push(reqs[i]); } updatedElesInLayers(); }); }; LTCp.queueLayer = function (layer, ele) { var self = this; var q = self.layersQueue; var elesQ = layer.elesQueue; var hasId = elesQ.hasId = elesQ.hasId || {}; // if a layer is going to be replaced, queuing is a waste of time if (layer.replacement) { return; } if (ele) { if (hasId[ele.id()]) { return; } elesQ.push(ele); hasId[ele.id()] = true; } if (layer.reqs) { layer.reqs++; q.updateItem(layer); } else { layer.reqs = 1; q.push(layer); } }; LTCp.dequeue = function (pxRatio) { var self = this; var q = self.layersQueue; var deqd = []; var eleDeqs = 0; while (eleDeqs < maxDeqSize) { if (q.size() === 0) { break; } var layer = q.peek(); // if a layer has been or will be replaced, then don't waste time with it if (layer.replacement) { // log('layer %s in queue skipped b/c it already has a replacement', layer.id); q.pop(); continue; } // if this is a replacement layer that has been superceded, then forget it if (layer.replaces && layer !== layer.replaces.replacement) { // log('layer is no longer the most uptodate replacement; dequeued', layer.id) q.pop(); continue; } if (layer.invalid) { // log('replacement layer %s is invalid; dequeued', layer.id); q.pop(); continue; } var ele = layer.elesQueue.shift(); if (ele) { // log('dequeue layer %s', layer.id); self.drawEleInLayer(layer, ele, layer.level, pxRatio); eleDeqs++; } if (deqd.length === 0) { // we need only one entry in deqd to queue redrawing etc deqd.push(true); } // if the layer has all its eles done, then remove from the queue if (layer.elesQueue.length === 0) { q.pop(); layer.reqs = 0; // log('dequeue of layer %s complete', layer.id); // when a replacement layer is dequeued, it replaces the old layer in the level if (layer.replaces) { self.applyLayerReplacement(layer); } self.requestRedraw(); } } return deqd; }; LTCp.applyLayerReplacement = function (layer) { var self = this; var layersInLevel = self.layersByLevel[layer.level]; var replaced = layer.replaces; var index = layersInLevel.indexOf(replaced); // if the replaced layer is not in the active list for the level, then replacing // refs would be a mistake (i.e. overwriting the true active layer) if (index < 0 || replaced.invalid) { // log('replacement layer would have no effect', layer.id); return; } layersInLevel[index] = layer; // replace level ref // replace refs in eles for (var i = 0; i < layer.eles.length; i++) { var _p = layer.eles[i]._private; var cache = _p.imgLayerCaches = _p.imgLayerCaches || {}; if (cache) { cache[layer.level] = layer; } } // log('apply replacement layer %s over %s', layer.id, replaced.id); self.requestRedraw(); }; LTCp.requestRedraw = util.debounce(function () { var r = this.renderer; r.redrawHint('eles', true); r.redrawHint('drag', true); r.redraw(); }, 100); LTCp.setupDequeueing = defs.setupDequeueing({ deqRedrawThreshold: deqRedrawThreshold, deqCost: deqCost, deqAvgCost: deqAvgCost, deqNoDrawCost: deqNoDrawCost, deqFastCost: deqFastCost, deq: function deq(self, pxRatio) { return self.dequeue(pxRatio); }, onDeqd: util.noop, shouldRedraw: util.trueify, priority: function priority(self) { return self.renderer.beforeRenderPriorities.lyrTxrDeq; } }); module.exports = LayeredTextureCache; /***/ }), /* 127 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var CRp = {}; var impl; CRp.arrowShapeImpl = function (name) { return (impl || (impl = { 'polygon': function polygon(context, points) { for (var i = 0; i < points.length; i++) { var pt = points[i]; context.lineTo(pt.x, pt.y); } }, 'triangle-backcurve': function triangleBackcurve(context, points, controlPoint) { var firstPt; for (var i = 0; i < points.length; i++) { var pt = points[i]; if (i === 0) { firstPt = pt; } context.lineTo(pt.x, pt.y); } context.quadraticCurveTo(controlPoint.x, controlPoint.y, firstPt.x, firstPt.y); }, 'triangle-tee': function triangleTee(context, trianglePoints, teePoints) { if (context.beginPath) { context.beginPath(); } var triPts = trianglePoints; for (var i = 0; i < triPts.length; i++) { var pt = triPts[i]; context.lineTo(pt.x, pt.y); } if (context.closePath) { context.closePath(); } if (context.beginPath) { context.beginPath(); } var teePts = teePoints; var firstTeePt = teePoints[0]; context.moveTo(firstTeePt.x, firstTeePt.y); for (var i = 0; i < teePts.length; i++) { var pt = teePts[i]; context.lineTo(pt.x, pt.y); } if (context.closePath) { context.closePath(); } }, 'triangle-cross': function triangleCross(context, trianglePoints, crossLinePoints) { if (context.beginPath) { context.beginPath(); } var triPts = trianglePoints; for (var i = 0; i < triPts.length; i++) { var pt = triPts[i]; context.lineTo(pt.x, pt.y); } if (context.closePath) { context.closePath(); } if (context.beginPath) { context.beginPath(); } var teePts = crossLinePoints; var firstTeePt = crossLinePoints[0]; context.moveTo(firstTeePt.x, firstTeePt.y); for (var i = 0; i < teePts.length; i++) { var pt = teePts[i]; context.lineTo(pt.x, pt.y); } if (context.closePath) { context.closePath(); } }, 'circle': function circle(context, rx, ry, r) { context.arc(rx, ry, r, 0, Math.PI * 2, false); } }))[name]; }; module.exports = CRp; /***/ }), /* 128 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var math = __webpack_require__(2); var CRp = {}; CRp.drawElement = function (context, ele, shiftToOriginWithBb, showLabel) { var r = this; if (ele.isNode()) { r.drawNode(context, ele, shiftToOriginWithBb, showLabel); } else { r.drawEdge(context, ele, shiftToOriginWithBb, showLabel); } }; CRp.drawCachedElement = function (context, ele, pxRatio, extent) { var r = this; var bb = ele.boundingBox(); if (bb.w === 0 || bb.h === 0) { return; } if (!extent || math.boundingBoxesIntersect(bb, extent)) { var cache = r.data.eleTxrCache.getElement(ele, bb, pxRatio); if (cache != null) { context.drawImage(cache.texture.canvas, cache.x, 0, cache.width, cache.height, bb.x1, bb.y1, bb.w, bb.h); } else { // if the element is not cacheable, then draw directly r.drawElement(context, ele); } } }; CRp.drawElements = function (context, eles) { var r = this; for (var i = 0; i < eles.length; i++) { var ele = eles[i]; r.drawElement(context, ele); } }; CRp.drawCachedElements = function (context, eles, pxRatio, extent) { var r = this; for (var i = 0; i < eles.length; i++) { var ele = eles[i]; r.drawCachedElement(context, ele, pxRatio, extent); } }; CRp.drawCachedNodes = function (context, eles, pxRatio, extent) { var r = this; for (var i = 0; i < eles.length; i++) { var ele = eles[i]; if (!ele.isNode()) { continue; } r.drawCachedElement(context, ele, pxRatio, extent); } }; CRp.drawLayeredElements = function (context, eles, pxRatio, extent) { var r = this; var layers = r.data.lyrTxrCache.getLayers(eles, pxRatio); if (layers) { for (var i = 0; i < layers.length; i++) { var layer = layers[i]; var bb = layer.bb; if (bb.w === 0 || bb.h === 0) { continue; } context.drawImage(layer.canvas, bb.x1, bb.y1, bb.w, bb.h); } } else { // fall back on plain caching if no layers r.drawCachedElements(context, eles, pxRatio, extent); } }; CRp.drawDebugPoints = function (context, eles) { var draw = function draw(x, y, color) { context.fillStyle = color; context.fillRect(x - 1, y - 1, 3, 3); }; for (var i = 0; i < eles.length; i++) { var ele = eles[i]; var rs = ele._private.rscratch; if (ele.isNode()) { var p = ele.position(); draw(p.x, p.y, 'magenta'); } else { var pts = rs.allpts; for (var j = 0; j + 1 < pts.length; j += 2) { var x = pts[j]; var y = pts[j + 1]; draw(x, y, 'cyan'); } draw(rs.midX, rs.midY, 'yellow'); } } }; module.exports = CRp; /***/ }), /* 129 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var CRp = {}; CRp.drawEdge = function (context, edge, shiftToOriginWithBb, drawLabel) { var r = this; var rs = edge._private.rscratch; var usePaths = r.usePaths(); if (!edge.visible()) { return; } // if bezier ctrl pts can not be calculated, then die if (rs.badLine || rs.allpts == null || isNaN(rs.allpts[0])) { // isNaN in case edge is impossible and browser bugs (e.g. safari) return; } var bb = void 0; if (shiftToOriginWithBb) { bb = shiftToOriginWithBb; context.translate(-bb.x1, -bb.y1); } var overlayPadding = edge.pstyle('overlay-padding').pfValue; var overlayWidth = 2 * overlayPadding; var overlayOpacity = edge.pstyle('overlay-opacity').value; var overlayColor = edge.pstyle('overlay-color').value; var lineColor = edge.pstyle('line-color').value; var opacity = edge.pstyle('opacity').value; var lineStyle = edge.pstyle('line-style').value; var edgeWidth = edge.pstyle('width').pfValue; var drawLine = function drawLine() { var strokeOpacity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : opacity; context.lineWidth = edgeWidth; context.lineCap = 'butt'; r.strokeStyle(context, lineColor[0], lineColor[1], lineColor[2], strokeOpacity); r.drawEdgePath(edge, context, rs.allpts, lineStyle); }; var drawOverlay = function drawOverlay() { var strokeOpacity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : overlayOpacity; context.lineWidth = overlayWidth; if (rs.edgeType === 'self' && !usePaths) { context.lineCap = 'butt'; } else { context.lineCap = 'round'; } r.strokeStyle(context, overlayColor[0], overlayColor[1], overlayColor[2], strokeOpacity); r.drawEdgePath(edge, context, rs.allpts, 'solid'); }; var drawArrows = function drawArrows() { var arrowOpacity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : opacity; r.drawArrowheads(context, edge, arrowOpacity); }; var drawText = function drawText() { r.drawElementText(context, edge, drawLabel); }; context.lineJoin = 'round'; var ghost = edge.pstyle('ghost').value === 'yes'; if (ghost) { var gx = edge.pstyle('ghost-offset-x').pfValue; var gy = edge.pstyle('ghost-offset-y').pfValue; var ghostOpacity = edge.pstyle('ghost-opacity').value; var effectiveGhostOpacity = opacity * ghostOpacity; context.translate(gx, gy); drawLine(effectiveGhostOpacity); drawArrows(effectiveGhostOpacity); context.translate(-gx, -gy); } drawLine(); drawArrows(); drawOverlay(); drawText(); if (shiftToOriginWithBb) { context.translate(bb.x1, bb.y1); } }; CRp.drawEdgePath = function (edge, context, pts, type) { var rs = edge._private.rscratch; var canvasCxt = context; var path = void 0; var pathCacheHit = false; var usePaths = this.usePaths(); if (usePaths) { var pathCacheKey = pts.join('$'); var keyMatches = rs.pathCacheKey && rs.pathCacheKey === pathCacheKey; if (keyMatches) { path = context = rs.pathCache; pathCacheHit = true; } else { path = context = new Path2D(); // eslint-disable-line no-undef rs.pathCacheKey = pathCacheKey; rs.pathCache = path; } } if (canvasCxt.setLineDash) { // for very outofdate browsers switch (type) { case 'dotted': canvasCxt.setLineDash([1, 1]); break; case 'dashed': canvasCxt.setLineDash([6, 3]); break; case 'solid': canvasCxt.setLineDash([]); break; } } if (!pathCacheHit && !rs.badLine) { if (context.beginPath) { context.beginPath(); } context.moveTo(pts[0], pts[1]); switch (rs.edgeType) { case 'bezier': case 'self': case 'compound': case 'multibezier': for (var i = 2; i + 3 < pts.length; i += 4) { context.quadraticCurveTo(pts[i], pts[i + 1], pts[i + 2], pts[i + 3]); } break; case 'straight': case 'segments': case 'haystack': for (var _i = 2; _i + 1 < pts.length; _i += 2) { context.lineTo(pts[_i], pts[_i + 1]); } break; } } context = canvasCxt; if (usePaths) { context.stroke(path); } else { context.stroke(); } // reset any line dashes if (context.setLineDash) { // for very outofdate browsers context.setLineDash([]); } }; CRp.drawArrowheads = function (context, edge, opacity) { var rs = edge._private.rscratch; var isHaystack = rs.edgeType === 'haystack'; if (!isHaystack) { this.drawArrowhead(context, edge, 'source', rs.arrowStartX, rs.arrowStartY, rs.srcArrowAngle, opacity); } this.drawArrowhead(context, edge, 'mid-target', rs.midX, rs.midY, rs.midtgtArrowAngle, opacity); this.drawArrowhead(context, edge, 'mid-source', rs.midX, rs.midY, rs.midsrcArrowAngle, opacity); if (!isHaystack) { this.drawArrowhead(context, edge, 'target', rs.arrowEndX, rs.arrowEndY, rs.tgtArrowAngle, opacity); } }; CRp.drawArrowhead = function (context, edge, prefix, x, y, angle, opacity) { if (isNaN(x) || x == null || isNaN(y) || y == null || isNaN(angle) || angle == null) { return; } var self = this; var arrowShape = edge.pstyle(prefix + '-arrow-shape').value; if (arrowShape === 'none') { return; } var arrowClearFill = edge.pstyle(prefix + '-arrow-fill').value === 'hollow' ? 'both' : 'filled'; var arrowFill = edge.pstyle(prefix + '-arrow-fill').value; var edgeWidth = edge.pstyle('width').pfValue; var edgeOpacity = edge.pstyle('opacity').value; if (opacity === undefined) { opacity = edgeOpacity; } var gco = context.globalCompositeOperation; if (opacity !== 1 || arrowFill === 'hollow') { // then extra clear is needed context.globalCompositeOperation = 'destination-out'; self.fillStyle(context, 255, 255, 255, 1); self.strokeStyle(context, 255, 255, 255, 1); self.drawArrowShape(edge, prefix, context, arrowClearFill, edgeWidth, arrowShape, x, y, angle); context.globalCompositeOperation = gco; } // otherwise, the opaque arrow clears it for free :) var color = edge.pstyle(prefix + '-arrow-color').value; self.fillStyle(context, color[0], color[1], color[2], opacity); self.strokeStyle(context, color[0], color[1], color[2], opacity); self.drawArrowShape(edge, prefix, context, arrowFill, edgeWidth, arrowShape, x, y, angle); }; CRp.drawArrowShape = function (edge, arrowType, context, fill, edgeWidth, shape, x, y, angle) { var r = this; var usePaths = this.usePaths(); var rs = edge._private.rscratch; var pathCacheHit = false; var path = void 0; var canvasContext = context; var translation = { x: x, y: y }; var scale = edge.pstyle('arrow-scale').value; var size = this.getArrowWidth(edgeWidth, scale); var shapeImpl = r.arrowShapes[shape]; if (usePaths) { var pathCacheKey = size + '$' + shape + '$' + angle + '$' + x + '$' + y; rs.arrowPathCacheKey = rs.arrowPathCacheKey || {}; rs.arrowPathCache = rs.arrowPathCache || {}; var alreadyCached = rs.arrowPathCacheKey[arrowType] === pathCacheKey; if (alreadyCached) { path = context = rs.arrowPathCache[arrowType]; pathCacheHit = true; } else { path = context = new Path2D(); // eslint-disable-line no-undef rs.arrowPathCacheKey[arrowType] = pathCacheKey; rs.arrowPathCache[arrowType] = path; } } if (context.beginPath) { context.beginPath(); } if (!pathCacheHit) { shapeImpl.draw(context, size, angle, translation, edgeWidth); } if (!shapeImpl.leavePathOpen && context.closePath) { context.closePath(); } context = canvasContext; if (fill === 'filled' || fill === 'both') { if (usePaths) { context.fill(path); } else { context.fill(); } } if (fill === 'hollow' || fill === 'both') { context.lineWidth = shapeImpl.matchEdgeWidth ? edgeWidth : 1; context.lineJoin = 'miter'; if (usePaths) { context.stroke(path); } else { context.stroke(); } } }; module.exports = CRp; /***/ }), /* 130 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var CRp = {}; CRp.safeDrawImage = function (context, img, ix, iy, iw, ih, x, y, w, h) { var r = this; // detect problematic cases for old browsers with bad images (cheaper than try-catch) if (iw <= 0 || ih <= 0 || w <= 0 || h <= 0) { return; } context.drawImage(img, ix, iy, iw, ih, x, y, w, h); }; CRp.drawInscribedImage = function (context, img, node, index, nodeOpacity) { var r = this; var pos = node.position(); var nodeX = pos.x; var nodeY = pos.y; var styleObj = node.cy().style(); var getIndexedStyle = styleObj.getIndexedStyle.bind(styleObj); var fit = getIndexedStyle(node, 'background-fit', 'value', index); var repeat = getIndexedStyle(node, 'background-repeat', 'value', index); var nodeW = node.width(); var nodeH = node.height(); var paddingX2 = node.padding() * 2; var nodeTW = nodeW + (getIndexedStyle(node, 'background-width-relative-to', 'value', index) === 'inner' ? 0 : paddingX2); var nodeTH = nodeH + (getIndexedStyle(node, 'background-height-relative-to', 'value', index) === 'inner' ? 0 : paddingX2); var rs = node._private.rscratch; var clip = node.pstyle('background-clip').value; var shouldClip = clip === 'node'; var imgOpacity = getIndexedStyle(node, 'background-image-opacity', 'value', index) * nodeOpacity; var imgW = img.width || img.cachedW; var imgH = img.height || img.cachedH; // workaround for broken browsers like ie if (null == imgW || null == imgH) { document.body.appendChild(img); // eslint-disable-line no-undef imgW = img.cachedW = img.width || img.offsetWidth; imgH = img.cachedH = img.height || img.offsetHeight; document.body.removeChild(img); // eslint-disable-line no-undef } var w = imgW; var h = imgH; if (getIndexedStyle(node, 'background-width', 'value', index) !== 'auto') { if (getIndexedStyle(node, 'background-width', 'units', index) === '%') { w = getIndexedStyle(node, 'background-width', 'pfValue', index) * nodeTW; } else { w = getIndexedStyle(node, 'background-width', 'pfValue', index); } } if (getIndexedStyle(node, 'background-height', 'value', index) !== 'auto') { if (getIndexedStyle(node, 'background-height', 'units', index) === '%') { h = getIndexedStyle(node, 'background-height', 'pfValue', index) * nodeTH; } else { h = getIndexedStyle(node, 'background-height', 'pfValue', index); } } if (w === 0 || h === 0) { return; // no point in drawing empty image (and chrome is broken in this case) } if (fit === 'contain') { var scale = Math.min(nodeTW / w, nodeTH / h); w *= scale; h *= scale; } else if (fit === 'cover') { var scale = Math.max(nodeTW / w, nodeTH / h); w *= scale; h *= scale; } var x = nodeX - nodeTW / 2; // left if (getIndexedStyle(node, 'background-position-x', 'units', index) === '%') { x += (nodeTW - w) * getIndexedStyle(node, 'background-position-x', 'pfValue', index); } else { x += getIndexedStyle(node, 'background-position-x', 'pfValue', index); } var y = nodeY - nodeTH / 2; // top if (getIndexedStyle(node, 'background-position-y', 'units', index) === '%') { y += (nodeTH - h) * getIndexedStyle(node, 'background-position-y', 'pfValue', index); } else { y += getIndexedStyle(node, 'background-position-y', 'pfValue', index); } if (rs.pathCache) { x -= nodeX; y -= nodeY; nodeX = 0; nodeY = 0; } var gAlpha = context.globalAlpha; context.globalAlpha = imgOpacity; if (repeat === 'no-repeat') { if (shouldClip) { context.save(); if (rs.pathCache) { context.clip(rs.pathCache); } else { r.nodeShapes[r.getNodeShape(node)].draw(context, nodeX, nodeY, nodeTW, nodeTH); context.clip(); } } r.safeDrawImage(context, img, 0, 0, imgW, imgH, x, y, w, h); if (shouldClip) { context.restore(); } } else { var pattern = context.createPattern(img, repeat); context.fillStyle = pattern; r.nodeShapes[r.getNodeShape(node)].draw(context, nodeX, nodeY, nodeTW, nodeTH); context.translate(x, y); context.fill(); context.translate(-x, -y); } context.globalAlpha = gAlpha; }; module.exports = CRp; /***/ }), /* 131 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(1); var math = __webpack_require__(2); var CRp = {}; CRp.eleTextBiggerThanMin = function (ele, scale) { if (!scale) { var zoom = ele.cy().zoom(); var pxRatio = this.getPixelRatio(); var lvl = Math.ceil(math.log2(zoom * pxRatio)); // the effective texture level scale = Math.pow(2, lvl); } var computedSize = ele.pstyle('font-size').pfValue * scale; var minSize = ele.pstyle('min-zoomed-font-size').pfValue; if (computedSize < minSize) { return false; } return true; }; CRp.drawElementText = function (context, ele, force) { var r = this; if (force === undefined) { if (!r.eleTextBiggerThanMin(ele)) { return; } } else { if (!force) { return; } } if (ele.isNode()) { var label = ele.pstyle('label'); if (!label || !label.value) { return; } var textHalign = ele.pstyle('text-halign').strValue; var textValign = ele.pstyle('text-valign').strValue; switch (textHalign) { case 'left': context.textAlign = 'right'; break; case 'right': context.textAlign = 'left'; break; default: // e.g. center context.textAlign = 'center'; } context.textBaseline = 'bottom'; } else { var label = ele.pstyle('label'); var srcLabel = ele.pstyle('source-label'); var tgtLabel = ele.pstyle('target-label'); if ((!label || !label.value) && (!srcLabel || !srcLabel.value) && (!tgtLabel || !tgtLabel.value)) { return; } context.textAlign = 'center'; context.textBaseline = 'bottom'; } r.drawText(context, ele); if (ele.isEdge()) { r.drawText(context, ele, 'source'); r.drawText(context, ele, 'target'); } }; CRp.drawNodeText = CRp.drawEdgeText = CRp.drawElementText; CRp.getFontCache = function (context) { var cache; this.fontCaches = this.fontCaches || []; for (var i = 0; i < this.fontCaches.length; i++) { cache = this.fontCaches[i]; if (cache.context === context) { return cache; } } cache = { context: context }; this.fontCaches.push(cache); return cache; }; // set up canvas context with font // returns transformed text string CRp.setupTextStyle = function (context, ele) { // Font style var parentOpacity = ele.effectiveOpacity(); var labelStyle = ele.pstyle('font-style').strValue; var labelSize = ele.pstyle('font-size').pfValue + 'px'; var labelFamily = ele.pstyle('font-family').strValue; var labelWeight = ele.pstyle('font-weight').strValue; var opacity = ele.pstyle('text-opacity').value * ele.pstyle('opacity').value * parentOpacity; var outlineOpacity = ele.pstyle('text-outline-opacity').value * opacity; var color = ele.pstyle('color').value; var outlineColor = ele.pstyle('text-outline-color').value; var fontCacheKey = ele._private.fontKey; var cache = this.getFontCache(context); if (cache.key !== fontCacheKey) { context.font = labelStyle + ' ' + labelWeight + ' ' + labelSize + ' ' + labelFamily; cache.key = fontCacheKey; } // Calculate text draw position based on text alignment // so text outlines aren't jagged context.lineJoin = 'round'; this.fillStyle(context, color[0], color[1], color[2], opacity); this.strokeStyle(context, outlineColor[0], outlineColor[1], outlineColor[2], outlineOpacity); }; function roundRect(ctx, x, y, width, height, radius) { var radius = radius || 5; ctx.beginPath(); ctx.moveTo(x + radius, y); ctx.lineTo(x + width - radius, y); ctx.quadraticCurveTo(x + width, y, x + width, y + radius); ctx.lineTo(x + width, y + height - radius); ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); ctx.lineTo(x + radius, y + height); ctx.quadraticCurveTo(x, y + height, x, y + height - radius); ctx.lineTo(x, y + radius); ctx.quadraticCurveTo(x, y, x + radius, y); ctx.closePath(); ctx.fill(); } // Draw text CRp.drawText = function (context, ele, prefix) { var _p = ele._private; var rscratch = _p.rscratch; var parentOpacity = ele.effectiveOpacity(); if (parentOpacity === 0 || ele.pstyle('text-opacity').value === 0) { return; } var textX = util.getPrefixedProperty(rscratch, 'labelX', prefix); var textY = util.getPrefixedProperty(rscratch, 'labelY', prefix); var text = this.getLabelText(ele, prefix); if (text != null && text !== '' && !isNaN(textX) && !isNaN(textY)) { this.setupTextStyle(context, ele); var pdash = prefix ? prefix + '-' : ''; var textW = util.getPrefixedProperty(rscratch, 'labelWidth', prefix); var textH = util.getPrefixedProperty(rscratch, 'labelHeight', prefix); var textAngle = util.getPrefixedProperty(rscratch, 'labelAngle', prefix); var marginX = ele.pstyle(pdash + 'text-margin-x').pfValue; var marginY = ele.pstyle(pdash + 'text-margin-y').pfValue; var isEdge = ele.isEdge(); var isNode = ele.isNode(); var halign = ele.pstyle('text-halign').value; var valign = ele.pstyle('text-valign').value; if (isEdge) { halign = 'center'; valign = 'center'; } textX += marginX; textY += marginY; var rotation = ele.pstyle(pdash + 'text-rotation'); var theta; if (rotation.strValue === 'autorotate') { theta = isEdge ? textAngle : 0; } else if (rotation.strValue === 'none') { theta = 0; } else { theta = rotation.pfValue; } if (theta !== 0) { var orgTextX = textX; var orgTextY = textY; context.translate(orgTextX, orgTextY); context.rotate(theta); textX = 0; textY = 0; } switch (valign) { case 'top': break; case 'center': textY += textH / 2; break; case 'bottom': textY += textH; break; } var backgroundOpacity = ele.pstyle('text-background-opacity').value; var borderOpacity = ele.pstyle('text-border-opacity').value; var textBorderWidth = ele.pstyle('text-border-width').pfValue; var backgroundPadding = ele.pstyle('text-background-padding').pfValue; if (backgroundOpacity > 0 || textBorderWidth > 0 && borderOpacity > 0) { var bgX = textX - backgroundPadding; switch (halign) { case 'left': bgX -= textW; break; case 'center': bgX -= textW / 2; break; case 'right': break; } var bgY = textY - textH - backgroundPadding; var bgW = textW + 2 * backgroundPadding; var bgH = textH + 2 * backgroundPadding; if (backgroundOpacity > 0) { var textFill = context.fillStyle; var textBackgroundColor = ele.pstyle('text-background-color').value; context.fillStyle = 'rgba(' + textBackgroundColor[0] + ',' + textBackgroundColor[1] + ',' + textBackgroundColor[2] + ',' + backgroundOpacity * parentOpacity + ')'; var styleShape = ele.pstyle('text-background-shape').strValue; if (styleShape == 'roundrectangle') { roundRect(context, bgX, bgY, bgW, bgH, 2); } else { context.fillRect(bgX, bgY, bgW, bgH); } context.fillStyle = textFill; } if (textBorderWidth > 0 && borderOpacity > 0) { var textStroke = context.strokeStyle; var textLineWidth = context.lineWidth; var textBorderColor = ele.pstyle('text-border-color').value; var textBorderStyle = ele.pstyle('text-border-style').value; context.strokeStyle = 'rgba(' + textBorderColor[0] + ',' + textBorderColor[1] + ',' + textBorderColor[2] + ',' + borderOpacity * parentOpacity + ')'; context.lineWidth = textBorderWidth; if (context.setLineDash) { // for very outofdate browsers switch (textBorderStyle) { case 'dotted': context.setLineDash([1, 1]); break; case 'dashed': context.setLineDash([4, 2]); break; case 'double': context.lineWidth = textBorderWidth / 4; // 50% reserved for white between the two borders context.setLineDash([]); break; case 'solid': context.setLineDash([]); break; } } context.strokeRect(bgX, bgY, bgW, bgH); if (textBorderStyle === 'double') { var whiteWidth = textBorderWidth / 2; context.strokeRect(bgX + whiteWidth, bgY + whiteWidth, bgW - whiteWidth * 2, bgH - whiteWidth * 2); } if (context.setLineDash) { // for very outofdate browsers context.setLineDash([]); } context.lineWidth = textLineWidth; context.strokeStyle = textStroke; } } var lineWidth = 2 * ele.pstyle('text-outline-width').pfValue; // *2 b/c the stroke is drawn centred on the middle if (lineWidth > 0) { context.lineWidth = lineWidth; } if (ele.pstyle('text-wrap').value === 'wrap') { var lines = util.getPrefixedProperty(rscratch, 'labelWrapCachedLines', prefix); var lineHeight = textH / lines.length; switch (valign) { case 'top': textY -= (lines.length - 1) * lineHeight; break; case 'center': case 'bottom': textY -= (lines.length - 1) * lineHeight; break; } for (var l = 0; l < lines.length; l++) { if (lineWidth > 0) { context.strokeText(lines[l], textX, textY); } context.fillText(lines[l], textX, textY); textY += lineHeight; } } else { if (lineWidth > 0) { context.strokeText(text, textX, textY); } context.fillText(text, textX, textY); } if (theta !== 0) { context.rotate(-theta); context.translate(-orgTextX, -orgTextY); } } }; module.exports = CRp; /***/ }), /* 132 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /* global Path2D */ var is = __webpack_require__(0); var CRp = {}; CRp.drawNode = function (context, node, shiftToOriginWithBb, drawLabel) { var r = this; var nodeWidth = void 0, nodeHeight = void 0; var _p = node._private; var rs = _p.rscratch; var pos = node.position(); if (!is.number(pos.x) || !is.number(pos.y)) { return; // can't draw node with undefined position } if (!node.visible()) { return; } var parentOpacity = node.effectiveOpacity(); var usePaths = r.usePaths(); var path = void 0; var pathCacheHit = false; var padding = node.padding(); nodeWidth = node.width() + 2 * padding; nodeHeight = node.height() + 2 * padding; // // setup shift var bb = void 0; if (shiftToOriginWithBb) { bb = shiftToOriginWithBb; context.translate(-bb.x1, -bb.y1); } // // load bg image var bgImgProp = node.pstyle('background-image'); var urls = bgImgProp.value; var urlDefined = new Array(urls.length); var image = new Array(urls.length); var numImages = 0; for (var i = 0; i < urls.length; i++) { var url = urls[i]; var defd = urlDefined[i] = url != null && url !== 'none'; if (defd) { var bgImgCrossOrigin = node.cy().style().getIndexedStyle(node, 'background-image-crossorigin', 'value', i); numImages++; // get image, and if not loaded then ask to redraw when later loaded image[i] = r.getCachedImage(url, bgImgCrossOrigin, function () { node.emitAndNotify('background'); }); } } // // setup styles var darkness = node.pstyle('background-blacken').value; var borderWidth = node.pstyle('border-width').pfValue; var bgColor = node.pstyle('background-color').value; var bgOpacity = node.pstyle('background-opacity').value * parentOpacity; var borderColor = node.pstyle('border-color').value; var borderStyle = node.pstyle('border-style').value; var borderOpacity = node.pstyle('border-opacity').value * parentOpacity; context.lineJoin = 'miter'; // so borders are square with the node shape var setupShapeColor = function setupShapeColor() { var bgOpy = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : bgOpacity; r.fillStyle(context, bgColor[0], bgColor[1], bgColor[2], bgOpy); }; var setupBorderColor = function setupBorderColor() { var bdrOpy = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : borderOpacity; r.strokeStyle(context, borderColor[0], borderColor[1], borderColor[2], bdrOpy); }; // // setup shape var styleShape = node.pstyle('shape').strValue; var shapePts = node.pstyle('shape-polygon-points').pfValue; if (usePaths) { var pathCacheKey = styleShape + '$' + nodeWidth + '$' + nodeHeight + (styleShape === 'polygon' ? '$' + shapePts.join('$') : ''); context.translate(pos.x, pos.y); if (rs.pathCacheKey === pathCacheKey) { path = rs.pathCache; pathCacheHit = true; } else { path = new Path2D(); rs.pathCacheKey = pathCacheKey; rs.pathCache = path; } } var drawShape = function drawShape() { if (!pathCacheHit) { var npos = pos; if (usePaths) { npos = { x: 0, y: 0 }; } r.nodeShapes[r.getNodeShape(node)].draw(path || context, npos.x, npos.y, nodeWidth, nodeHeight); } if (usePaths) { context.fill(path); } else { context.fill(); } }; var drawImages = function drawImages() { var nodeOpacity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : parentOpacity; var prevBging = _p.backgrounding; var totalCompleted = 0; for (var _i = 0; _i < image.length; _i++) { if (urlDefined[_i] && image[_i].complete && !image[_i].error) { totalCompleted++; r.drawInscribedImage(context, image[_i], node, _i, nodeOpacity); } } _p.backgrounding = !(totalCompleted === numImages); if (prevBging !== _p.backgrounding) { // update style b/c :backgrounding state changed node.updateStyle(false); } }; var drawPie = function drawPie() { var redrawShape = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var pieOpacity = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : parentOpacity; if (r.hasPie(node)) { r.drawPie(context, node, pieOpacity); // redraw/restore path if steps after pie need it if (redrawShape) { if (!usePaths) { r.nodeShapes[r.getNodeShape(node)].draw(context, pos.x, pos.y, nodeWidth, nodeHeight); } } } }; var darken = function darken() { var darkenOpacity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : parentOpacity; var opacity = (darkness > 0 ? darkness : -darkness) * darkenOpacity; var c = darkness > 0 ? 0 : 255; if (darkness !== 0) { r.fillStyle(context, c, c, c, opacity); if (usePaths) { context.fill(path); } else { context.fill(); } } }; var drawBorder = function drawBorder() { if (borderWidth > 0) { context.lineWidth = borderWidth; context.lineCap = 'butt'; if (context.setLineDash) { // for very outofdate browsers switch (borderStyle) { case 'dotted': context.setLineDash([1, 1]); break; case 'dashed': context.setLineDash([4, 2]); break; case 'solid': case 'double': context.setLineDash([]); break; } } if (usePaths) { context.stroke(path); } else { context.stroke(); } if (borderStyle === 'double') { context.lineWidth = borderWidth / 3; var gco = context.globalCompositeOperation; context.globalCompositeOperation = 'destination-out'; if (usePaths) { context.stroke(path); } else { context.stroke(); } context.globalCompositeOperation = gco; } // reset in case we changed the border style if (context.setLineDash) { // for very outofdate browsers context.setLineDash([]); } } }; var drawOverlay = function drawOverlay() { var overlayPadding = node.pstyle('overlay-padding').pfValue; var overlayOpacity = node.pstyle('overlay-opacity').value; var overlayColor = node.pstyle('overlay-color').value; if (overlayOpacity > 0) { r.fillStyle(context, overlayColor[0], overlayColor[1], overlayColor[2], overlayOpacity); r.nodeShapes['roundrectangle'].draw(context, pos.x, pos.y, nodeWidth + overlayPadding * 2, nodeHeight + overlayPadding * 2); context.fill(); } }; var drawText = function drawText() { r.drawElementText(context, node, drawLabel); }; var ghost = node.pstyle('ghost').value === 'yes'; if (ghost) { var gx = node.pstyle('ghost-offset-x').pfValue; var gy = node.pstyle('ghost-offset-y').pfValue; var ghostOpacity = node.pstyle('ghost-opacity').value; var effGhostOpacity = ghostOpacity * parentOpacity; context.translate(gx, gy); setupShapeColor(ghostOpacity * bgOpacity); drawShape(); drawImages(effGhostOpacity); drawPie(darkness !== 0 || borderWidth !== 0); darken(effGhostOpacity); setupBorderColor(ghostOpacity * borderOpacity); drawBorder(); context.translate(-gx, -gy); } setupShapeColor(); drawShape(); drawImages(); drawPie(darkness !== 0 || borderWidth !== 0); darken(); setupBorderColor(); drawBorder(); if (usePaths) { context.translate(-pos.x, -pos.y); } drawText(); drawOverlay(); // // clean up shift if (shiftToOriginWithBb) { context.translate(bb.x1, bb.y1); } }; // does the node have at least one pie piece? CRp.hasPie = function (node) { node = node[0]; // ensure ele ref return node._private.hasPie; }; CRp.drawPie = function (context, node, nodeOpacity, pos) { node = node[0]; // ensure ele ref pos = pos || node.position(); var cyStyle = node.cy().style(); var pieSize = node.pstyle('pie-size'); var x = pos.x; var y = pos.y; var nodeW = node.width(); var nodeH = node.height(); var radius = Math.min(nodeW, nodeH) / 2; // must fit in node var lastPercent = 0; // what % to continue drawing pie slices from on [0, 1] var usePaths = this.usePaths(); if (usePaths) { x = 0; y = 0; } if (pieSize.units === '%') { radius = radius * pieSize.pfValue; } else if (pieSize.pfValue !== undefined) { radius = pieSize.pfValue / 2; } for (var i = 1; i <= cyStyle.pieBackgroundN; i++) { // 1..N var size = node.pstyle('pie-' + i + '-background-size').value; var color = node.pstyle('pie-' + i + '-background-color').value; var opacity = node.pstyle('pie-' + i + '-background-opacity').value * nodeOpacity; var percent = size / 100; // map integer range [0, 100] to [0, 1] // percent can't push beyond 1 if (percent + lastPercent > 1) { percent = 1 - lastPercent; } var angleStart = 1.5 * Math.PI + 2 * Math.PI * lastPercent; // start at 12 o'clock and go clockwise var angleDelta = 2 * Math.PI * percent; var angleEnd = angleStart + angleDelta; // ignore if // - zero size // - we're already beyond the full circle // - adding the current slice would go beyond the full circle if (size === 0 || lastPercent >= 1 || lastPercent + percent > 1) { continue; } context.beginPath(); context.moveTo(x, y); context.arc(x, y, radius, angleStart, angleEnd); context.closePath(); this.fillStyle(context, color[0], color[1], color[2], opacity); context.fill(); lastPercent += percent; } }; module.exports = CRp; /***/ }), /* 133 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var CRp = {}; var util = __webpack_require__(1); var motionBlurDelay = 100; // var isFirefox = typeof InstallTrigger !== 'undefined'; CRp.getPixelRatio = function () { var context = this.data.contexts[0]; if (this.forcedPixelRatio != null) { return this.forcedPixelRatio; } var backingStore = context.backingStorePixelRatio || context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio || context.backingStorePixelRatio || 1; return (window.devicePixelRatio || 1) / backingStore; // eslint-disable-line no-undef }; CRp.paintCache = function (context) { var caches = this.paintCaches = this.paintCaches || []; var needToCreateCache = true; var cache; for (var i = 0; i < caches.length; i++) { cache = caches[i]; if (cache.context === context) { needToCreateCache = false; break; } } if (needToCreateCache) { cache = { context: context }; caches.push(cache); } return cache; }; CRp.fillStyle = function (context, r, g, b, a) { context.fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; // turn off for now, seems context does its own caching // var cache = this.paintCache(context); // var fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; // if( cache.fillStyle !== fillStyle ){ // context.fillStyle = cache.fillStyle = fillStyle; // } }; CRp.strokeStyle = function (context, r, g, b, a) { context.strokeStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; // turn off for now, seems context does its own caching // var cache = this.paintCache(context); // var strokeStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; // if( cache.strokeStyle !== strokeStyle ){ // context.strokeStyle = cache.strokeStyle = strokeStyle; // } }; // Resize canvas CRp.matchCanvasSize = function (container) { var r = this; var data = r.data; var bb = r.findContainerClientCoords(); var width = bb[2]; var height = bb[3]; var pixelRatio = r.getPixelRatio(); var mbPxRatio = r.motionBlurPxRatio; if (container === r.data.bufferCanvases[r.MOTIONBLUR_BUFFER_NODE] || container === r.data.bufferCanvases[r.MOTIONBLUR_BUFFER_DRAG]) { pixelRatio = mbPxRatio; } var canvasWidth = width * pixelRatio; var canvasHeight = height * pixelRatio; var canvas; if (canvasWidth === r.canvasWidth && canvasHeight === r.canvasHeight) { return; // save cycles if same } r.fontCaches = null; // resizing resets the style var canvasContainer = data.canvasContainer; canvasContainer.style.width = width + 'px'; canvasContainer.style.height = height + 'px'; for (var i = 0; i < r.CANVAS_LAYERS; i++) { canvas = data.canvases[i]; canvas.width = canvasWidth; canvas.height = canvasHeight; canvas.style.width = width + 'px'; canvas.style.height = height + 'px'; } for (var i = 0; i < r.BUFFER_COUNT; i++) { canvas = data.bufferCanvases[i]; canvas.width = canvasWidth; canvas.height = canvasHeight; canvas.style.width = width + 'px'; canvas.style.height = height + 'px'; } r.textureMult = 1; if (pixelRatio <= 1) { canvas = data.bufferCanvases[r.TEXTURE_BUFFER]; r.textureMult = 2; canvas.width = canvasWidth * r.textureMult; canvas.height = canvasHeight * r.textureMult; } r.canvasWidth = canvasWidth; r.canvasHeight = canvasHeight; }; CRp.renderTo = function (cxt, zoom, pan, pxRatio) { this.render({ forcedContext: cxt, forcedZoom: zoom, forcedPan: pan, drawAllLayers: true, forcedPxRatio: pxRatio }); }; CRp.render = function (options) { options = options || util.staticEmptyObject(); var forcedContext = options.forcedContext; var drawAllLayers = options.drawAllLayers; var drawOnlyNodeLayer = options.drawOnlyNodeLayer; var forcedZoom = options.forcedZoom; var forcedPan = options.forcedPan; var r = this; var pixelRatio = options.forcedPxRatio === undefined ? this.getPixelRatio() : options.forcedPxRatio; var cy = r.cy;var data = r.data; var needDraw = data.canvasNeedsRedraw; var textureDraw = r.textureOnViewport && !forcedContext && (r.pinching || r.hoverData.dragging || r.swipePanning || r.data.wheelZooming); var motionBlur = options.motionBlur !== undefined ? options.motionBlur : r.motionBlur; var mbPxRatio = r.motionBlurPxRatio; var hasCompoundNodes = cy.hasCompoundNodes(); var inNodeDragGesture = r.hoverData.draggingEles; var inBoxSelection = r.hoverData.selecting || r.touchData.selecting ? true : false; motionBlur = motionBlur && !forcedContext && r.motionBlurEnabled && !inBoxSelection; var motionBlurFadeEffect = motionBlur; if (!forcedContext) { if (r.prevPxRatio !== pixelRatio) { r.invalidateContainerClientCoordsCache(); r.matchCanvasSize(r.container); r.redrawHint('eles', true); r.redrawHint('drag', true); } r.prevPxRatio = pixelRatio; } if (!forcedContext && r.motionBlurTimeout) { clearTimeout(r.motionBlurTimeout); } if (motionBlur) { if (r.mbFrames == null) { r.mbFrames = 0; } r.mbFrames++; if (r.mbFrames < 3) { // need several frames before even high quality motionblur motionBlurFadeEffect = false; } // go to lower quality blurry frames when several m/b frames have been rendered (avoids flashing) if (r.mbFrames > r.minMbLowQualFrames) { //r.fullQualityMb = false; r.motionBlurPxRatio = r.mbPxRBlurry; } } if (r.clearingMotionBlur) { r.motionBlurPxRatio = 1; } // b/c drawToContext() may be async w.r.t. redraw(), keep track of last texture frame // because a rogue async texture frame would clear needDraw if (r.textureDrawLastFrame && !textureDraw) { needDraw[r.NODE] = true; needDraw[r.SELECT_BOX] = true; } var coreStyle = cy.style()._private.coreStyle; var zoom = cy.zoom(); var effectiveZoom = forcedZoom !== undefined ? forcedZoom : zoom; var pan = cy.pan(); var effectivePan = { x: pan.x, y: pan.y }; var vp = { zoom: zoom, pan: { x: pan.x, y: pan.y } }; var prevVp = r.prevViewport; var viewportIsDiff = prevVp === undefined || vp.zoom !== prevVp.zoom || vp.pan.x !== prevVp.pan.x || vp.pan.y !== prevVp.pan.y; // we want the low quality motionblur only when the viewport is being manipulated etc (where it's not noticed) if (!viewportIsDiff && !(inNodeDragGesture && !hasCompoundNodes)) { r.motionBlurPxRatio = 1; } if (forcedPan) { effectivePan = forcedPan; } // apply pixel ratio effectiveZoom *= pixelRatio; effectivePan.x *= pixelRatio; effectivePan.y *= pixelRatio; var eles = r.getCachedZSortedEles(); function mbclear(context, x, y, w, h) { var gco = context.globalCompositeOperation; context.globalCompositeOperation = 'destination-out'; r.fillStyle(context, 255, 255, 255, r.motionBlurTransparency); context.fillRect(x, y, w, h); context.globalCompositeOperation = gco; } function setContextTransform(context, clear) { var ePan, eZoom, w, h; if (!r.clearingMotionBlur && (context === data.bufferContexts[r.MOTIONBLUR_BUFFER_NODE] || context === data.bufferContexts[r.MOTIONBLUR_BUFFER_DRAG])) { ePan = { x: pan.x * mbPxRatio, y: pan.y * mbPxRatio }; eZoom = zoom * mbPxRatio; w = r.canvasWidth * mbPxRatio; h = r.canvasHeight * mbPxRatio; } else { ePan = effectivePan; eZoom = effectiveZoom; w = r.canvasWidth; h = r.canvasHeight; } context.setTransform(1, 0, 0, 1, 0, 0); if (clear === 'motionBlur') { mbclear(context, 0, 0, w, h); } else if (!forcedContext && (clear === undefined || clear)) { context.clearRect(0, 0, w, h); } if (!drawAllLayers) { context.translate(ePan.x, ePan.y); context.scale(eZoom, eZoom); } if (forcedPan) { context.translate(forcedPan.x, forcedPan.y); } if (forcedZoom) { context.scale(forcedZoom, forcedZoom); } } if (!textureDraw) { r.textureDrawLastFrame = false; } if (textureDraw) { r.textureDrawLastFrame = true; var bb; if (!r.textureCache) { r.textureCache = {}; bb = r.textureCache.bb = cy.mutableElements().boundingBox(); r.textureCache.texture = r.data.bufferCanvases[r.TEXTURE_BUFFER]; var cxt = r.data.bufferContexts[r.TEXTURE_BUFFER]; cxt.setTransform(1, 0, 0, 1, 0, 0); cxt.clearRect(0, 0, r.canvasWidth * r.textureMult, r.canvasHeight * r.textureMult); r.render({ forcedContext: cxt, drawOnlyNodeLayer: true, forcedPxRatio: pixelRatio * r.textureMult }); var vp = r.textureCache.viewport = { zoom: cy.zoom(), pan: cy.pan(), width: r.canvasWidth, height: r.canvasHeight }; vp.mpan = { x: (0 - vp.pan.x) / vp.zoom, y: (0 - vp.pan.y) / vp.zoom }; } needDraw[r.DRAG] = false; needDraw[r.NODE] = false; var context = data.contexts[r.NODE]; var texture = r.textureCache.texture; var vp = r.textureCache.viewport; bb = r.textureCache.bb; context.setTransform(1, 0, 0, 1, 0, 0); if (motionBlur) { mbclear(context, 0, 0, vp.width, vp.height); } else { context.clearRect(0, 0, vp.width, vp.height); } var outsideBgColor = coreStyle['outside-texture-bg-color'].value; var outsideBgOpacity = coreStyle['outside-texture-bg-opacity'].value; r.fillStyle(context, outsideBgColor[0], outsideBgColor[1], outsideBgColor[2], outsideBgOpacity); context.fillRect(0, 0, vp.width, vp.height); var zoom = cy.zoom(); setContextTransform(context, false); context.clearRect(vp.mpan.x, vp.mpan.y, vp.width / vp.zoom / pixelRatio, vp.height / vp.zoom / pixelRatio); context.drawImage(texture, vp.mpan.x, vp.mpan.y, vp.width / vp.zoom / pixelRatio, vp.height / vp.zoom / pixelRatio); } else if (r.textureOnViewport && !forcedContext) { // clear the cache since we don't need it r.textureCache = null; } var extent = cy.extent(); var vpManip = r.pinching || r.hoverData.dragging || r.swipePanning || r.data.wheelZooming || r.hoverData.draggingEles; var hideEdges = r.hideEdgesOnViewport && vpManip; var needMbClear = []; needMbClear[r.NODE] = !needDraw[r.NODE] && motionBlur && !r.clearedForMotionBlur[r.NODE] || r.clearingMotionBlur; if (needMbClear[r.NODE]) { r.clearedForMotionBlur[r.NODE] = true; } needMbClear[r.DRAG] = !needDraw[r.DRAG] && motionBlur && !r.clearedForMotionBlur[r.DRAG] || r.clearingMotionBlur; if (needMbClear[r.DRAG]) { r.clearedForMotionBlur[r.DRAG] = true; } if (needDraw[r.NODE] || drawAllLayers || drawOnlyNodeLayer || needMbClear[r.NODE]) { var useBuffer = motionBlur && !needMbClear[r.NODE] && mbPxRatio !== 1; var context = forcedContext || (useBuffer ? r.data.bufferContexts[r.MOTIONBLUR_BUFFER_NODE] : data.contexts[r.NODE]); var clear = motionBlur && !useBuffer ? 'motionBlur' : undefined; setContextTransform(context, clear); if (hideEdges) { r.drawCachedNodes(context, eles.nondrag, pixelRatio, extent); } else { r.drawLayeredElements(context, eles.nondrag, pixelRatio, extent); } if (r.debug) { r.drawDebugPoints(context, eles.nondrag); } if (!drawAllLayers && !motionBlur) { needDraw[r.NODE] = false; } } if (!drawOnlyNodeLayer && (needDraw[r.DRAG] || drawAllLayers || needMbClear[r.DRAG])) { var useBuffer = motionBlur && !needMbClear[r.DRAG] && mbPxRatio !== 1; var context = forcedContext || (useBuffer ? r.data.bufferContexts[r.MOTIONBLUR_BUFFER_DRAG] : data.contexts[r.DRAG]); setContextTransform(context, motionBlur && !useBuffer ? 'motionBlur' : undefined); if (hideEdges) { r.drawCachedNodes(context, eles.drag, pixelRatio, extent); } else { r.drawCachedElements(context, eles.drag, pixelRatio, extent); } if (r.debug) { r.drawDebugPoints(context, eles.drag); } if (!drawAllLayers && !motionBlur) { needDraw[r.DRAG] = false; } } if (r.showFps || !drawOnlyNodeLayer && needDraw[r.SELECT_BOX] && !drawAllLayers) { var context = forcedContext || data.contexts[r.SELECT_BOX]; setContextTransform(context); if (r.selection[4] == 1 && (r.hoverData.selecting || r.touchData.selecting)) { var zoom = r.cy.zoom(); var borderWidth = coreStyle['selection-box-border-width'].value / zoom; context.lineWidth = borderWidth; context.fillStyle = 'rgba(' + coreStyle['selection-box-color'].value[0] + ',' + coreStyle['selection-box-color'].value[1] + ',' + coreStyle['selection-box-color'].value[2] + ',' + coreStyle['selection-box-opacity'].value + ')'; context.fillRect(r.selection[0], r.selection[1], r.selection[2] - r.selection[0], r.selection[3] - r.selection[1]); if (borderWidth > 0) { context.strokeStyle = 'rgba(' + coreStyle['selection-box-border-color'].value[0] + ',' + coreStyle['selection-box-border-color'].value[1] + ',' + coreStyle['selection-box-border-color'].value[2] + ',' + coreStyle['selection-box-opacity'].value + ')'; context.strokeRect(r.selection[0], r.selection[1], r.selection[2] - r.selection[0], r.selection[3] - r.selection[1]); } } if (data.bgActivePosistion && !r.hoverData.selecting) { var zoom = r.cy.zoom(); var pos = data.bgActivePosistion; context.fillStyle = 'rgba(' + coreStyle['active-bg-color'].value[0] + ',' + coreStyle['active-bg-color'].value[1] + ',' + coreStyle['active-bg-color'].value[2] + ',' + coreStyle['active-bg-opacity'].value + ')'; context.beginPath(); context.arc(pos.x, pos.y, coreStyle['active-bg-size'].pfValue / zoom, 0, 2 * Math.PI); context.fill(); } var timeToRender = r.lastRedrawTime; if (r.showFps && timeToRender) { timeToRender = Math.round(timeToRender); var fps = Math.round(1000 / timeToRender); context.setTransform(1, 0, 0, 1, 0, 0); context.fillStyle = 'rgba(255, 0, 0, 0.75)'; context.strokeStyle = 'rgba(255, 0, 0, 0.75)'; context.lineWidth = 1; context.fillText('1 frame = ' + timeToRender + ' ms = ' + fps + ' fps', 0, 20); var maxFps = 60; context.strokeRect(0, 30, 250, 20); context.fillRect(0, 30, 250 * Math.min(fps / maxFps, 1), 20); } if (!drawAllLayers) { needDraw[r.SELECT_BOX] = false; } } // motionblur: blit rendered blurry frames if (motionBlur && mbPxRatio !== 1) { var cxtNode = data.contexts[r.NODE]; var txtNode = r.data.bufferCanvases[r.MOTIONBLUR_BUFFER_NODE]; var cxtDrag = data.contexts[r.DRAG]; var txtDrag = r.data.bufferCanvases[r.MOTIONBLUR_BUFFER_DRAG]; var drawMotionBlur = function drawMotionBlur(cxt, txt, needClear) { cxt.setTransform(1, 0, 0, 1, 0, 0); if (needClear || !motionBlurFadeEffect) { cxt.clearRect(0, 0, r.canvasWidth, r.canvasHeight); } else { mbclear(cxt, 0, 0, r.canvasWidth, r.canvasHeight); } var pxr = mbPxRatio; cxt.drawImage(txt, // img 0, 0, // sx, sy r.canvasWidth * pxr, r.canvasHeight * pxr, // sw, sh 0, 0, // x, y r.canvasWidth, r.canvasHeight // w, h ); }; if (needDraw[r.NODE] || needMbClear[r.NODE]) { drawMotionBlur(cxtNode, txtNode, needMbClear[r.NODE]); needDraw[r.NODE] = false; } if (needDraw[r.DRAG] || needMbClear[r.DRAG]) { drawMotionBlur(cxtDrag, txtDrag, needMbClear[r.DRAG]); needDraw[r.DRAG] = false; } } r.prevViewport = vp; if (r.clearingMotionBlur) { r.clearingMotionBlur = false; r.motionBlurCleared = true; r.motionBlur = true; } if (motionBlur) { r.motionBlurTimeout = setTimeout(function () { r.motionBlurTimeout = null; r.clearedForMotionBlur[r.NODE] = false; r.clearedForMotionBlur[r.DRAG] = false; r.motionBlur = false; r.clearingMotionBlur = !textureDraw; r.mbFrames = 0; needDraw[r.NODE] = true; needDraw[r.DRAG] = true; r.redraw(); }, motionBlurDelay); } if (!forcedContext) { cy.emit('render'); } }; module.exports = CRp; /***/ }), /* 134 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var math = __webpack_require__(2); var CRp = {}; // @O Polygon drawing CRp.drawPolygonPath = function (context, x, y, width, height, points) { var halfW = width / 2; var halfH = height / 2; if (context.beginPath) { context.beginPath(); } context.moveTo(x + halfW * points[0], y + halfH * points[1]); for (var i = 1; i < points.length / 2; i++) { context.lineTo(x + halfW * points[i * 2], y + halfH * points[i * 2 + 1]); } context.closePath(); }; // Round rectangle drawing CRp.drawRoundRectanglePath = function (context, x, y, width, height) { var halfWidth = width / 2; var halfHeight = height / 2; var cornerRadius = math.getRoundRectangleRadius(width, height); if (context.beginPath) { context.beginPath(); } // Start at top middle context.moveTo(x, y - halfHeight); // Arc from middle top to right side context.arcTo(x + halfWidth, y - halfHeight, x + halfWidth, y, cornerRadius); // Arc from right side to bottom context.arcTo(x + halfWidth, y + halfHeight, x, y + halfHeight, cornerRadius); // Arc from bottom to left side context.arcTo(x - halfWidth, y + halfHeight, x - halfWidth, y, cornerRadius); // Arc from left side to topBorder context.arcTo(x - halfWidth, y - halfHeight, x, y - halfHeight, cornerRadius); // Join line context.lineTo(x, y - halfHeight); context.closePath(); }; CRp.drawBottomRoundRectanglePath = function (context, x, y, width, height) { var halfWidth = width / 2; var halfHeight = height / 2; var cornerRadius = math.getRoundRectangleRadius(width, height); if (context.beginPath) { context.beginPath(); } // Start at top middle context.moveTo(x, y - halfHeight); context.lineTo(x + halfWidth, y - halfHeight); context.lineTo(x + halfWidth, y); context.arcTo(x + halfWidth, y + halfHeight, x, y + halfHeight, cornerRadius); context.arcTo(x - halfWidth, y + halfHeight, x - halfWidth, y, cornerRadius); context.lineTo(x - halfWidth, y - halfHeight); context.lineTo(x, y - halfHeight); context.closePath(); }; CRp.drawCutRectanglePath = function (context, x, y, width, height) { var halfWidth = width / 2; var halfHeight = height / 2; var cornerLength = math.getCutRectangleCornerLength(); if (context.beginPath) { context.beginPath(); } context.moveTo(x - halfWidth + cornerLength, y - halfHeight); context.lineTo(x + halfWidth - cornerLength, y - halfHeight); context.lineTo(x + halfWidth, y - halfHeight + cornerLength); context.lineTo(x + halfWidth, y + halfHeight - cornerLength); context.lineTo(x + halfWidth - cornerLength, y + halfHeight); context.lineTo(x - halfWidth + cornerLength, y + halfHeight); context.lineTo(x - halfWidth, y + halfHeight - cornerLength); context.lineTo(x - halfWidth, y - halfHeight + cornerLength); context.closePath(); }; CRp.drawBarrelPath = function (context, x, y, width, height) { var halfWidth = width / 2; var halfHeight = height / 2; var xBegin = x - halfWidth; var xEnd = x + halfWidth; var yBegin = y - halfHeight; var yEnd = y + halfHeight; var barrelCurveConstants = math.getBarrelCurveConstants(width, height); var wOffset = barrelCurveConstants.widthOffset; var hOffset = barrelCurveConstants.heightOffset; var ctrlPtXOffset = barrelCurveConstants.ctrlPtOffsetPct * wOffset; if (context.beginPath) { context.beginPath(); } context.moveTo(xBegin, yBegin + hOffset); context.lineTo(xBegin, yEnd - hOffset); context.quadraticCurveTo(xBegin + ctrlPtXOffset, yEnd, xBegin + wOffset, yEnd); context.lineTo(xEnd - wOffset, yEnd); context.quadraticCurveTo(xEnd - ctrlPtXOffset, yEnd, xEnd, yEnd - hOffset); context.lineTo(xEnd, yBegin + hOffset); context.quadraticCurveTo(xEnd - ctrlPtXOffset, yBegin, xEnd - wOffset, yBegin); context.lineTo(xBegin + wOffset, yBegin); context.quadraticCurveTo(xBegin + ctrlPtXOffset, yBegin, xBegin, yBegin + hOffset); context.closePath(); }; var sin0 = Math.sin(0); var cos0 = Math.cos(0); var sin = {}; var cos = {}; var ellipseStepSize = Math.PI / 40; for (var i = 0 * Math.PI; i < 2 * Math.PI; i += ellipseStepSize) { sin[i] = Math.sin(i); cos[i] = Math.cos(i); } CRp.drawEllipsePath = function (context, centerX, centerY, width, height) { if (context.beginPath) { context.beginPath(); } if (context.ellipse) { context.ellipse(centerX, centerY, width / 2, height / 2, 0, 0, 2 * Math.PI); } else { var xPos, yPos; var rw = width / 2; var rh = height / 2; for (var i = 0 * Math.PI; i < 2 * Math.PI; i += ellipseStepSize) { xPos = centerX - rw * sin[i] * sin0 + rw * cos[i] * cos0; yPos = centerY + rh * cos[i] * sin0 + rh * sin[i] * cos0; if (i === 0) { context.moveTo(xPos, yPos); } else { context.lineTo(xPos, yPos); } } } context.closePath(); }; module.exports = CRp; /***/ }), /* 135 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var CRp = {}; CRp.createBuffer = function (w, h) { var buffer = document.createElement('canvas'); // eslint-disable-line no-undef buffer.width = w; buffer.height = h; return [buffer, buffer.getContext('2d')]; }; CRp.bufferCanvasImage = function (options) { var cy = this.cy; var eles = cy.mutableElements(); var bb = eles.boundingBox(); var ctrRect = this.findContainerClientCoords(); var width = options.full ? Math.ceil(bb.w) : ctrRect[2]; var height = options.full ? Math.ceil(bb.h) : ctrRect[3]; var specdMaxDims = is.number(options.maxWidth) || is.number(options.maxHeight); var pxRatio = this.getPixelRatio(); var scale = 1; if (options.scale !== undefined) { width *= options.scale; height *= options.scale; scale = options.scale; } else if (specdMaxDims) { var maxScaleW = Infinity; var maxScaleH = Infinity; if (is.number(options.maxWidth)) { maxScaleW = scale * options.maxWidth / width; } if (is.number(options.maxHeight)) { maxScaleH = scale * options.maxHeight / height; } scale = Math.min(maxScaleW, maxScaleH); width *= scale; height *= scale; } if (!specdMaxDims) { width *= pxRatio; height *= pxRatio; scale *= pxRatio; } var buffCanvas = document.createElement('canvas'); // eslint-disable-line no-undef buffCanvas.width = width; buffCanvas.height = height; buffCanvas.style.width = width + 'px'; buffCanvas.style.height = height + 'px'; var buffCxt = buffCanvas.getContext('2d'); // Rasterize the layers, but only if container has nonzero size if (width > 0 && height > 0) { buffCxt.clearRect(0, 0, width, height); buffCxt.globalCompositeOperation = 'source-over'; var zsortedEles = this.getCachedZSortedEles(); if (options.full) { // draw the full bounds of the graph buffCxt.translate(-bb.x1 * scale, -bb.y1 * scale); buffCxt.scale(scale, scale); this.drawElements(buffCxt, zsortedEles); buffCxt.scale(1 / scale, 1 / scale); buffCxt.translate(bb.x1 * scale, bb.y1 * scale); } else { // draw the current view var pan = cy.pan(); var translation = { x: pan.x * scale, y: pan.y * scale }; scale *= cy.zoom(); buffCxt.translate(translation.x, translation.y); buffCxt.scale(scale, scale); this.drawElements(buffCxt, zsortedEles); buffCxt.scale(1 / scale, 1 / scale); buffCxt.translate(-translation.x, -translation.y); } // need to fill bg at end like this in order to fill cleared transparent pixels in jpgs if (options.bg) { buffCxt.globalCompositeOperation = 'destination-over'; buffCxt.fillStyle = options.bg; buffCxt.rect(0, 0, width, height); buffCxt.fill(); } } return buffCanvas; }; function b64ToBlob(b64, mimeType) { var bytes = atob(b64); var buff = new ArrayBuffer(bytes.length); var buffUint8 = new Uint8Array(buff); for (var i = 0; i < bytes.length; i++) { buffUint8[i] = bytes.charCodeAt(i); } return new Blob([buff], { type: mimeType }); } function b64UriToB64(b64uri) { var i = b64uri.indexOf(','); return b64uri.substr(i + 1); }; function output(options, canvas, mimeType) { var b64Uri = canvas.toDataURL(mimeType, options.quality); switch (options.output) { case 'blob': return b64ToBlob(b64UriToB64(b64Uri), mimeType); case 'base64': return b64UriToB64(b64Uri); case 'base64uri': default: return b64Uri; } } CRp.png = function (options) { return output(options, this.bufferCanvasImage(options), 'image/png'); }; CRp.jpg = function (options) { return output(options, this.bufferCanvasImage(options), 'image/jpeg'); }; module.exports = CRp; /***/ }), /* 136 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var CRp = {}; CRp.nodeShapeImpl = function (name, context, centerX, centerY, width, height, points) { switch (name) { case 'ellipse': return this.drawEllipsePath(context, centerX, centerY, width, height); case 'polygon': return this.drawPolygonPath(context, centerX, centerY, width, height, points); case 'roundrectangle': return this.drawRoundRectanglePath(context, centerX, centerY, width, height); case 'cutrectangle': return this.drawCutRectanglePath(context, centerX, centerY, width, height); case 'bottomroundrectangle': return this.drawBottomRoundRectanglePath(context, centerX, centerY, width, height); case 'barrel': return this.drawBarrelPath(context, centerX, centerY, width, height); } }; module.exports = CRp; /***/ }), /* 137 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var is = __webpack_require__(0); var util = __webpack_require__(1); var Style = __webpack_require__(18); // a dummy stylesheet object that doesn't need a reference to the core // (useful for init) var Stylesheet = function Stylesheet() { if (!(this instanceof Stylesheet)) { return new Stylesheet(); } this.length = 0; }; var sheetfn = Stylesheet.prototype; sheetfn.instanceString = function () { return 'stylesheet'; }; // just store the selector to be parsed later sheetfn.selector = function (selector) { var i = this.length++; this[i] = { selector: selector, properties: [] }; return this; // chaining }; // just store the property to be parsed later sheetfn.css = function (name, value) { var i = this.length - 1; if (is.string(name)) { this[i].properties.push({ name: name, value: value }); } else if (is.plainObject(name)) { var map = name; for (var j = 0; j < Style.properties.length; j++) { var prop = Style.properties[j]; var mapVal = map[prop.name]; if (mapVal === undefined) { // also try camel case name mapVal = map[util.dash2camel(prop.name)]; } if (mapVal !== undefined) { var _name = prop.name; var _value = mapVal; this[i].properties.push({ name: _name, value: _value }); } } } return this; // chaining }; sheetfn.style = sheetfn.css; // generate a real style object from the dummy stylesheet sheetfn.generateStyle = function (cy) { var style = new Style(cy); return this.appendToStyle(style); }; // append a dummy stylesheet object on a real style object sheetfn.appendToStyle = function (style) { for (var i = 0; i < this.length; i++) { var context = this[i]; var selector = context.selector; var props = context.properties; style.selector(selector); // apply selector for (var j = 0; j < props.length; j++) { var prop = props[j]; style.css(prop.name, prop.value); // apply property } } return style; }; module.exports = Stylesheet; /***/ }), /* 138 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; module.exports = "3.2.20"; /***/ }) /******/ ]); });