Added path highlighting

master
Rohan Vazarkar 2016-07-27 11:01:19 -04:00
parent f7917e9a07
commit 6894e14381
6 changed files with 108 additions and 25 deletions

View File

@ -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,

View File

@ -107,7 +107,9 @@ export default class GroupNodeData extends Component {
<NodeALink
ready={this.state.directMembers !== -1}
value={this.state.directMembers}
click={this.placeholder} />
click={function(){
emitter.emit('query', "MATCH (n)-[r:MemberOf]->(m:Group {name:'{}'}) RETURN n,r,m".format(this.state.label))
}.bind(this)} />
</dd>
<dt>
Unrolled Members
@ -116,7 +118,10 @@ export default class GroupNodeData extends Component {
<NodeALink
ready={this.state.unrolledMembers !== -1}
value={this.state.unrolledMembers}
click={this.placeholder} />
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)} />
</dd>
<br />
<dt>
@ -126,7 +131,10 @@ export default class GroupNodeData extends Component {
<NodeALink
ready={this.state.directAdminTo !== -1}
value={this.state.directAdminTo}
click={this.placeholder} />
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)} />
</dd>
<br />
<dt>
@ -136,7 +144,10 @@ export default class GroupNodeData extends Component {
<NodeALink
ready={this.state.derivativeAdminTo !== -1}
value={this.state.derivativeAdminTo}
click={this.placeholder} />
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)} />
</dd>
<dt>
Unrolled Member Of
@ -145,7 +156,10 @@ export default class GroupNodeData extends Component {
<NodeALink
ready={this.state.unrolledMemberOf !== -1}
value={this.state.unrolledMemberOf}
click={this.placeholder} />
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)} />
</dd>
<dt>
Sessions
@ -154,7 +168,10 @@ export default class GroupNodeData extends Component {
<NodeALink
ready={this.state.sessions !== -1}
value={this.state.sessions}
click={this.placeholder} />
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)} />
</dd>
</dl>
</div>

View File

@ -27,10 +27,6 @@ export default class UserNodeData extends Component {
emitter.on('userNodeClicked', this.getNodeData.bind(this));
}
placeholder(){
}
getNodeData(payload){
this.setState({
label: payload,

View File

@ -33,6 +33,8 @@ Array.prototype.allEdgesSameType = function() {
global.appStore = {
startNode: null,
endNode: null,
reversePath: [],
forwardPath: [],
spotlightData: {},
queryStack: [],
currentTooltip: null,

View File

@ -984,7 +984,7 @@ function reversepath(nid) {
tedge = pos;
}
});
tedge.color = 'blue';
tedge.color = reverse ? 'blue' : 'red';
reversePath.push(tedge);
reversepath(nextnode);
});

View File

@ -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',