You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2 lines
15 KiB

4 months ago
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).GraphLib={})}(this,(function(e){"use strict";var t=function(){function e(){this._events={}}return e.prototype.on=function(e,t,s){return this._events[e]||(this._events[e]=[]),this._events[e].push({callback:t,once:!!s}),this},e.prototype.once=function(e,t){return this.on(e,t,!0)},e.prototype.emit=function(e){for(var t=this,s=[],d=1;d<arguments.length;d++)s[d-1]=arguments[d];var r=this._events[e]||[],a=this._events["*"]||[],h=function(d){for(var r=d.length,a=0;a<r;a++)if(d[a]){var h=d[a],i=h.callback;h.once&&(d.splice(a,1),0===d.length&&delete t._events[e],r--,a--),i.apply(t,s)}};h(r),h(a)},e.prototype.off=function(e,t){if(e)if(t){for(var s=this._events[e]||[],d=s.length,r=0;r<d;r++)s[r].callback===t&&(s.splice(r,1),d--,r--);0===s.length&&delete this._events[e]}else delete this._events[e];else this._events={};return this},e.prototype.getEvents=function(){return this._events},e}();function s(e,t,s,d){for(;e.length;){const r=e.shift();if(s(r))return!0;t.add(r.id),d(r.id).forEach((s=>{t.has(s.id)||(t.add(s.id),e.push(s))}))}return!1}function d(e,t,s,r){if(s(e))return!0;t.add(e.id);for(const a of r(e.id))if(!t.has(a.id)&&d(a,t,s,r))return!0;return!1}const r=()=>!0;class a{graph;nodeFilter;edgeFilter;cacheEnabled;inEdgesMap=new Map;outEdgesMap=new Map;bothEdgesMap=new Map;allNodesMap=new Map;allEdgesMap=new Map;constructor(e){this.graph=e.graph;const t=e.nodeFilter||r,s=e.edgeFilter||r;this.nodeFilter=t,this.edgeFilter=e=>{const{source:d,target:r}=this.graph.getEdgeDetail(e.id);return!(!t(d)||!t(r))&&s(e,d,r)},"auto"===e.cache?(this.cacheEnabled=!0,this.startAutoCache()):"manual"===e.cache?this.cacheEnabled=!0:this.cacheEnabled=!1}clearCache=()=>{this.inEdgesMap.clear(),this.outEdgesMap.clear(),this.bothEdgesMap.clear(),this.allNodesMap.clear(),this.allEdgesMap.clear()};refreshCache=()=>{this.clearCache(),this.updateCache(this.graph.getAllNodes().map((e=>e.id)))};updateCache=e=>{const t=new Set;e.forEach((e=>{const s=this.bothEdgesMap.get(e);if(s&&s.forEach((e=>t.add(e.id))),this.hasNode(e)){const s=this.graph.getRelatedEdges(e,"in").filter(this.edgeFilter),d=this.graph.getRelatedEdges(e,"out").filter(this.edgeFilter),r=Array.from(new Set([...s,...d]));r.forEach((e=>t.add(e.id))),this.inEdgesMap.set(e,s),this.outEdgesMap.set(e,d),this.bothEdgesMap.set(e,r),this.allNodesMap.set(e,this.graph.getNode(e))}else this.inEdgesMap.delete(e),this.outEdgesMap.delete(e),this.bothEdgesMap.delete(e),this.allNodesMap.delete(e)})),t.forEach((e=>{this.hasEdge(e)?this.allEdgesMap.set(e,this.graph.getEdge(e)):this.allEdgesMap.delete(e)}))};startAutoCache(){this.refreshCache(),this.graph.on("changed",this.handleGraphChanged)}stopAutoCache(){this.graph.off("changed",this.handleGraphChanged)}handleGraphChanged=e=>{const t=new Set;e.changes.forEach((s=>{switch(s.type){case"NodeAdded":case"NodeRemoved":t.add(s.value.id);break;case"NodeDataUpdated":t.add(s.id);break;case"EdgeAdded":case"EdgeRemoved":t.add(s.value.source),t.add(s.value.target);break;case"EdgeUpdated":"source"!==s.propertyName&&"target"!==s.propertyName||(t.add(s.oldValue),t.add(s.newValue));break;case"EdgeDataUpdated":if(e.graph.hasEdge(s.id)){const d=e.graph.getEdge(s.id);t.add(d.source),t.add(d.target)}}})),this.updateCache(t)};checkNodeExistence(e){this.getNode(e)}hasNode(e){if(!this.graph.hasNode(e))return!1;const t=this.graph.getNode(e);return this.nodeFilter(t)}areNeighbors(e,t){return this.checkNodeExistence(e),this.getNeighbors(t).some((t=>t.id===e))}getNode(e){const t=this.graph.getNode(e);if(!this.nodeFilter(t))throw new Error("Node not found for id: "+e);return t}getRelatedEdges(e,t){if(this.checkNodeExistence(e),this.cacheEnabled)return"in"===t?this.inEdgesMap.get(e):"out"===t?this.outEdgesMap.get(e):this.bothEdgesMap.get(e);return this.graph.getRelatedEdges(e,t).filter(this.edgeFilter)}getDegree(e,t){return this.getRelatedEdges(e,t).length}getSuccessors(e){const t=this.getRelatedEdg