Added path highlighting
parent
f7917e9a07
commit
6894e14381
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -27,10 +27,6 @@ export default class UserNodeData extends Component {
|
|||
emitter.on('userNodeClicked', this.getNodeData.bind(this));
|
||||
}
|
||||
|
||||
placeholder(){
|
||||
|
||||
}
|
||||
|
||||
getNodeData(payload){
|
||||
this.setState({
|
||||
label: payload,
|
||||
|
|
|
@ -33,6 +33,8 @@ Array.prototype.allEdgesSameType = function() {
|
|||
global.appStore = {
|
||||
startNode: null,
|
||||
endNode: null,
|
||||
reversePath: [],
|
||||
forwardPath: [],
|
||||
spotlightData: {},
|
||||
queryStack: [],
|
||||
currentTooltip: null,
|
||||
|
|
|
@ -984,7 +984,7 @@ function reversepath(nid) {
|
|||
tedge = pos;
|
||||
}
|
||||
});
|
||||
tedge.color = 'blue';
|
||||
tedge.color = reverse ? 'blue' : 'red';
|
||||
reversePath.push(tedge);
|
||||
reversepath(nextnode);
|
||||
});
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue