From 6894e14381887cd1cd6349ea662fc70eb3a6a1d2 Mon Sep 17 00:00:00 2001 From: Rohan Vazarkar Date: Wed, 27 Jul 2016 11:01:19 -0400 Subject: [PATCH] Added path highlighting --- src/components/Graph.jsx | 44 +++++++++++++--- .../SearchContainer/Tabs/GroupNodeData.jsx | 29 ++++++++--- .../SearchContainer/Tabs/UserNodeData.jsx | 4 -- src/index.js | 2 + src/js/bloodhound.js | 2 +- src/js/utils.js | 52 ++++++++++++++++--- 6 files changed, 108 insertions(+), 25 deletions(-) diff --git a/src/components/Graph.jsx b/src/components/Graph.jsx index 5cc8870..1d2a8c2 100644 --- a/src/components/Graph.jsx +++ b/src/components/Graph.jsx @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import { collapseEdgeNodes, setNodeData, collapseSiblingNodes } from 'utils'; +import { collapseEdgeNodes, setNodeData, collapseSiblingNodes, findGraphPath } from 'utils'; export default class GraphContainer extends Component { constructor(props){ @@ -53,7 +53,7 @@ export default class GraphContainer extends Component { function(sigmaInstance){ appStore.spotlightData = {} var design = this.state.design; - sigmaInstance = setNodeData(this.state.sigmaInstance); + sigmaInstance = setNodeData(this.state.sigmaInstance, params.start, params.end); if (params.allowCollapse){ sigmaInstance = collapseEdgeNodes(sigmaInstance); sigmaInstance = collapseSiblingNodes(sigmaInstance); @@ -89,20 +89,20 @@ export default class GraphContainer extends Component { doPathQuery(start, end){ var statement = "MATCH (n {name:'{}'}), (m {name:'{}'}), p=allShortestPaths((n)-[*]->(m)) RETURN p".format(start,end) - appStore.startNode = start - appStore.endNode = end this.doQueryNative({ statement: statement, - allowCollapse: true + allowCollapse: true, + start: start, + end: end }) } doGenericQuery(statement, start, end, allowCollapse=true){ - appStore.startNode = start - appStore.endNode = end this.doQueryNative({ statement: statement, allowCollapse: allowCollapse, + start: start, + end: end }) } @@ -192,6 +192,36 @@ export default class GraphContainer extends Component { sigmaInstance.bind('clickNode', this._nodeClicked.bind(this)) + sigmaInstance.bind('hovers', function(e){ + if (e.data.enter.nodes.length > 0) { + if (appStore.endNode !== null) { + findGraphPath(this.state.sigmaInstance, false, e.data.enter.nodes[0].id) + } + + if (appStore.startNode !== null) { + findGraphPath(this.state.sigmaInstance, true, e.data.enter.nodes[0].id) + } + } + + if (e.data.leave.nodes.length > 0) { + if (appStore.forwardPath.length > 0) { + $.each(appStore.forwardPath, function(index, edge) { + edge.color = '#356'; + }); + appStore.forwardPath = []; + sigmaInstance.refresh({ 'skipIndexation': true }); + } + + if (appStore.reversePath.length > 0) { + $.each(appStore.reversePath, function(index, edge) { + edge.color = '#356'; + }); + appStore.reversePath = []; + sigmaInstance.refresh({ 'skipIndexation': true }); + } + } + }.bind(this)) + var fa = sigma.layouts.configForceLink(sigmaInstance, { worker: true, background: true, diff --git a/src/components/SearchContainer/Tabs/GroupNodeData.jsx b/src/components/SearchContainer/Tabs/GroupNodeData.jsx index a0d560f..9905768 100644 --- a/src/components/SearchContainer/Tabs/GroupNodeData.jsx +++ b/src/components/SearchContainer/Tabs/GroupNodeData.jsx @@ -107,7 +107,9 @@ export default class GroupNodeData extends Component { + click={function(){ + emitter.emit('query', "MATCH (n)-[r:MemberOf]->(m:Group {name:'{}'}) RETURN n,r,m".format(this.state.label)) + }.bind(this)} />
Unrolled Members @@ -116,7 +118,10 @@ export default class GroupNodeData extends Component { + click={function(){ + emitter.emit('query', "MATCH (n:User), (m:Group {name:'{}'}), p=allShortestPaths((n)-[:MemberOf*1..]->(m)) RETURN p".format(this.state.label), + this.state.label) + }.bind(this)} />
@@ -126,7 +131,10 @@ export default class GroupNodeData extends Component { + click={function(){ + emitter.emit('query', "MATCH (n:Group {name:'{}'})-[r:AdminTo]->(m:Computer) RETURN n,r,m".format(this.state.label), + this.state.label) + }.bind(this)} />
@@ -136,7 +144,10 @@ export default class GroupNodeData extends Component { + click={function(){ + emitter.emit('query', "MATCH (n:Group {name:'{}'}), (target:Computer), p=allShortestPaths((n)-[*]->(target)) RETURN p".format(this.state.label), + this.state.label) + }.bind(this)} />
Unrolled Member Of @@ -145,7 +156,10 @@ export default class GroupNodeData extends Component { + click={function(){ + emitter.emit('query', "MATCH (n:Group {name:'{}'}), (target:Group), p=allShortestPaths((n)-[r:MemberOf*1..]->(target)) RETURN p".format(this.state.label), + this.state.label) + }.bind(this)} />
Sessions @@ -154,7 +168,10 @@ export default class GroupNodeData extends Component { + click={function(){ + emitter.emit('query', "MATCH (n:User), (m:Group {name: '{}'}), p=allShortestPaths((n)-[r:MemberOf*1..]->(m)) WITH n,m,r MATCH (n)-[s:HasSession]-(o:Computer) RETURN m,n,r,o,s".format(this.state.label), + this.state.label) + }.bind(this)} /> diff --git a/src/components/SearchContainer/Tabs/UserNodeData.jsx b/src/components/SearchContainer/Tabs/UserNodeData.jsx index f091eb0..ed761bf 100644 --- a/src/components/SearchContainer/Tabs/UserNodeData.jsx +++ b/src/components/SearchContainer/Tabs/UserNodeData.jsx @@ -27,10 +27,6 @@ export default class UserNodeData extends Component { emitter.on('userNodeClicked', this.getNodeData.bind(this)); } - placeholder(){ - - } - getNodeData(payload){ this.setState({ label: payload, diff --git a/src/index.js b/src/index.js index 35c5589..8f932d5 100644 --- a/src/index.js +++ b/src/index.js @@ -33,6 +33,8 @@ Array.prototype.allEdgesSameType = function() { global.appStore = { startNode: null, endNode: null, + reversePath: [], + forwardPath: [], spotlightData: {}, queryStack: [], currentTooltip: null, diff --git a/src/js/bloodhound.js b/src/js/bloodhound.js index 7c32363..4b37208 100644 --- a/src/js/bloodhound.js +++ b/src/js/bloodhound.js @@ -984,7 +984,7 @@ function reversepath(nid) { tedge = pos; } }); - tedge.color = 'blue'; + tedge.color = reverse ? 'blue' : 'red'; reversePath.push(tedge); reversepath(nextnode); }); diff --git a/src/js/utils.js b/src/js/utils.js index dcdb46f..c20797b 100644 --- a/src/js/utils.js +++ b/src/js/utils.js @@ -10,14 +10,15 @@ export function buildAuthHeader(){ //Graph Utils export function setNodeData(sigmaInstance, startLabel, endLabel){ - var startNode = null; - var endNode = null; + appStore.startNode = null; + appStore.endNode = null; - startLabel = (typeof startLabel === 'undefined') ? "" : startLabel - endLabel = (typeof endLabel === 'undefined') ? "" : endLabel + startLabel = (typeof startLabel === 'undefined') ? undefined : startLabel + endLabel = (typeof endLabel === 'undefined') ? undefined : endLabel $.each(sigmaInstance.graph.nodes(), function(index, node){ node.degree = sigmaInstance.graph.degree(node.id); + node.glyphs = [] }); $.each(sigmaInstance.graph.nodes(), function(index, node){ @@ -41,10 +42,24 @@ export function setNodeData(sigmaInstance, startLabel, endLabel){ if (node.neo4j_data.name === startLabel){ appStore.startNode = node; + node.glyphs.push({ + 'position': 'bottom-right', + 'font': 'FontAwesome', + 'content': '\uF21D', + 'fillColor': '#3399FF', + 'fontScale': 1.5 + }) } if (node.neo4j_data.name === endLabel){ appStore.endNode = node; + node.glyphs.push({ + 'position': 'bottom-right', + 'font': 'FontAwesome', + 'fillColor': '#990000', + 'content': '\uF05B', + 'fontScale': 1.5 + }) } }); return sigmaInstance @@ -87,10 +102,10 @@ export function collapseEdgeNodes(sigmaInstance){ node.folded.edges.push(edge) appStore.spotlightData[anode.id] = [anode.neo4j_data.name, node.id, node.neo4j_data.name]; sigmaInstance.graph.dropNode(anode.id); - node.glyphs = [{ + node.glyphs.push({ 'position': 'bottom-left', 'content': node.folded.nodes.length - }] + }) } }); }) @@ -127,7 +142,7 @@ export function collapseSiblingNodes(sigmaInstance){ //Generate our string to compare other nodes to //by sorting the parents and turning it into a string var checkString = parents.sort().join(',') - var testString; + var testString; //Loop back over nodes in the graph and look for any nodes //with identical parents @@ -212,6 +227,29 @@ export function generateUniqueId(sigmaInstance, isNode){ return i } +export function findGraphPath(sigmaInstance, reverse, nodeid){ + var target = reverse ? appStore.startNode : appStore.endNode + + if (nodeid !== target.id){ + var edges = sigmaInstance.graph.adjacentEdges(nodeid) + var nodes = reverse ? sigmaInstance.graph.inboundNodes(nodeid) : sigmaInstance.graph.outboundNodes(nodeid) + $.each(nodes, function(index, node){ + $.each(edges, function(index, edge){ + var check = reverse ? edge.source : edge.target + if (check === node){ + edge.color = reverse ? 'blue' : 'red'; + appStore.reversePath.push(edge); + findGraphPath(sigmaInstance, reverse, node); + } + }) + }) + }else{ + sigmaInstance.refresh({'skipIndexation': true}) + } +} + + +//Utilities for generating AJAX requests export function defaultAjaxSettings(){ return { url: appStore.databaseInfo.url + '/db/data/transaction/commit',