UNPKG

jsnetworkx

Version:

A graph processing and visualization library for JavaScript (port of NetworkX for Python).

418 lines (352 loc) 10.7 kB
'use strict'; var _createClass = require('babel-runtime/helpers/create-class')['default']; var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default']; var _getIterator = require('babel-runtime/core-js/get-iterator')['default']; var _Array$from = require('babel-runtime/core-js/array/from')['default']; Object.defineProperty(exports, '__esModule', { value: true }); exports.observe = observe; exports.unobserve = unobserve; exports.isObservable = isObservable; /** * A simple event object to any data can be added. It provides four methods: * * - stopPropagation to indicated that subsequent event handlers should not be * executed. * - isPropgationStopped to test the status (internal only) * - preventDefault to prevent the default action * - isDefaultPrevented to test the status */ var Event = (function () { /** * @param {string} type * @param {*} target */ function Event(type, target) { _classCallCheck(this, Event); this.type = type; this.target = target; this._defaultAction = true; this._propagate = true; } _createClass(Event, [{ key: 'stopPropagation', /** * When called, should prevent the execution of subsequent handlers. */ value: function stopPropagation() { this._propagate = false; } }, { key: 'isPropgationStopped', /** * Tests whether the propagation should be stopped. * @return {boolean} */ value: function isPropgationStopped() { return !this._propagate; } }, { key: 'preventDefault', /** * When called, should prevent the default action. */ value: function preventDefault() { this._defaultAction = false; } }, { key: 'isDefaultPrevented', /** * Tests whether the default action should be stopped. * * @return {boolean} */ value: function isDefaultPrevented() { return !this._defaultAction; } }]); return Event; })(); /** * Makes a graph observable, i.e. external code can bind event handlers to * be notified about changes in the graph (adding or removing nodes or edges). * * @param {Graph} G The graph to make observable * @return {Graph} The same graph passed as argument (not a new graph) */ function observe(G) { if (typeof G.on === 'function') { // graph is already observable, do nothing return G; } var eventHandlers = { 'addNodes': [], 'removeNodes': [], 'addEdges': [], 'removeEdges': [], 'clear': [] }; var proto = G.constructor.prototype; /* eslint-disable no-shadow */ function triggerHandlers(event, G, funcName, args) { /* eslint-enable no-shadow */ var handlers = eventHandlers[event.type]; if (!handlers) { return; } // run before handlers for (var i = 0, l = handlers.length; i < l && !event.isPropgationStopped(); i += 3) { if (handlers[i + 2]) { handlers[i].call(handlers[i + 1] || G, event); } } if (!event.isDefaultPrevented()) { if (args) { proto[funcName].apply(G, args); } else { proto[funcName].call(G); } if (!event.isPropgationStopped()) { // run after handlers for (i = 0, l = handlers.length; i < l && !event.isPropgationStopped(); i += 3) { if (!handlers[i + 2]) { handlers[i].call(handlers[i + 1] || G, event); } } } } } G.on = function (event, handler, thisObj, before) { if (!eventHandlers[event]) { throw new Error('Event "' + event + '" is not supported.'); } eventHandlers[event].push(handler, thisObj, !!before); }; G.off = function (event, handler, thisObj) { var handlers; var startIndex; var i; if (arguments.length === 1) { // Remove all event handlers eventHandlers[event].length = 0; } else if (arguments.length === 2) { // Remove particular handler or object only handlers = eventHandlers[event]; startIndex = handlers.length - 2; if (typeof handler !== 'function') { startIndex += 1; } for (i = startIndex; i > 0; i -= 2) { if (handlers[i] === handler) { handlers.splice(i, 3); } } } else { // Remove particular handler-object combination handlers = eventHandlers[event]; startIndex = handlers.length - 2; for (i = startIndex; i > 0; i -= 2) { if (handlers[i] === handler && handlers[i + 1] === thisObj) { handlers.splice(i, 2); } } } }; G.addNode = function (n) { var newNodes = G.hasNode(n) ? [] : [n]; var event = new Event('addNodes', this); event.nodes = [n]; event.newNodes = newNodes; triggerHandlers(event, this, 'addNode', arguments); }; G.addNodesFrom = function (nbunch) { var nodes = []; var newNodes = []; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = _getIterator(nbunch), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var bunch = _step.value; var v = Array.isArray(bunch) ? bunch[0] : bunch; nodes.push(Array.isArray(bunch) ? bunch.slice() : bunch); if (!G.hasNode(v)) { newNodes.push(v); } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator['return']) { _iterator['return'](); } } finally { if (_didIteratorError) { throw _iteratorError; } } } var event = new Event('addNodes', this); event.nodes = nodes.filter(function (v) { return Array.isArray(v) ? v[0] : v; }); event.newNodes = newNodes; var args = _Array$from(arguments); args[0] = nodes; triggerHandlers(event, this, 'addNodesFrom', args); }; G.addEdge = function (u, v) { var edges = [[u, v]]; var newEdges = this.hasEdge(u, v) ? [] : edges; var event = new Event('addEdges', this); event.edges = edges; event.newEdges = newEdges; triggerHandlers(event, this, 'addEdge', arguments); }; G.addEdgesFrom = function (ebunch) { var edges = []; var newEdges = []; var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = _getIterator(ebunch), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var bunch = _step2.value; edges.push(bunch.slice()); if (!this.hasEdge(bunch[0], bunch[1])) { newEdges.push(bunch.slice(0, 2)); } } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2['return']) { _iterator2['return'](); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } var event = new Event('addEdges', this); event.edges = edges; event.newEdges = newEdges; var args = _Array$from(arguments); args[0] = edges; triggerHandlers(event, this, 'addEdgesFrom', args); }; G.removeNode = function (n) { var event = new Event('removeNodes', this); event.nodes = [n]; triggerHandlers(event, this, 'removeNode', arguments); }; G.removeNodesFrom = function (nbunch) { var nodes = []; var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = _getIterator(nbunch), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var bunch = _step3.value; nodes.push(Array.isArray(bunch) ? bunch.slice() : bunch); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3['return']) { _iterator3['return'](); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } var event = new Event('removeNodes', this); event.nodes = nodes; var args = _Array$from(arguments); args[0] = nodes; triggerHandlers(event, this, 'removeNodesFrom', args); }; G.removeEdge = function (u, v) { var event = new Event('removeEdges', this); event.edges = [[u, v]]; triggerHandlers(event, this, 'removeEdge', arguments); }; G.removeEdgesFrom = function (ebunch) { var edges = []; var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = _getIterator(ebunch), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var bunch = _step4.value; edges.push(bunch.slice()); } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4['return']) { _iterator4['return'](); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } var event = new Event('removeEdges'); event.edges = edges; var args = _Array$from(arguments); args[0] = edges; triggerHandlers(event, this, 'removeEdgesFrom', args); }; G.clear = function () { triggerHandlers(new Event('clear', this), this, 'clear'); }; return G; } /** * Removes the properties added to a graph for event handling. * * @param {Graph} G * @return {Graph} The graph passed to the function */ function unobserve(G) { var proto = G.constructor.prototype; if (typeof G.on !== 'function') { // nothing to do return G; } G.addNode = proto.addNode; G.addNodesFrome = proto.addNodesFrom; G.addEdge = proto.addEdge; G.addEdgesFrome = proto.addEdgesFrom; G.removeNode = proto.removeNode; G.removeEdge = proto.removeEdge; G.removeNodesFrom = proto.removeNodesFrom; G.removeEdgesFrom = proto.removeEdgesFrom; G.clear = proto.clear; delete G.on; delete G.off; return G; } /** * Tests whether the graph is observable. * * @param {Graph} G * @return {boolean} */ function isObservable(G) { return typeof G.on === 'function' && typeof G.off === 'function'; }