(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o * Build: `lodash modern modularize exports="npm" -o ./` * Copyright 2012-2015 The Dojo Foundation * Based on Underscore.js 1.8.3 * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ /** Used as the `TypeError` message for "Functions" methods. */ var FUNC_ERROR_TEXT = 'Expected a function'; /* Native method references for those with the same name as other `lodash` methods. */ var nativeMax = Math.max, nativeNow = Date.now; /** * Gets the number of milliseconds that have elapsed since the Unix epoch * (1 January 1970 00:00:00 UTC). * * @static * @memberOf _ * @category Date * @example * * _.defer(function(stamp) { * console.log(_.now() - stamp); * }, _.now()); * // => logs the number of milliseconds it took for the deferred function to be invoked */ var now = nativeNow || function() { return new Date().getTime(); }; /** * 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 invocations. Provide an options object to indicate that `func` * should be invoked on the leading and/or trailing edge of the `wait` timeout. * 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 the debounced function is * invoked more than once during the `wait` timeout. * * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) * for details over the differences between `_.debounce` and `_.throttle`. * * @static * @memberOf _ * @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 the click event is fired, debouncing subsequent calls * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { * 'leading': true, * 'trailing': false * })); * * // ensure `batchLog` is invoked once after 1 second of debounced calls * var source = new EventSource('/stream'); * jQuery(source).on('message', _.debounce(batchLog, 250, { * 'maxWait': 1000 * })); * * // cancel a debounced call * var todoChanges = _.debounce(batchLog, 1000); * Object.observe(models.todo, todoChanges); * * Object.observe(models, function(changes) { * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { * todoChanges.cancel(); * } * }, ['delete']); * * // ...at some point `models.todo` is changed * models.todo.completed = true; * * // ...before 1 second has passed `models.todo` is deleted * // which cancels the debounced `todoChanges` call * delete models.todo; */ function debounce(func, wait, options) { var args, maxTimeoutId, result, stamp, thisArg, timeoutId, trailingCall, lastCalled = 0, maxWait = false, trailing = true; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } wait = wait < 0 ? 0 : (+wait || 0); if (options === true) { var leading = true; trailing = false; } else if (isObject(options)) { leading = !!options.leading; maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); trailing = 'trailing' in options ? !!options.trailing : trailing; } function cancel() { if (timeoutId) { clearTimeout(timeoutId); } if (maxTimeoutId) { clearTimeout(maxTimeoutId); } lastCalled = 0; maxTimeoutId = timeoutId = trailingCall = undefined; } function complete(isCalled, id) { if (id) { clearTimeout(id); } maxTimeoutId = timeoutId = trailingCall = undefined; if (isCalled) { lastCalled = now(); result = func.apply(thisArg, args); if (!timeoutId && !maxTimeoutId) { args = thisArg = undefined; } } } function delayed() { var remaining = wait - (now() - stamp); if (remaining <= 0 || remaining > wait) { complete(trailingCall, maxTimeoutId); } else { timeoutId = setTimeout(delayed, remaining); } } function maxDelayed() { complete(trailing, timeoutId); } function debounced() { args = arguments; stamp = now(); thisArg = this; trailingCall = trailing && (timeoutId || !leading); if (maxWait === false) { var leadingCall = leading && !timeoutId; } else { if (!maxTimeoutId && !leading) { lastCalled = stamp; } var remaining = maxWait - (stamp - lastCalled), isCalled = remaining <= 0 || remaining > maxWait; if (isCalled) { if (maxTimeoutId) { maxTimeoutId = clearTimeout(maxTimeoutId); } lastCalled = stamp; result = func.apply(thisArg, args); } else if (!maxTimeoutId) { maxTimeoutId = setTimeout(maxDelayed, remaining); } } if (isCalled && timeoutId) { timeoutId = clearTimeout(timeoutId); } else if (!timeoutId && wait !== maxWait) { timeoutId = setTimeout(delayed, wait); } if (leadingCall) { isCalled = true; result = func.apply(thisArg, args); } if (isCalled && !timeoutId && !maxTimeoutId) { args = thisArg = undefined; } return result; } debounced.cancel = cancel; return debounced; } /** * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @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(1); * // => false */ function isObject(value) { // Avoid a V8 JIT bug in Chrome 19-20. // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. var type = typeof value; return !!value && (type == 'object' || type == 'function'); } return debounce; })(); module.exports = debounce; },{}],3:[function(require,module,exports){ module.exports = function (cy, snap) { var discreteDrag = {}; var attachedNode; var draggedNodes; var startPos; var endPos; discreteDrag.onTapStartNode = function (e) { if (e.cyTarget.selected()) draggedNodes = e.cy.$(":selected"); else draggedNodes = e.cyTarget; startPos = e.cyPosition; attachedNode = e.cyTarget; attachedNode.lock(); attachedNode.trigger("grab"); cy.on("tapdrag", onTapDrag); cy.on("tapend", onTapEndNode); }; var onTapEndNode = function (e) { //attachedNode.trigger("free"); cy.off("tapdrag", onTapDrag); cy.off("tapend", onTapEndNode); attachedNode.unlock(); e.preventDefault(); }; var getDist = function () { return { x: endPos.x - startPos.x, y: endPos.y - startPos.y } }; function getTopMostNodes(nodes) { var nodesMap = {}; for (var i = 0; i < nodes.length; i++) { nodesMap[nodes[i].id()] = true; } var roots = nodes.filter(function (i, ele) { var parent = ele.parent()[0]; while (parent != null) { if (nodesMap[parent.id()]) { return false; } parent = parent.parent()[0]; } return true; }); return roots; } var moveNodesTopDown = function (nodes, dx, dy) { /* console.log(nodes.map(function (e) { return e.id(); })); for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; var pos = node.position(); if (!node.isParent()) { node.position({ x: pos.x + dx, y: pos.y + dy }); console.log(node.id() + " " + dx + " " + dy); } moveNodesTopDown(nodes.children(), dx, dy); } */ }; var onTapDrag = function (e) { var nodePos = attachedNode.position(); endPos = e.cyPosition; endPos = snap.snapPos(endPos); var dist = getDist(); if (dist.x != 0 || dist.y != 0) { attachedNode.unlock(); //var topMostNodes = getTopMostNodes(draggedNodes); var nodes = draggedNodes.union(draggedNodes.descendants()); nodes.positions(function (i, node) { var pos = node.position(); return snap.snapPos({ x: pos.x + dist.x, y: pos.y + dist.y }); }); startPos = endPos; attachedNode.lock(); attachedNode.trigger("drag"); } }; return discreteDrag; }; },{}],4:[function(require,module,exports){ module.exports = function (opts, cy, $, debounce) { var options = opts; var changeOptions = function (opts) { options = opts; }; var $canvas = $( '' ); var $container = $( cy.container() ); var ctx = $canvas[ 0 ].getContext( '2d' ); $container.append( $canvas ); var drawGrid = function() { clearDrawing(); var zoom = cy.zoom(); var canvasWidth = $container.width(); var canvasHeight = $container.height(); var increment = options.gridSpacing*zoom; var pan = cy.pan(); var initialValueX = pan.x%increment; var initialValueY = pan.y%increment; ctx.strokeStyle = options.strokeStyle; ctx.lineWidth = options.lineWidth; if(options.zoomDash) { var zoomedDash = options.lineDash.slice(); for(var i = 0; i < zoomedDash.length; i++) { zoomedDash[ i ] = options.lineDash[ i ]*zoom; } ctx.setLineDash( zoomedDash ); } else { ctx.setLineDash( options.lineDash ); } if(options.panGrid) { ctx.lineDashOffset = -pan.y; } else { ctx.lineDashOffset = 0; } for(var i = initialValueX; i < canvasWidth; i += increment) { ctx.beginPath(); ctx.moveTo( i, 0 ); ctx.lineTo( i, canvasHeight ); ctx.stroke(); } if(options.panGrid) { ctx.lineDashOffset = -pan.x; } else { ctx.lineDashOffset = 0; } for(var i = initialValueY; i < canvasHeight; i += increment) { ctx.beginPath(); ctx.moveTo( 0, i ); ctx.lineTo( canvasWidth, i ); ctx.stroke(); } }; var clearDrawing = function() { var width = $container.width(); var height = $container.height(); ctx.clearRect( 0, 0, width, height ); }; var resizeCanvas = debounce(function() { $canvas .attr( 'height', $container.height() ) .attr( 'width', $container.width() ) .css( { 'position': 'absolute', 'top': 0, 'left': 0, 'z-index': options.gridStackOrder } ); setTimeout( function() { var canvasBb = $canvas.offset(); var containerBb = $container.offset(); $canvas .attr( 'height', $container.height() ) .attr( 'width', $container.width() ) .css( { 'top': -( canvasBb.top - containerBb.top ), 'left': -( canvasBb.left - containerBb.left ) } ); drawGrid(); }, 0 ); }, 250); return { initCanvas: resizeCanvas, resizeCanvas: resizeCanvas, clearCanvas: clearDrawing, drawGrid: drawGrid, changeOptions: changeOptions, sizeCanvas: drawGrid }; }; },{}],5:[function(require,module,exports){ module.exports = function (cy, snap, resize, discreteDrag, drawGrid, guidelines, parentPadding, $) { var feature = function (func) { return function (enable) { func(enable); }; }; var controller = { discreteDrag: new feature(setDiscreteDrag), resize: new feature(setResize), snapToGrid: new feature(setSnapToGrid), drawGrid: new feature(setDrawGrid), guidelines: new feature(setGuidelines), parentPadding: new feature(setParentPadding) }; function applyToCyTarget(func, allowParent) { return function (e) { if (!e.cyTarget.is(":parent") || allowParent) func(e.cyTarget); } } function applyToActiveNodes(func, allowParent) { return function (e) { if (!e.cyTarget.is(":parent") || allowParent) if (e.cyTarget.selected()) func(e.cyTarget, e.cy.$(":selected")); else func(e.cyTarget, e.cyTarget); } } function applyToAllNodesButNoParent(func) { return function () { cy.nodes().not(":parent").each(function (i, ele) { func(ele); }); }; } function applyToAllNodes(func) { return function () { cy.nodes().each(function (i, ele) { func(ele); }); }; } function eventStatus(enable) { return enable ? "on" : "off"; } // Discrete Drag function setDiscreteDrag(enable) { cy[eventStatus(enable)]("tapstart", "node", discreteDrag.onTapStartNode); } // Resize var resizeAllNodes = applyToAllNodesButNoParent(resize.resizeNode); var resizeNode = applyToCyTarget(resize.resizeNode); var recoverAllNodeDimensions = applyToAllNodesButNoParent(resize.recoverNodeDimensions); function setResize(enable) { cy[eventStatus(enable)]("ready", resizeAllNodes); // cy[eventStatus(enable)]("style", "node", resizeNode); enable ? resizeAllNodes() : recoverAllNodeDimensions(); } // Snap To Grid var snapAllNodes = applyToAllNodes(snap.snapNodesTopDown); var recoverSnapAllNodes = applyToAllNodes(snap.recoverSnapNode); var snapCyTarget = applyToCyTarget(snap.snapNode, true); function setSnapToGrid(enable) { cy[eventStatus(enable)]("add", "node", snapCyTarget); cy[eventStatus(enable)]("ready", snapAllNodes); cy[eventStatus(enable)]("free", "node", snap.onFreeNode); if (enable) { snapAllNodes(); } else { recoverSnapAllNodes(); } } // Draw Grid var drawGridOnZoom = function () { if (currentOptions.zoomDash) drawGrid.drawGrid() }; var drawGridOnPan = function () { if (currentOptions.panGrid) drawGrid.drawGrid() }; function setDrawGrid(enable) { cy[eventStatus(enable)]('zoom', drawGridOnZoom); cy[eventStatus(enable)]('pan', drawGridOnPan); cy[eventStatus(enable)]('ready', drawGrid.resizeCanvas); if (enable) { drawGrid.initCanvas(); $(window).on('resize', drawGrid.resizeCanvas); } else { drawGrid.clearCanvas(); $(window).off('resize', drawGrid.resizeCanvas); } } // Guidelines function setGuidelines(enable) { cy[eventStatus(enable)]('zoom', guidelines.onZoom); cy[eventStatus(enable)]('drag', "node", guidelines.onDragNode); cy[eventStatus(enable)]('grab', "node", guidelines.onGrabNode); cy[eventStatus(enable)]('free', "node", guidelines.onFreeNode); } // Parent Padding var setAllParentPaddings = function (enable) { parentPadding.setPaddingOfParent(cy.nodes(":parent"), enable); }; var enableParentPadding = function (node) { parentPadding.setPaddingOfParent(node, true); }; function setParentPadding(enable) { setAllParentPaddings(enable); cy[eventStatus(enable)]('ready', setAllParentPaddings); cy[eventStatus(enable)]("add", "node:parent", applyToCyTarget(enableParentPadding, true)); } // Sync with options: Enables/disables changed via options. var latestOptions = {}; var currentOptions; var specialOpts = { drawGrid: ["gridSpacing", "zoomDash", "panGrid", "gridStackOrder", "strokeStyle", "lineWidth", "lineDash"], guidelines: ["gridSpacing", "guidelinesStackOrder", "guidelinesTolerance", "guidelinesStyle"], resize: ["gridSpacing"], parentPadding: ["gridSpacing", "parentSpacing"], snapToGrid: ["gridSpacing"] }; function syncWithOptions(options) { currentOptions = $.extend(true, {}, options); for (var key in options) if (latestOptions[key] != options[key]) if (controller.hasOwnProperty(key)) { controller[key](options[key]); } else { for (var optsKey in specialOpts) { var opts = specialOpts[optsKey]; if (opts.indexOf(key) >= 0) { if(optsKey == "drawGrid") { drawGrid.changeOptions(options); if (options.drawGrid) drawGrid.resizeCanvas(); } if (optsKey == "snapToGrid"){ snap.changeOptions(options); if (options.snapToGrid) snapAllNodes(); } if(optsKey == "guidelines") guidelines.changeOptions(options); if (optsKey == "resize") { resize.changeOptions(options); if (options.resize) resizeAllNodes(); } if (optsKey == "parentPadding") parentPadding.changeOptions(options); } } } latestOptions = $.extend(true, latestOptions, options); } return { init: syncWithOptions, syncWithOptions: syncWithOptions }; }; },{}],6:[function(require,module,exports){ module.exports = function (opts, cy, $, debounce) { var options = opts; var changeOptions = function (opts) { options = opts; }; function calcDistance(p1, p2) { return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2)); } function getExtraDim(node, paddingDim) { } var dims = function (node) { var pos = node.renderedPosition(); var width = node.renderedWidth(); var height = node.renderedHeight(); var padding = { left: Number(node.renderedStyle("padding-left").replace("px", "")), right: Number(node.renderedStyle("padding-right").replace("px", "")), top: Number(node.renderedStyle("padding-top").replace("px", "")), bottom: Number(node.renderedStyle("padding-bottom").replace("px", "")) }; this.horizontal = { center: pos.x, left: pos.x - (padding.left + width / 2), right: pos.x + (padding.right + width / 2) }; this.vertical = { center: pos.y, top: pos.y - (padding.top + height / 2), bottom: pos.y + (padding.bottom + height / 2) }; return this; }; var $canvas = $(''); var $container = $(cy.container()); var ctx = $canvas[0].getContext('2d'); $container.append($canvas); $canvas .attr('height', $container.height()) .attr('width', $container.width()) .css({ 'position': 'absolute', 'top': 0, 'left': 0, 'z-index': options.guidelinesStackOrder }); var canvasBb = $canvas.offset(); var containerBb = $container.offset(); $canvas .attr( 'height', $container.height() ) .attr( 'width', $container.width() ) .css( { 'top': -( canvasBb.top - containerBb.top ), 'left': -( canvasBb.left - containerBb.left ) } ); var clearDrawing = function () { var width = $container.width(); var height = $container.height(); ctx.clearRect(0, 0, width, height); }; var pickedNode; function onGrabNode(e) { pickedNode = e.cyTarget; onDragNode(e); } var onDragNode = debounce(function(e) { if (pickedNode) { var node = pickedNode; var mainDims = new dims(node); var cy = e.cy; var nearests = { horizontal: { distance: Number.MAX_VALUE }, vertical: { distance: Number.MAX_VALUE } }; cy.nodes(":visible").not(node.ancestors()).not(node.descendants()).not(node).each(function (i, ele) { var nodeDims = new dims(ele); for (var dim in mainDims) { var mainDim = mainDims[dim]; var nodeDim = nodeDims[dim]; var otherDim = dim == "horizontal" ? "y" : "x"; var eitherDim = otherDim == "x" ? "y" : "x"; for (var key in mainDim) { for (var key2 in nodeDim) { if (Math.abs(mainDim[key] - nodeDim[key2]) < options.guidelinesTolerance) { var distance = calcDistance(node.renderedPosition(), ele.renderedPosition()); if (nearests[dim].distance > distance) { nearests[dim] = { to: ele.id(), toPos: {}, from: node.id(), fromPos: {}, distance: distance }; nearests[dim].fromPos[eitherDim] = mainDim[key]; nearests[dim].fromPos[otherDim] = node.renderedPosition(otherDim); nearests[dim].toPos[eitherDim] = nodeDim[key2]; nearests[dim].toPos[otherDim] = ele.renderedPosition(otherDim); } } // console.log(key + " of " + node.id() + " -> " + key2 + " of " + ele.id()) } } } }); clearDrawing(); for (var key in nearests) { var item = nearests[key]; if (item.from) { ctx.beginPath(); ctx.moveTo(item.fromPos.x, item.fromPos.y); ctx.lineTo(item.toPos.x, item.toPos.y); ctx.setLineDash(options.guidelinesStyle.lineDash); for (var styleKey in options.guidelinesStyle) ctx[styleKey] = options.guidelinesStyle[styleKey]; ctx.stroke(); } } } }, 0, true); function onFreeNode() { pickedNode = undefined; clearDrawing(); } return { onDragNode: onDragNode, onZoom: onDragNode, onGrabNode: onGrabNode, onFreeNode: onFreeNode, changeOptions: changeOptions } }; },{}],7:[function(require,module,exports){ ;(function(){ 'use strict'; // registers the extension on a cytoscape lib ref var register = function( cytoscape ){ if( !cytoscape ){ return; } // can't register if cytoscape unspecified var options = { // On/Off Modules snapToGrid: true, // Snap to grid functionality discreteDrag: true, // Discrete Drag guidelines: true, // Guidelines on dragging nodes resize: true, // Adjust node sizes to cell sizes parentPadding: true, // Adjust parent sizes to cell sizes by padding drawGrid: true, // Draw grid background // Other settings // General gridSpacing: 20, // Distance between the lines of the grid. // Draw Grid zoomDash: true, // Determines whether the size of the dashes should change when the drawing is zoomed in and out if grid is drawn. panGrid: true, // Determines whether the grid should move then the user moves the graph if grid is drawn. gridStackOrder: -1, // Namely z-index strokeStyle: '#dedede', // Color of grid lines lineWidth: 1.0, // Width of grid lines lineDash: [2.5, 4], // Defines style of dash. Read: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash // Guidelines guidelinesStackOrder: 4, // z-index of guidelines guidelinesTolerance: 2.00, // Tolerance distance for rendered positions of nodes' interaction. guidelinesStyle: { // Set ctx properties of line. Properties are here: strokeStyle: "#8b7d6b", lineDash: [3, 5] }, // Parent Padding parentSpacing: -1 // -1 to set paddings of parents to gridSpacing }; var _snap = require("./snap"); var _discreteDrag = require("./discrete_drag"); var _drawGrid = require("./draw_grid"); var _resize = require("./resize"); var _eventsController = require("./events_controller"); var _guidelines = require("./guidelines"); var _parentPadding = require("./parentPadding"); var _alignment = require("./alignment"); var debounce = require("./debounce"); var snap, resize, discreteDrag, drawGrid, eventsController, guidelines, parentPadding, alignment; function getScratch() { if (!cy.scratch("_gridGuide")) { cy.scratch("_gridGuide", { }); } return cy.scratch("_gridGuide"); } cytoscape( 'core', 'gridGuide', function(opts){ var cy = this; $.extend(true, options, opts); if (!getScratch().initialized) { snap = _snap(options.gridSpacing); resize = _resize(options.gridSpacing); discreteDrag = _discreteDrag(cy, snap); drawGrid = _drawGrid(options, cy, $, debounce); guidelines = _guidelines(options, cy, $, debounce); parentPadding = _parentPadding(options, cy); eventsController = _eventsController(cy, snap, resize, discreteDrag, drawGrid, guidelines, parentPadding, $); alignment = _alignment(cytoscape, $); eventsController.init(options); getScratch().initialized = true; } else eventsController.syncWithOptions(options); return this; // chainability } ) ; }; if( typeof module !== 'undefined' && module.exports ){ // expose as a commonjs module module.exports = register; } if( typeof define !== 'undefined' && define.amd ){ // expose as an amd/requirejs module define('cytoscape-grid-guide', function(){ return register; }); } if( typeof cytoscape !== 'undefined' ){ // expose to global cytoscape (i.e. window.cytoscape) register( cytoscape ); } })(); },{"./alignment":1,"./debounce":2,"./discrete_drag":3,"./draw_grid":4,"./events_controller":5,"./guidelines":6,"./parentPadding":8,"./resize":9,"./snap":10}],8:[function(require,module,exports){ module.exports = function (opts, cy) { var options = opts; var ppClass = "_gridParentPadding"; function initPadding() { var padding = options.parentSpacing < 0 ? options.gridSpacing : options.parentSpacing; cy.style() .selector('.' + ppClass) .style("compound-sizing-wrt-labels", "exclude") .style("padding-left", padding) .style("padding-right", padding) .style("padding-top", padding) .style("padding-bottom", padding) .update(); } function changeOptions(opts) { options = opts; padding = options.parentSpacing < 0 ? options.gridSpacing : options.parentSpacing; initPadding(); } function setPaddingOfParent(node, enable) { if (enable) node.addClass(ppClass); else node.removeClass(ppClass); } return { changeOptions: changeOptions, setPaddingOfParent: setPaddingOfParent }; }; },{}],9:[function(require,module,exports){ module.exports = function (gridSpacing) { var changeOptions = function (opts) { gridSpacing = Number(opts.gridSpacing); }; var getScratch = function (node) { if (!node.scratch("_gridGuide")) node.scratch("_gridGuide", {}); return node.scratch("_gridGuide"); }; function resizeNode(node) { var width = node.width(); var height = node.height(); var newWidth = Math.round((width - gridSpacing) / (gridSpacing * 2)) * (gridSpacing * 2); var newHeight = Math.round((height - gridSpacing) / (gridSpacing * 2)) * (gridSpacing * 2); newWidth = newWidth > 0 ? newWidth + gridSpacing : gridSpacing; newHeight = newHeight > 0 ? newHeight + gridSpacing : gridSpacing; if (width != newWidth || height != newHeight) { node.style({ "width": newWidth, "height": newHeight }); getScratch(node).resize = { oldWidth: width, oldHeight: height }; } } function recoverNodeDimensions(node) { var oldSizes = getScratch(node).resize; if (oldSizes) node.style({ "width": oldSizes.oldWidth, "height": oldSizes.oldHeight }); } return { resizeNode: resizeNode, recoverNodeDimensions: recoverNodeDimensions, changeOptions: changeOptions }; }; },{}],10:[function(require,module,exports){ module.exports = function (gridSpacing) { var snap = { }; snap.changeOptions = function (opts) { gridSpacing = opts.gridSpacing; }; var getScratch = function (node) { if (!node.scratch("_gridGuide")) node.scratch("_gridGuide", {}); return node.scratch("_gridGuide"); }; function getTopMostNodes(nodes) { var nodesMap = {}; for (var i = 0; i < nodes.length; i++) { nodesMap[nodes[i].id()] = true; } var roots = nodes.filter(function (i, ele) { var parent = ele.parent()[0]; while(parent != null){ if(nodesMap[parent.id()]){ return false; } parent = parent.parent()[0]; } return true; }); return roots; } snap.snapPos = function (pos) { var newPos = { x: (Math.floor(pos.x / gridSpacing) + 0.5) * gridSpacing, y: (Math.floor(pos.y / gridSpacing) + 0.5) * gridSpacing }; return newPos; }; snap.snapNode = function (node) { var pos = node.position(); var newPos = snap.snapPos(pos); node.position(newPos); }; function snapTopDown(nodes) { nodes.union(nodes.descendants()).positions(function (i, node) { var pos = node.position(); return snap.snapPos(pos); }); /* for (var i = 0; i < nodes.length; i++) { if (!nodes[i].isParent()) snap.snapNode(nodes[i]); snapTopDown(nodes.children()); }*/ } snap.snapNodesTopDown = function (nodes) { // getTOpMostNodes -> nodes cy.startBatch(); nodes.union(nodes.descendants()).positions(function (i, node) { var pos = node.position(); return snap.snapPos(pos); }); cy.endBatch(); }; snap.onFreeNode = function (e) { var nodes; if (e.cyTarget.selected()) nodes = e.cy.$(":selected"); else nodes = e.cyTarget; snap.snapNodesTopDown(nodes); }; snap.recoverSnapNode = function (node) { var snapScratch = getScratch(node).snap; if (snapScratch) { node.position(snapScratch.oldPos); } }; return snap; }; },{}]},{},[7]);