Skip to content

Commit

Permalink
Merge pull request #35 from diggyk/master
Browse files Browse the repository at this point in the history
Working on Fates visualizations
  • Loading branch information
gmjosack committed Sep 10, 2015
2 parents 1fc0f73 + 0d869c1 commit d7f780f
Show file tree
Hide file tree
Showing 8 changed files with 475 additions and 19 deletions.
3 changes: 2 additions & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"angular": "~1.4.5",
"angular-animate": "~1.4.5",
"angular-route": "~1.4.5",
"bootstrap": "~3.3.5"
"bootstrap": "~3.3.5",
"raphael": "raphael.js#~2.1.4"
}
}
6 changes: 3 additions & 3 deletions hermes/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -737,9 +737,9 @@ def question_the_fates(cls, session, events, quest=None):
relevant_fates.append(fate)

# And with that list of relevant Fates, we can look for
# open Labors where the Labor's EventType matches the Fate's
# creation EventType. We will collect the matching Labors into
# and array for batch achievement
# open Labors where the Labor's creation EventType matches
# the Fate's creation EventType. We will collect the matching
# Labors into and array for batch achievement
if host.id in labors_by_hostid:
for labor in labors_by_hostid[host.id]:
for fate in relevant_fates:
Expand Down
4 changes: 2 additions & 2 deletions hermes/webapp/src/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ body {
font-family: "Open Sans";
margin: 0;
padding: 0;
font-size: 2em;
font-size: 1.2em;
}

