Ssieth / Storium Usergraph

// ==UserScript==
// @name        Storium Usergraph
// @namespace   usergraph.storium.com
// @description Graph users and games in storium
// @include     https://storium.com/user/*
// @version     1.4.0
// @require     https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js
// @require     https://cdnjs.cloudflare.com/ajax/libs/vis/4.20.0/vis.min.js
// @resource    vis_CSS  https://cdnjs.cloudflare.com/ajax/libs/vis/4.20.0/vis.min.css
// @resource	font_CSS	http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_setValue
// ==/UserScript==

var data={}; // Primary data for the graph
var network;

// Insert CSS info for the graph //
var vis_CssSrc = GM_getResourceText ("vis_CSS");
var font_CssSrc = GM_getResourceText ("font_CSS");
GM_addStyle (vis_CssSrc);
GM_addStyle (font_CssSrc);
// ----------------------- //

// Get url and user details //
var aryURL = window.location.href.split("/"); 
var user = aryURL[aryURL.length -1].trim().toLowerCase();
// ----------------------- //

function buildUserObject() {
	var objUser = {};
	var games = [];
	var gameSlugs = [];
	objUser.id = user;
	objUser.updated = new Date();
    $('table.profile-table a').each(function() {
		var href = $(this).prop("href");
		var name = $(this).text();
		if (href.indexOf("/game/") !== -1) {
			var aryGameURL = href.split("/");
			var gameSlug = aryGameURL[aryGameURL.length -1].trim().toLowerCase()
			var objGame = {};
			objGame.name = name;
			objGame.slug = gameSlug;
			objGame.url = href;
			if (gameSlugs.indexOf(objGame.slug) == -1) {
				gameSlugs.push(objGame.slug);
				games.push(objGame);
			}
		}
	});
	objUser.games = games;
	return objUser;
}

function loadData() {
    var strIn = GM_getValue("data","");
    data = {};
    if (strIn!="") {
        data = JSON.parse(strIn);
    }	
}

function saveData() {
	GM_setValue("data",JSON.stringify(data));
}

function removeUser(strUser) {
	delete data[strUser];
}

function main() {
	console.log("Start script: Storium Usergraph");
	loadData();
	switch (user) {
		case "usergraph":
			drawGraph(data);	
			break;
		case "usergraph-dot":
			drawGraph(data,"dot");
			break;
		case "cleardata":
			clearData();
			break;
		case "":
			break;
		default:
			var objUser = buildUserObject();
			data[objUser.id] = objUser;
			saveData();
			break;
	}
	console.log("End script: Storium Usergraph");
}

function clearData() {
	data = {};
	saveData();
	$('body div').remove();
	$('body').append("<div id='graphData' style='width: 100%; height: 100%; border: thin solid gray;'>Graph Data Cleared!</div>");
}

function graphRefresh() {
	drawGraph(data);
}

function setButtons() {
	console.log("Settign Buttons");
	var arySelected = network.getSelectedNodes();
	if (arySelected.length > 0 && arySelected[0].substr(0,1) == "@") {
		console.log("disab");		
		$("#deleteNode").removeAttr("disabled");  
	} else {
		console.log("enab");		
		$("#deleteNode").attr("disabled","disabled");
	}
}

function drawGraph(data, mode) {
	$('body div').remove();
	$('body').append("<div id='mynetwork' style='width: 100%; height: 100%; border: thin solid gray;'></div>");
	if (mode === undefined) {
		mode = "graph";
	}
	if (mode==="graph") {
		$('body').append("<i id='statusFlag' class='fa fa-flag' style='color: green; position: absolute; top: 0px; left: 0px;'></i>");
	}

	
	// create an array with nodes
    var nodes = [];
	var nodeNames = [];
	var nodeReserve = {};

    // create an array with edges
    var edges = [];

	for (var userID in data) {
		var objUser = data[userID];
		if (objUser.games.length > 0) {
			nodes.push({id: '@' + objUser.id, label: '@' + objUser.id, group: 'user'});
			var arrayLength = objUser.games.length;
			for (var i = 0; i < arrayLength; i++) {
				var game = objUser.games[i];
				if (nodeNames.indexOf(game.slug) == -1) {
					if (nodeReserve[game.slug] != undefined) {
						nodeNames.push(game.slug);
						nodes.push({id: game.slug, title: game.name, group: 'game'});
						edges.push(nodeReserve[game.slug]);
						edges.push({from: '@' + objUser.id, to: game.slug });
					} else {
						nodeReserve[game.slug] = {from: '@' + objUser.id, to: game.slug };
					}
				} else {
					edges.push({from: '@' + objUser.id, to: game.slug });
				}
			}
		}
	}
	
	switch (mode) {
		case "graph":
		    // Add delete buttons
			var $btnPanel = $("<div style='position: absolute; top: 5px; right:5px; border: thin solid black' id='divBtn'></div>");
			var $btnDel = $("<button id='deleteNode' disabled='disabled'>Delete</button>");
			var $btnSave = $("<button id='saveNodes'>Save</button>");
			var $btnRedraw = $("<button id='redrawNodes'>Redraw</button>");
			$btnRedraw.click(function() {
				graphRefresh();
			});
			$btnSave.click(function() {
				saveData();
				$('#statusFlag').css("color","green");
			});
			$btnDel.click(function() {
				var arySelected = network.getSelectedNodes();
				if (arySelected.length > 0 && arySelected[0].substr(0,1) == "@") {
					var strUser = arySelected[0].substr(1);
					console.log("Deleting user: " + strUser);
					$('#statusFlag').css("color","red");
					removeUser(strUser);
					network.deleteSelected();
				}
			});
			$btnPanel.append($btnDel);
			$btnPanel.append($btnSave);
			$btnPanel.append($btnRedraw);
			$("body").append($btnPanel);
			// create a network
			var container = document.getElementById('mynetwork');
			
			// provide the data in the vis format
			var dataIn = {
				nodes: new vis.DataSet(nodes),
				edges: new vis.DataSet(edges)
			};
			
			var options = {
			  groups: {
				user: {color:{background:'red'}, mass: 10, shape: 'icon', icon: {
							face: 'FontAwesome',
							code: '\uf0c0',
							color: 'green'
						}
				},
				game: {shape: "dot" }
			  },
			  "edges": {
				"smooth": {
				  "forceDirection": "none"
				}
			  },
			  "physics": {
				"barnesHut": {
					"damping": 0.45,
				  "avoidOverlap": 0.25
				},
				"minVelocity": 0.5
				},
				"layout": {"improvedLayout": false}
			}

			// initialize your network!
			network = new vis.Network(container, dataIn, options);
			network.on("selectNode", function() { setButtons() } );
			network.on("deselectNode", function() { setButtons() } );
			break;
		case "dot":
			var strDot = "";
			strDot += "graph G {\n"
			for (var i = 0; i < nodes.length; i++) {
				var objNode = nodes[i];
				strDot += "    \"" + objNode.id + "\" ["
				switch (objNode.group) {
					case "user":
						strDot += "style=filled,color=green,label=\"" + objNode.label + "\""
						break;
					case "game":
						strDot += "label=\"" + objNode.title + "\""
						break;
				}
				strDot += "];\n"			
			}
			for (var i = 0; i < edges.length; i++) {
				var objEdge = edges[i];
				strDot += "    \"" + objEdge.from + "\" -- \"" + objEdge.to + "\";\n"			
			}
			strDot += "}"

			var $pre = $("<pre id='dotCode'></pre>").html(strDot);
			$('#mynetwork').append($pre);
			break;
		default:
			
	}
}
	
main();