-
Notifications
You must be signed in to change notification settings - Fork 216
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
309 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,46 @@ | ||
# Viaz: graph visualization with D3.js | ||
# Graphexp: graph explorer with D3.js | ||
|
||
The HTML files contains Javascript code to visualize a graph together with meta-data associated to the nodes. The program uses: | ||
* the D3.js library to visualize a graph in an interactive manner | ||
* an ajax request (with Jquery) that query a graph database (Gremin Tinkerpop) | ||
Graphexp is a javascript interface to explore and display a graph stored in the Gremlin graphdatabase via the Gremlin server. Graphexp is under the Apache 2.0 licence. | ||
|
||
## Configuration | ||
|
||
## D3.js Resources | ||
To use graph Explorer, you need a [Gremlin server](http://tinkerpop.apache.org/) running with REST protocol and a *recent* web browser to display the visualization. | ||
On your web browser, just access the file `graphexp.html`. | ||
|
||
* [API Reference](https://github.com/d3/d3/blob/master/API.md) | ||
* [Release Notes](https://github.com/d3/d3/releases) | ||
* [Gallery](https://github.com/d3/d3/wiki/Gallery) | ||
* [Examples](http://bl.ocks.org/mbostock) | ||
* [Wiki](https://github.com/d3/d3/wiki) | ||
If the access to the Gremlin server is not `localhost:8182`, the address can be configured in `graphConf.js`. | ||
|
||
## Font Awesome Resources | ||
## Getting started | ||
|
||
If you do not have your own Gremlin server, you may use a docker container with a server ready to use. | ||
|
||
To display a node, type in a property name and value, then click on the search button. | ||
Leaving a blank field and keyword will display the full graph. | ||
The node and edge properties can be automatically retrieved using the `get graph info` button. Pushing this button will also display some graph properties on the left side of the page. | ||
|
||
When a node of the visualization is clicked, it will become 'active' with a circle surround it and its information will be display on the right side of the page. Moreover, this action will trigger the display of its neighbors. | ||
Clicking on an edge will show its properties (without highlighting the edge). | ||
|
||
When appearing for the first time the nodes will be positioned following a force layout. Drag and drop can be used to pin them in a particular position. Once dragged the nodes will stay at their position. Drag and drop is allowed only for the nodes on the active layer (most recent layer) with no connection with nodes in other layers. See "Visualization concepts" section for more information on the layers. | ||
|
||
## Visualization concept | ||
|
||
The visualization is based on a concept of layers of visualisation. The idea is to progress in the graph as in a jungle. The clicked node will show its neighbors, opening new paths for the exploration. If not clicked, the other displayed nodes will vanish little by little as we progress in the exploration. Coming back in the exploration paths allowed. Before it completely disappears, a node can be clicked and it will become active again. As in a jungle, you can not see the full jungle and there are so many things that you must focus on your direction and what is in front of you if you do not want to get lost. | ||
|
||
During your exploration you can set up milestones by clicking on the small circle on the upper right side of a node. This will pin the node in time, preventing it to disappear. | ||
|
||
You may also freeze the exploration, by ticking the appropriate checkbox. The evolution of the exploration will stop, allowing to gather information on the nodes displayed, without displaying their neighbors. | ||
|
||
## Node and edge information | ||
|
||
The Id and label of each node can be displayed by hovering the cursor over the node. The full information on the properties are displayed on the right of the page when clicking on the node or edges. Once the `get graph info` button has been clicked, a choice of properties to display appear on the left side. | ||
|
||
## Node color | ||
|
||
If a node property called 'color' exists in the node properties with an hexadecimal color code (string), it will be displayed automatically on the graph. Otherwise, the default node color can be set in the `graphConf.js` file. The node color can be set interactively after the `get graph info` button has been pressed. A select tab appears on the left side bar allowing to set the color according to one of the property values present in the graph. | ||
|
||
## Program description | ||
|
||
The program uses: | ||
* the D3.js library to visualize a graph in an interactive manner, [API Reference](https://github.com/d3/d3/blob/master/API.md), | ||
* an ajax request (with Jquery) that query the graph database (Gremlin Tinkerpop via REST). | ||
|
||
* [List of symbols](http://fontawesome.io/cheatsheet/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,269 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
<title>Graphexp, graph explorer</title> | ||
<head> | ||
<link rel="stylesheet" href="css/graphStyle.css"> | ||
<link rel="stylesheet" href="css/styles.css"> | ||
<!--<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"> | ||
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>--> | ||
<link rel="stylesheet" href="font-awesome-4.7.0/css/font-awesome.min.css"> | ||
<!--<script src="jquery-1.11.3.min.js"></script>--> | ||
<script src="jquery-3.2.1.min.js"></script> | ||
<!-- <link rel="stylesheet" href="68eddd94.main.css">--> | ||
|
||
<!--<script src="http://d3js.org/d3.v3.min.js"></script>--> | ||
<script src="d3/d3.min.js"></script> | ||
<script src="graphConf.js"></script> | ||
<script src="graphShapes.js"></script> | ||
<script src="infobox.js"></script> | ||
<script src="graph_viz.js"></script> | ||
<script src="graphioGremlin.js"></script> | ||
|
||
<script type="text/javascript"> | ||
|
||
/////////////////////////////////////////////// | ||
function search_query(){ | ||
//if (typeof graph_viz.simulation!=='undefined') {graph_viz.simulation.stop(); console.log('Simulation stopped!');} | ||
graphioGremlin.search_query(); | ||
} | ||
|
||
function get_graph_info(){ | ||
graphioGremlin.get_graph_info(); | ||
} | ||
</script> | ||
<!-- ------------------------------------------------- --> | ||
|
||
|
||
|
||
</head> | ||
<body> | ||
<div class="header"> | ||
<div class="container"> | ||
<h1 class="header-heading">Graph Explorer v 0.4</h1> | ||
</div> | ||
</div> | ||
<div class="nav-bar"> | ||
<div class="container" id="nav_bar"> | ||
<ul class="nav"> | ||
<li> | ||
Enter a field: <span id="prop_choice"><input name="search_field" id="search_field" value="" /></span> | ||
</li> | ||
<li> | ||
Enter a Keyword/value: <input name="search_value" id="search_value" value="" /> | ||
</li> | ||
<li><button name="search query" onclick="search_query();">Search</button></li> | ||
<li><button name="clear" onclick="graph_viz.clear();">Clear</button></li> | ||
<li><input type="checkbox" name="Freeze" id="freeze-in" />Freeze exploration</li> | ||
<li> | ||
<input type="checkbox" name="showName_box" id="showName" onclick="graphShapes.show_names()"/>Show labels | ||
</li> | ||
<li><input type="number" id="nbLayers" min="1" max="128" onclick="set_nb_layers()"> Nb of layers. | ||
</li> | ||
</ul> | ||
</div> | ||
</div> | ||
<div class="content"> | ||
<div class="main" id="main"> | ||
<svg></svg> | ||
</div> | ||
|
||
<div class="aside left_bar" style="background-color:transparent;pointer-events:none;"> | ||
<div id="graphInfoBar" style="background-color:transparent;pointer-events:auto;"> | ||
<button name="graphInfo" onclick="get_graph_info();">Get graph info</button> | ||
</div> | ||
<div id="graphInfo" style="background-color:transparent;pointer-events:none;"> | ||
</div> | ||
</div> | ||
|
||
<div class="aside right_bar" id="details" style="background-color:transparent;pointer-events:none;"> | ||
<div id="messageArea"></div><div id="outputArea"></div> | ||
<div id="nodeInfo" style="background-color:transparent;pointer-events:none;"> | ||
</div> | ||
</div> | ||
<!-- | ||
<div class="aside" id="ImageInfo" style="background-color:transparent;"> | ||
<center><svg width="100" height="100"></svg></center> | ||
</div> | ||
--> | ||
</div> | ||
<div class="footer"> | ||
<div class="container"> | ||
<a href="http://www.github.com/bricaud/graphexp">About</a> | ||
</div> | ||
</div> | ||
<!-- INITIALIZATION --> | ||
<script type="text/javascript"> | ||
|
||
init_property_bar(); | ||
// Create the graph canvas in the chosen div element | ||
graph_viz.init("#main"); | ||
// Add the zoom layer to the graph | ||
//var svg_graph = | ||
graph_viz.addzoom(); | ||
//graph_viz.layers.set_nb_layers(4); | ||
|
||
// Create the info box for node details | ||
infobox.create("#graphInfo","#nodeInfo"); // from module in infobox.js | ||
|
||
//console.log(graph_viz.graph_events.ev); | ||
//graph_viz.graph_events.test(); | ||
|
||
|
||
function init_property_bar(){ | ||
document.getElementById('nbLayers').value = default_nb_of_layers; | ||
} | ||
|
||
function change_nav_bar(node_data,edge_data){ | ||
var nav_bar = d3.select("#prop_choice"); | ||
nav_bar.select("input").remove(); | ||
//nav_choices = nav_bar.append("ul"); | ||
//nav_choices.append("li").append("button").attr("onclick",search_query).text("Search") | ||
var select = d3.select('#prop_choice') | ||
.append('select').attr('class','select').attr('id','search_field') | ||
|
||
var select_node = select.append('optgroup').attr('label','Nodes') | ||
//.on('change',onchange) | ||
|
||
var select_edge = select.append('optgroup').attr('label','Edges') | ||
|
||
var node_options = select_node | ||
.selectAll('option') | ||
.data(node_data).enter() | ||
.append('option') | ||
.text(function (d) { return d; }); | ||
|
||
var edge_options = select_edge | ||
.selectAll('option') | ||
.data(edge_data).enter() | ||
.append('option') | ||
.text(function (d) { return d; }); | ||
|
||
} | ||
|
||
function display_properties_bar(prop_list,item,text){ | ||
var nav_bar = d3.select("#graphInfoBar"); | ||
var property_bar = nav_bar.append("div").attr("id","property_bar_"+item); | ||
property_bar.append('text').text(text).style("font-weight","bold"); | ||
//d3.select('#property_bar').append('text').text('hello') | ||
var property_label = property_bar.selectAll('input').append("ul") | ||
.data(prop_list).enter().append("li"); | ||
//.append('label'); | ||
|
||
|
||
property_label.append('input').attr('type','checkbox').attr('id',function (d) { return item+"_"+d; }) | ||
.attr('id_nb',function (d) { return prop_list.indexOf(d); }) | ||
//.attr('onchange',function(d){display_prop(d);}); | ||
.attr('onchange','display_prop(this)'); | ||
|
||
property_label.append('label').text(function (d) { return d; }); | ||
|
||
|
||
} | ||
|
||
function display_color_choice(prop_list,item,text){ | ||
prop_list = ['none','label'].concat(prop_list); | ||
var nav_bar = d3.select("#graphInfoBar"); | ||
var color_bar = nav_bar.append("div").attr("id","color_choice_"+item); | ||
color_bar.append("text").text(text).style("font-weight","bold"); | ||
color_bar.append("select").attr("class","select").attr("id","color_select_"+item) | ||
.attr("onchange","colorize(this)") | ||
.selectAll("option") | ||
.data(prop_list).enter() | ||
.append("option") | ||
.text(function (d) { return d; }); | ||
} | ||
|
||
function colorize(selection){ | ||
var value = selection.value; | ||
console.log(value); | ||
graphShapes.colorize(value); | ||
|
||
} | ||
|
||
function display_prop(prop){ | ||
var prop_id = prop.id; | ||
var prop_id_nb = prop.getAttribute('id_nb'); | ||
var text_base_offset = 10; | ||
var text_offset = 10; | ||
var prop_name = prop_id.slice(prop_id.indexOf("_")+1); | ||
var item = prop_id.slice(0,prop_id.indexOf("_")); | ||
if(d3.select("#"+prop_id).property("checked")){ | ||
if (item=='nodes'){ | ||
var elements_text = d3.selectAll('.node'); | ||
} | ||
else if (item=='edges'){ | ||
var elements_text = d3.selectAll('.edgelabel'); | ||
} | ||
attach_property(elements_text,prop_name,prop_id_nb,item) | ||
} | ||
else{ | ||
if (item=='nodes'){ | ||
d3.selectAll('.node').select('.'+prop_id).remove(); | ||
} | ||
else if (item=='edges'){ | ||
d3.selectAll('.edgelabel').select('.'+prop_id).remove(); | ||
} | ||
|
||
} | ||
} | ||
|
||
|
||
function attach_property(graph_objects,prop_name,prop_id_nb,item){ | ||
var text_base_offset = 10; | ||
var text_offset = 10; | ||
var prop_id = item+"_"+prop_name; | ||
if (item=='nodes'){ | ||
elements_text = graph_objects.append("text").style("pointer-events", "none"); | ||
} | ||
else if (item=='edges'){ | ||
var elements_text = graph_objects.append("textPath") | ||
.attr('class','edge_text') | ||
.attr('href', function (d, i) {return '#edgepath' + d.id}) | ||
.style("text-anchor", "middle") | ||
.style("pointer-events", "none") | ||
.attr("startOffset", "70%"); | ||
//.text(function (d) {return d.label}); | ||
prop_id_nb = prop_id_nb + 1; | ||
} | ||
else { console.log('Bad item name.'); return 1;} | ||
elements_text.classed("prop_details",true).classed(prop_id,true) | ||
//.attr("x", 12) | ||
.attr("dy",function(d){return graphShapes.node_size(d)+text_base_offset+text_offset*parseInt(prop_id_nb);}) | ||
//.attr("y", ".31em") | ||
.text(function(d){return get_prop_value(d,prop_name,item);}); | ||
} | ||
|
||
|
||
function get_prop_value(d,prop_name,item){ | ||
if (prop_name in d.properties){ | ||
if (item=='nodes'){ | ||
return d.properties[prop_name][0].value; | ||
} | ||
else if (item=='edges'){ | ||
console.log(d.properties[prop_name]) | ||
return d.properties[prop_name]; | ||
} | ||
} | ||
else { | ||
return ""; | ||
} | ||
} | ||
|
||
function set_nb_layers(){ | ||
var nb_layers = parseInt(document.getElementById('nbLayers').value); | ||
//var nb_layers = parseInt(layer_input.getAttribute("value")); | ||
console.log(nb_layers) | ||
graph_viz.layers.set_nb_layers(nb_layers); | ||
|
||
} | ||
|
||
|
||
|
||
|
||
</script> | ||
|
||
</body> | ||
</html> |