note-graph
Version:
a generic visualization tool designed to show the structure of the document space and the relations between each doc
5 lines (4 loc) • 10.1 kB
JavaScript
/**
* @version 0.3.0
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("d3-color"),require("d3-force"),require("d3-scale"),require("force-graph")):"function"==typeof define&&define.amd?define(["exports","d3-color","d3-force","d3-scale","force-graph"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).NOTE_GRAPH={},e.d3,e.d3,e.d3,e.ForceGraph)}(this,(function(e,t,i,o,n){"use strict";function r(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var s=r(n);var h={};function d(e,t,i,o){var n,r=!1,s=0;function h(){n&&clearTimeout(n)}function d(){for(var d=arguments.length,a=new Array(d),l=0;l<d;l++)a[l]=arguments[l];var c=this,u=Date.now()-s;function g(){s=Date.now(),i.apply(c,a)}function f(){n=void 0}r||(o&&!n&&g(),h(),void 0===o&&u>e?g():!0!==t&&(n=setTimeout(o?f:g,void 0===o?e-u:e)))}return"boolean"!=typeof t&&(o=i,i=t,t=void 0),d.cancel=function(){h(),r=!0},d}Object.defineProperty(h,"__esModule",{value:!0});var a=h.debounce=function(e,t,i){return void 0===i?d(e,t,!1):d(e,i,!1!==t)};h.throttle=d;const l=(e,...t)=>{if(!t.length)return e;const i=t.shift();return void 0===i?e:(c(e)&&c(i)&&Object.keys(i).forEach((function(t){c(i[t])?(e[t]||(e[t]={}),l(e[t],i[t])):e[t]=i[t]})),l(e,...t))},c=e=>(e=>null!==e&&"object"==typeof e)(e)&&!Array.isArray(e);function u(e,t,i){return getComputedStyle(e).getPropertyValue(t)||i}function g(e={}){const t=e.container||document.body,i=u(t,"--notegraph-highlighted-foreground-color","#f9c74f");return{background:u(t,"--notegraph-background","#f7f7f7"),fontSize:parseInt(u(t,"--notegraph-font-size",12)),highlightedForeground:i,node:{note:{regular:u(t,"--notegraph-note-color-regular","#5f76e7")},unknown:u(t,"--notegraph-unkown-node-color","#f94144")},link:{regular:u(t,"--notegraph-link-color-regular","#ccc"),highlighted:u(t,"--notegraph-link-color-highlighted",i)},hoverNodeLink:{highlightedDirection:{inbound:"#3078cd",outbound:i}}}}const f=e=>({circle:function(t,i,o,n){return e.beginPath(),e.arc(t,i,o,0,2*Math.PI,!1),e.fillStyle=n,e.fill(),e.closePath(),this},text:function(t,i,o,n,r){return e.font=`${n}px Sans-Serif`,e.textAlign="center",e.textBaseline="top",e.fillStyle=r,e.fillText(t,i,o),this}});e.NoteGraphModel=class{constructor(e){this.subscribers=[],this.notes=e,this.updateCache()}updateCache(){const e=[],t=[],i={},o=new Map;this.notes.forEach((n=>{e.push({id:n.id,data:{note:n}});const r={title:n.title,linkIds:[],neighbors:[]};n.linkTo&&n.linkTo.forEach((e=>{const i={id:this.formLinkId(n.id,e),source:n.id,target:e};t.push(i),o.set(i.id,i),r.linkIds.push(i.id),r.neighbors.push(e)})),n.referencedBy&&n.referencedBy.forEach((e=>{r.linkIds.push(this.formLinkId(e,n.id)),r.neighbors.push(e)})),i[n.id]=r}));const n=this.cache||{};n.nodeInfos=i,n.links=t,n.linkMap=o,this.cache=n}getNodeInfoById(e){return this.cache.nodeInfos[e]}getLinkById(e){return this.cache.linkMap.get(e)}formLinkId(e,t){return`${e}-${t}`}toGraphViewData(){return{graphData:{nodes:this.notes,links:this.cache.links},nodeInfos:this.cache.nodeInfos}}publishChange(){this.subscribers.forEach((e=>{e(this)}))}subscribe(e){return this.subscribers.push(e),()=>{const t=this.subscribers.indexOf(e);t>-1&&this.subscribers.splice(t,1)}}},e.NoteGraphView=class{constructor(e){this.hasEngineStopped=!1,this.engineStopSizingFn=null,this.sizeScaler=o.scaleLinear().domain([0,20]).range([1,4]).clamp(!0),this.labelAlphaScaler=o.scaleLinear().domain([1.2,2]).range([0,1]).clamp(!0),this.interactionCallbacks={},this.hasInitialZoomToFit=!1,this.actions={selectNode(e,t,i){i||e.selectedNodes.clear(),null!=t&&e.selectedNodes.add(t)},highlightNode(e,t){e.hoverNode=t}},this.shouldDebugColor=!1,this.options=e,this.container=e.container,this.model={graphData:{nodes:[],links:[]},nodeInfos:{},selectedNodes:new Set,focusNodes:new Set,focusLinks:new Set,hoverNode:null},this.initStyle(),e.graphModel&&(this.linkWithGraphModel(e.graphModel),e.lazyInitView||this.initView())}initStyle(){this.style||(this.style=g({container:this.container})),l(this.style,this.options.style)}updateStyle(e){this.options.style=l(this.options.style||{},e),this.initStyle(),this.refreshByStyle()}refreshByStyle(){if(!this.forceGraph)return;const e=t.rgb(this.style.background),i=(i,o)=>{const n=o.nodeInfos[i],r=this.style.node.note,s=this.style.node.note[n.type||"regular"]||this.style.node.unknown;switch(this.shouldDebugColor&&console.log("node fill",s),this.getNodeState(i,o)){case"regular":return{fill:s,border:s};case"lessened":let o=r.lessened;if(!o){o=function(e,i,o=.5){const n=e.r*o+i.r*(1-o),r=e.g*o+i.g*(1-o),s=e.b*o+i.b*(1-o);return t.rgb(n,r,s)}(t.rgb(s),e,.2)}return{fill:o,border:o};case"highlighted":return{fill:s,border:this.style.highlightedForeground};default:throw new Error(`Unknown type for node ${i}`)}};this.forceGraph.backgroundColor(this.style.background).nodeCanvasObject(((e,o,n)=>{if(!e.id)return;const r=this.model.nodeInfos[e.id],s=this.sizeScaler(r.neighbors?r.neighbors.length:1),{fill:h,border:d}=i(e.id,this.model),a=this.style.fontSize/n;let l=t.rgb(h);const c=this.getNodeState(e.id,this.model),u=this.labelAlphaScaler(n);l.opacity="highlighted"===c?1:"lessened"===c?Math.min(.2,u):u;const g=r.title;f(o).circle(e.x,e.y,s+.5,d).circle(e.x,e.y,s,h).text(g,e.x,e.y+s+1,a,l)})).linkColor((e=>this.getLinkColor(e,this.model)))}linkWithGraphModel(e){this.currentDataModelEntry&&this.currentDataModelEntry.unsub(),this.updateViewData(e.toGraphViewData());const t=e.subscribe((()=>{this.updateViewData(e.toGraphViewData())}));this.currentDataModelEntry={graphModel:e,unsub:t}}getColorOnContainer(e,t){return getComputedStyle(this.container).getPropertyValue(e)||t}updateViewData(e){Object.assign(this.model,e),e.focusedNode&&(this.model.hoverNode=e.focusedNode)}updateCanvasSize(e){this.forceGraph&&("width"in e&&this.forceGraph.width(e.width),"height"in e&&this.forceGraph.height(e.height))}initView(){const{options:e,model:t,actions:o}=this,n=s.default||window.ForceGraph,r=this.forceGraph||n(),h=e.width||window.innerWidth-this.container.offsetLeft-20,d=e.height||window.innerHeight-this.container.offsetTop-20;r(this.container).height(d).width(h).graphData(t.graphData).linkHoverPrecision(8).enableNodeDrag(!!e.enableNodeDrag).cooldownTime(200).d3Force("x",i.forceX()).d3Force("y",i.forceY()).d3Force("collide",i.forceCollide(r.nodeRelSize())).linkWidth(1).linkDirectionalParticles(1).linkDirectionalParticleWidth((e=>"highlighted"===this.getLinkState(e,t)?2:0)).onEngineStop((()=>{this.hasEngineStopped=!0,this.engineStopSizingFn?this.engineStopSizingFn():this.hasInitialZoomToFit||(this.hasInitialZoomToFit=!0,r.zoomToFit(1e3,20))})).onNodeHover((e=>{o.highlightNode(this.model,e?e.id:null),this.updateViewModeInteractiveState()})).onNodeClick(((e,t)=>{o.selectNode(this.model,e.id,t.getModifierState("Shift")),this.updateViewModeInteractiveState(),this.fireInteraction("nodeClick",{node:e,event:t})})).onLinkClick(((e,t)=>{this.fireInteraction("linkClick",{link:e,event:t})})).onBackgroundClick((e=>{o.selectNode(this.model,null,e.getModifierState("Shift")),this.updateViewModeInteractiveState(),this.fireInteraction("backgroundClick",{event:e})})).onBackgroundRightClick((e=>{r.zoomToFit(1e3,20),this.fireInteraction("backgroundRightClick",{event:e})})),!1!==e.enableSmartZooming&&this.initGraphSmartZooming(r),this.forceGraph=r,this.refreshByStyle()}initGraphSmartZooming(e){let t=!1;const i=a(200,(e=>{if(t)return;const{x:i,y:o}=this.forceGraph.getGraphBbox(),{k:n,x:r,y:s}=e,h=n*i[0],d=n*i[1],a=n*o[0],l=n*o[1],c=this.forceGraph.width(),u=this.forceGraph.height(),g=this.forceGraph.centerAt();let f,p;d+r<0?(t=!1,f=i[1]):h+r>c&&(f=i[0]),a+s>u?p=o[0]:l+s<0&&(p=o[1]),"number"!=typeof f&&"number"!=typeof p||this.forceGraph.centerAt(void 0!==f?f:g.x,void 0!==p?p:g.y,2e3)}));e.onZoom((e=>{this.hasInitialZoomToFit&&i(e)})).onZoomEnd((()=>{setTimeout((()=>{t=!1}),20)}))}getLinkNodeId(e){const t=typeof e;return"string"===t||"number"===t?e:e.id}getNodeState(e,t=this.model){return t.selectedNodes.has(e)||t.hoverNode===e?"highlighted":0===t.focusNodes.size||t.focusNodes.has(e)?"regular":"lessened"}getLinkState(e,t=this.model){return 0===t.focusNodes.size?"regular":t.focusLinks.has(e.id)?"highlighted":"lessened"}getLinkColor(e,i){var o,n;const r=this.style,s=r.link;switch(this.getLinkState(e,i)){case"regular":return s.regular;case"highlighted":let h;const d=r.hoverNodeLink;return i.hoverNode===this.getLinkNodeId(e.source)?h=null===(o=d.highlightedDirection)||void 0===o?void 0:o.outbound:i.hoverNode===this.getLinkNodeId(e.target)&&(h=null===(n=d.highlightedDirection)||void 0===n?void 0:n.inbound),h||s.highlighted||r.highlightedForeground;case"lessened":let a=s.lessened;if(!a){const e=t.hsl(r.node.note.lessened);e.opacity=.2,a=e}return a;default:throw new Error(`Unknown type for link ${e}`)}}updateViewModeInteractiveState(){var e,t;const{model:i}=this,o=new Set,n=new Set;if(i.hoverNode){o.add(i.hoverNode);const r=i.nodeInfos[i.hoverNode];null===(e=r.neighbors)||void 0===e||e.forEach((e=>o.add(e))),null===(t=r.linkIds)||void 0===t||t.forEach((e=>n.add(e)))}i.selectedNodes&&i.selectedNodes.forEach((e=>{var t,r;o.add(e);const s=i.nodeInfos[e];null===(t=s.neighbors)||void 0===t||t.forEach((e=>o.add(e))),null===(r=s.linkIds)||void 0===r||r.forEach((e=>n.add(e)))})),i.focusNodes=o,i.focusLinks=n}setSelectedNodes(e,t={}){const{isAppend:i,shouldZoomToFit:o}=t;if(i||this.model.selectedNodes.clear(),e.forEach((e=>this.actions.selectNode(this.model,e,!0))),this.updateViewModeInteractiveState(),o){const e=()=>{this.forceGraph.zoomToFit(1e3,20,(e=>this.model.focusNodes.has(e.id)))};this.hasEngineStopped?e():this.engineStopSizingFn=()=>{e(),this.engineStopSizingFn=null}}}onInteraction(e,t){this.interactionCallbacks[e]||(this.interactionCallbacks[e]=[]);const i=this.interactionCallbacks[e];return i.push(t),()=>{const e=i.indexOf(t);e>-1&&i.splice(e,1)}}fireInteraction(e,t){const i=this.interactionCallbacks[e];i&&i.forEach((e=>e(t)))}dispose(){this.forceGraph&&this.forceGraph.pauseAnimation()}},e.getColorOnContainer=u,e.getDefaultColorOf=g,Object.defineProperty(e,"__esModule",{value:!0})}));