h1 {
Expand All @@ -24,7 +24,7 @@ h1 {
#header {
background-color: #007EE5;
color: #f7f9fa;
font-size: 2em;
font-size: 3em;
padding: 10px;
}

Expand Down
2 changes: 1 addition & 1 deletion hermes/webapp/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
<div id="header">Hermes</div>
<div style="padding: 10px" ng-view></div>
</div>

<script src="/vendor/angular/angular.js"></script>
<script src="/vendor/angular-route/angular-route.js"></script>
<script src="/vendor/angular-animate/angular-animate.js"></script>
<script src="/vendor/raphael/raphael.js"></script>
<script src="/js/app.js"></script>
</body>
</html>
240 changes: 237 additions & 3 deletions hermes/webapp/src/js/controllers/fateCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,243 @@
function FateCtrl(hermesService) {
var vm = this;

hermesService.getFates().then(function(fates) {
vm.fates = fates;
});
vm.paper = null;
vm.graphData = null;

vm.getGraphingData = getGraphingData;
vm.getRawFates = getRawFates;

getRawFates();
getGraphingData();


//////////////////////

function getRawFates() {
hermesService.getFates().then(function (fates) {
vm.fates = fates;
});
}

function getGraphingData() {
hermesService.getFatesSigma().then(function (data) {
vm.graphData = data;
return data;
}).then(function(graphData){
// create our canvas
vm.paper = new Raphael(document.getElementById('fatesView'));
redrawGraph();
});

function redrawGraph() {
vm.paper.clear();

// we declare our settings here so they can be changed dynamically as needed
var settings = {
'xScale': 600,
'xOffset': 100,
'yScale': 500,
'yOffset': 140,
'rootNodeStyle': {
'fill': "#000"
},
'childNodeStyle': {
'fill': "#fff",
'stroke': "#000",
'stroke-width': 4,
},
'endNodeStyle': {
'fill': "#666",
'stroke': '#000',
'stroke-width': 4,
}
};

// draw our edges
for (var idx in vm.graphData.edges) {
var edge = vm.graphData.edges[idx];

drawEdge(vm.paper, settings, edge);
}

// draw our nodes
for (var idx in vm.graphData.nodes) {
var node = vm.graphData.nodes[idx];
switch (node["type"]) {
case "rootNode":
drawRootNode(
vm.paper, settings, node
);
break;
case "childNode":
drawChildNode(
vm.paper, settings, node
);
break;
case "endNode":
drawEndNode(
vm.paper, settings, node
);
break;
}

addNodeLabel(vm.paper, settings, node);
}

vm.paper.setViewBox(0, 0, vm.paper.width, vm.paper.height, true);
}

/**
* Draws the root node on our canvas
* @param paper the Raphael instance
* @param settings the settings to use
* @param style the style to use for this node
* @param node the node to draw
*/
function drawRootNode(paper, settings, node) {

var x = node['x'] * settings['xScale'] + settings['xOffset'];
var y = node['y'] * settings['yScale'] + settings['yOffset'];

var circle = paper.circle(x, y, 8);
circle.attr({'fill': '#000'});
}

/**
* Draws the child node on our canvas
* @param paper the Raphael instance
* @param settings the settings to use
* @param style the style to use for this node
* @param node the node to draw
*/
function drawChildNode(paper, settings, node) {
var x = node['x'] * settings['xScale'] + settings['xOffset'];
var y = node['y'] * settings['yScale'] + settings['yOffset'];

var circle = paper.circle(x, y, 8);
circle.attr({'fill': '#000'});

var circle2 = paper.circle(x, y, 6);
circle2.attr({ 'fill': '#fff'});
}

/**
* Draws the end node on our canvas
* @param paper the Raphael instance
* @param settings the settings to use
* @param style the style to use for this node
* @param node the node to draw
*/
function drawEndNode(paper, settings, node) {
var x = node['x'] * settings['xScale'] + settings['xOffset'];
var y = node['y'] * settings['yScale'] + settings['yOffset'];

var circle = paper.circle(x, y, 8);
circle.attr({'fill': '#000'});

var circle2 = paper.circle(x, y, 6);
circle2.attr({ 'fill': '#fff'});

var circle3 = paper.circle(x, y, 4);
circle3.attr({'fill': '#000'});
}

/**
* Add a node label for the given now
* @param paper the Raphael instance
* @param settings the settings to use
* @param node the node to label
*/
function addNodeLabel(paper, settings, node) {
var x = node['x'] * settings['xScale'] + settings['xOffset'];
var y = node['y'] * settings['yScale'] + settings['yOffset'] - 32;
var label = paper.text(x, y, node["label"].replace(' ', '\n'));
label.attr({
'font-size': 16,
});
}

/**
* Draw an edge between two nodes
* @param paper the Raphael canvas
* @param settings our settings
* @param edge the edge we want to draw
*/
function drawEdge(paper, settings, edge) {
var node1 = getNodeById(edge['source']);
var node2 = getNodeById(edge['target']);
if (!node1 || !node2) {
return;
}

var indent = settings['xScale'] /10;
var x1 = node1['x'] * settings['xScale'] + settings['xOffset'];
var y1 = node1['y'] * settings['yScale'] + settings['yOffset'];
var x2 = node2['x'] * settings['xScale'] + settings['xOffset'];
var y2 = node2['y'] * settings['yScale'] + settings['yOffset'];

var pathStr = "M" + x1 + "," + y1
+ " C" + (x1 + indent) + "," + y1 + "," + x1 + "," + y2 + "," + (x1 + indent) + "," + y2
+ " L" + x2 + "," + y2;
console.log(pathStr);
paper.path(pathStr).attr({'stroke': '#000'});

addEdgeLabel(paper, settings, edge, (x1 + indent), y2);
}

/**
* Add a label to our edge
* @param paper the Raphael canvas
* @param settings our settings
* @param edge the edge we want to label
* @param x the base x coord of where the label goes
* @param y the base y coord of where the label goes
*/
function addEdgeLabel(paper, settings, edge, x, y) {
var labelOffsetX = settings['xScale'] / 100;
var labelOffsetY = settings['yScale'] / 100;
var maxWidth = (settings['xScale'] / 3) - (labelOffsetX * 3);

// anchor our text so it is left justified
var label = paper.text(x, y + labelOffsetY);
label.attr({
'text-anchor': 'start',
});

// do some word wrapping here by testing the bounding box
var labelWords = edge['label'].split(" ");
var wrappedText = '';
for (var idx in labelWords) {
label.attr("text", wrappedText + " " + labelWords[idx]);
if (label.getBBox().width > maxWidth) {
wrappedText += '\n' + labelWords[idx];
} else {
wrappedText += ' ' + labelWords[idx];
}
}

var bb = label.getBBox();
var h = Math.abs(bb.y2) - Math.abs(bb.y) + 1;
label.attr({
'y': bb.y + h
});
}

/**
* Find a node with a given ID
* @param id the ID to search for
* @returns {*}
*/
function getNodeById(id) {
for (var idx in vm.graphData.nodes) {
if (vm.graphData.nodes[idx]["id"] == id) {
return vm.graphData.nodes[idx];
}
}

return null;
}
}
}

angular.module('hermesApp').controller('FateCtrl', ['HermesService', FateCtrl]);
Expand Down
61 changes: 61 additions & 0 deletions hermes/webapp/src/js/directives/sigma.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
(function() {
'use strict';
angular.module('hermesApp')
.directive('sigmajs', function() {
//over-engineered random id, so that multiple instances can be put on a single page
var divId = 'sigmjs-dir-container-'+Math.floor(Math.random() * 999999999999);
return {
restrict: 'E',
template: '<div id="'+divId+'" style="width: 100%;height: 400px;"></div>',
scope: {
//@ reads the attribute value, = provides two-way binding, & works with functions
graph: '=',
width: '@',
height: '@',
relativeSizeNode: '='
},
link: function (scope, element, attrs) {
// Let's first initialize sigma:
var s = new sigma({
container: "container",
renderer: {
container: "container",
type: "canvas"
},
settings: {
defaultNodeColor: '#ec5148',
labelThreshold: 4
}
});


scope.$watch('graph', function(newVal,oldVal) {
s.graph.clear();
s.graph.read(scope.graph);
s.refresh();
if(scope.releativeSizeNode) {
//this feature needs the plugin to be added
sigma.plugins.relativeSize(s, 2);
}
});

scope.$watch('width', function(newVal,oldVal) {
console.log("graph width: "+scope.width);
element.children().css("width",scope.width);
s.refresh();
window.dispatchEvent(new Event('resize')); //hack so that it will be shown instantly
});
scope.$watch('height', function(newVal,oldVal) {
console.log("graph height: "+scope.height);
element.children().css("height",scope.height);
s.refresh();
window.dispatchEvent(new Event('resize'));//hack so that it will be shown instantly
});

element.on('$destroy', function() {
s.graph.clear();
});
}
};
});
})();

0 comments on commit d7f780f

Please sign in to comment.