var app = app || {}; app.imageProperties = { baseSize: 256, scale: 1 / 4, rootScale: 1.5, focusScale: 2.5, transitionSpeed: 500 } var sampleNetwork = { "buildfarm": { "attr": { "Name": "", "Address": "", "Type": "server", "Services": "standard", "Description": "Created by super-joe.", "db.replication": "readonly", "lbr.replication": "readonly", "monitor": "1", "P4LOG": "./buildfarmLOGS/buildfarmLog.txt", "P4TARGET": "localhost:1666", "rpl.forward.all": "1", "server": "4", "serviceUser": "service3", "startup.1": "pull -i 1", "startup.2": "pull -u -i 1", "startup.3": "pull -u -i 1" } }, "master": { "attr": { "Name": "", "Address": "", "Type": "server", "Services": "standard", "Description": "Created by jrobinson.", "monitor": "2", "P4PORT": "localhost:1666", "master": true } }, "proxy1": { "attr": { "Name": "", "Address": "", "Type": "server", "Services": "standard", "Description": "Created by jrobinson.", "P4TARGET": "localhost:1666" } }, "replica1": { "attr": { "Name": "replica1", "Address": "localhost:2345", "Type": "server", "Services": "replica", "Description": "Created by jrobinson.", "db.replication": "readonly", "lbr.replication": "readonly", "monitor": "1", "P4LOG": "./replica1/replica1Log.txt", "P4NAME": "replica1", "P4TARGET": "localhost:1666", "P4TICKETS": "./replica1TICKETS/.p4tickets", "server": "1", "serviceUser": "service1", "startup.1": "pull -i 1", "startup.2": "pull -u -i 1", "startup.3": "pull -u -i 1" } }, "replica2": { "attr": { "Name": "replica2", "Address": "localhost:2347", "Type": "server", "Services": "forwarding-replica", "Description": "Created by jrobinson.", "db.replication": "readonly", "lbr.replication": "readonly", "monitor": "2", "P4LOG": "./replica2LOGS/replica2Log.txt", "P4NAME": "replica2", "P4TARGET": "localhost:1666", "P4TICKETS": "./replica2TICKETS/.p4tickets", "rpl.forward.all": "1", "server": "3", "serviceUser": "service2", "startup.1": "pull -i 1 -Preplica2", "startup.2": "pull -u -i 1", "startup.3": "pull -u -i 1", "startup.4": "pull -u -i 1" } }, "replica3": { "attr": { "Name": "replica3", "Address": "localhost:2350", "Type": "server", "Services": "forwarding-replica", "Description": "Created by jrobinson.", "db.replication": "readonly", "lbr.replication": "readonly", "monitor": "2", "P4LOG": "./replica3LOGS/replica3Log.txt", "P4NAME": "replica3", "P4TARGET": "localhost:2347", "P4TICKETS": "./replica3TICKETS/.p4tickets", "rpl.forward.all": "1", "server": "5", "serviceUser": "service5", "startup.1": "pull -i 1 -Preplica3", "startup.2": "pull -u -i 1", "startup.3": "pull -u -i 1", "startup.4": "pull -u -i 1" } }, "replica4": { "attr": { "Name": "replica4", "Address": "localhost:2351", "Type": "server", "Services": "forwarding-replica", "Description": "Created by jrobinson.", "db.replication": "readonly", "lbr.replication": "readonly", "monitor": "2", "P4LOG": "./replica4LOGS/replica4Log.txt", "P4NAME": "replica4", "P4TARGET": "localhost:1666", "P4TICKETS": "./replica4TICKETS/.p4tickets", "rpl.forward.all": "1", "server": "6", "serviceUser": "service6", "startup.1": "pull -i 1 -Preplica4", "startup.2": "pull -u -i 1", "startup.3": "pull -u -i 1", "startup.4": "pull -u -i 1" } }, "replica6": { "attr": { "Name": "replica6", "Address": "localhost:2352", "Type": "server", "Services": "forwarding-replica", "Description": "Created by jrobinson.", "db.replication": "readonly", "lbr.replication": "readonly", "monitor": "2", "P4LOG": "./replica6LOGS/replica6Log.txt", "P4NAME": "replica6", "P4TARGET": "localhost:2347", "P4TICKETS": "./replica6TICKETS/.p4tickets", "rpl.forward.all": "1", "server": "7", "serviceUser": "service7", "startup.1": "pull -i 1 -Preplica6", "startup.2": "pull -u -i 1", "startup.3": "pull -u -i 1", "startup.4": "pull -u -i 1" } }, "replica7": { "attr": { "Name": "replica7", "Address": "localhost:2353", "Type": "server", "Services": "forwarding-replica", "Description": "Created by jrobinson.", "db.replication": "readonly", "lbr.replication": "readonly", "monitor": "2", "P4LOG": "./replica7LOGS/replica7Log.txt", "P4NAME": "replica7", "P4TARGET": "localhost:2352", "P4TICKETS": "./replica7TICKETS/.p4tickets", "rpl.forward.all": "1", "server": "7", "serviceUser": "service8", "startup.1": "pull -i 1 -Preplica7", "startup.2": "pull -u -i 1", "startup.3": "pull -u -i 1", "startup.4": "pull -u -i 1" } }, "replica8": { "attr": { "Name": "replica8", "Address": "localhost:2360", "P4TARGET": "localhost:2353" } }, "replica9": { "attr": { "Name": "replica9", "Address": "localhost:2361", "P4TARGET": "localhost:2360" } }, "replica10": { "attr": { "Name": "replica10", "Address": "localhost:2362", "P4TARGET": "localhost:2361" } }, "replica11": { "attr": { "Name": "replica11", "Address": "localhost:2363", "P4TARGET": "localhost:2361" } }, "replica12": { "attr": { "Name": "replica12", "Address": "localhost:2364", "P4TARGET": "localhost:2361" } }, "replica13": { "attr": { "Name": "replica13", "Address": "localhost:2365", "P4TARGET": "localhost:2361" } }, "replica14": { "attr": { "Name": "replica14", "Address": "localhost:2366", "P4TARGET": "localhost:2364" } } } function Node(name, children){ this.name = name; this.children = []; for(child = 0; child < children.length; child++){ this.children.push(children[child]); } } function makeTree(data){ var data = (data ? data : app.WatcherView.model.attributes); var newTree = new Node("", []), orphans = []; for(server in data){ // Define root node if none has been found. if(data[server].attr.hasOwnProperty('master') && newTree.name == ""){ newTree.name = server; } // Else, push to orphans[]. else{ orphans.push(server); } } while(orphans.length > 0){ for(index = 0; index < orphans.length; index++){ var orphan = orphans[index]; /* Search model for parent node. * - Examines every server object in data * - Breaks loop once parent is found */ for(server in data){ if(data[server].attr.Address == data[orphan].attr.P4TARGET || data[server].attr.P4PORT == data[orphan].attr.P4TARGET ){ var parent = findParent(newTree, server); if(parent != null){ var newNode = new Node(orphan, []); parent.children.push(newNode); orphans.splice(orphans.indexOf(orphan), 1); } break; } } } } return newTree; } function findParent(tree, target){ // Initialize queue. var queue = []; queue.push(tree); while(queue.length > 0){ // Dequeue first node. var currentNode = queue.shift(); // If node matches, return node. if(currentNode.name == target){ return currentNode; } // Enqueue all children. for(index = 0; index < currentNode.children.length; index++){ queue.push(currentNode.children[index]); } } // Return null if no match is found. return null; } function draw(){ $("#canvas").html(''); // Reset canvas (removes previous image). var root = makeTree(); // var root = makeTree(sampleNetwork); // TEST CASE /* * UPDATE IMAGE PROPERTIES HERE * -scale, depth, etc */ var image = app.imageProperties; var maxDepth = 3.3; var tree = d3.layout.tree() .size([$('#canvas').width() / maxDepth, $('#canvas').width() / maxDepth]) .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; }); var svg = d3.select("#canvas").append("svg") .attr("width", $("#canvas").width()) .attr("height", $("#canvas").height()) .attr('viewBox', '0, 0, ' + $("#canvas").width() + ', ' + $("#canvas").height()) .attr('preserveAspectRatio', 'xMidYMid meet') .append("g") .attr("transform", "translate(" + $('#canvas').width() / 2 + "," + $('#canvas').height() / 2 + ")"); var diagonal = d3.svg.diagonal.radial() .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; }); var nodes = tree.nodes(root), links = tree.links(nodes); var link = svg.selectAll(".link") .data(links) .enter().append("path") .attr("class", "link") .attr("d", diagonal); var node = svg.selectAll(".node") .data(nodes) .enter().append("g") .attr("class", "node") .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + (d.y) + ")rotate(" + (90 - d.x) + ")"; }); node.append("svg:image") .attr("xlink:href", './images/databaseIcon1.png') .attr("x", function(d){ return -1 * ((image.baseSize * image.scale * (d.depth == 0 ? image.rootScale : 1)) / 2)}) .attr("y", function(d){ return -1 * ((image.baseSize * image.scale * (d.depth == 0 ? image.rootScale : 1)) / 2)}) .attr("width", function(d){ return image.baseSize * image.scale * (d.depth == 0 ? image.rootScale : 1)}) .attr("height", function(d){ return image.baseSize * image.scale * (d.depth == 0 ? image.rootScale : 1)}) .on("mouseover", function(d){ $(this).css('cursor', 'pointer'); d3.select(this) .transition().duration(image.transitionSpeed) .attr("x", -1 * ((image.baseSize * image.scale * image.focusScale) / 2)) .attr("y", -1 * ((image.baseSize * image.scale * image.focusScale) / 2)) .attr("width", image.baseSize * image.scale * image.focusScale) .attr("height", image.baseSize * image.scale * image.focusScale); d3.select(this.parentNode).select("text") .transition().duration(image.transitionSpeed) .attr("transform", function(d) { return "translate(0, " + (((image.baseSize * image.scale * (d.depth == 0 ? image.rootScale : 1)) / 2) + ((image.baseSize * image.scale * image.focusScale) / 4)) + ")" }) .style("font-size", "20px"); }) .on("mouseout", function(d){ d3.select(this) .transition().duration(image.transitionSpeed) .attr("x", -1 * ((image.baseSize * image.scale * (d.depth == 0 ? image.rootScale : 1)) / 2)) .attr("y", -1 * ((image.baseSize * image.scale * (d.depth == 0 ? image.rootScale : 1)) / 2)) .attr("width", image.baseSize * image.scale * (d.depth == 0 ? image.rootScale : 1)) .attr("height", image.baseSize * image.scale * (d.depth == 0 ? image.rootScale : 1)) d3.select(this.parentNode).select("text") .transition().duration(image.transitionSpeed) .attr("transform", function(d) { return "translate(0, " + (((image.baseSize * image.scale * (d.depth == 0 ? image.rootScale : 1)) / 2)) + ")" }) .style("font-size", "14px"); }) .on("click", function(d){ $(this).css('cursor', 'default'); showServerModal(d); }); node.append("text") .attr("dy", ".5em") .attr("text-anchor", "middle") .attr("transform", function(d) { return "translate(0, " + ((image.baseSize * image.scale * (d.depth == 0 ? image.rootScale : 1)) / 2) + ")" }) .style("fill", "rgb(200, 200, 200)") .style("font-size", "14px") .text(function(d) { return d.name; }); } function showServerModal(d){ var data = app.WatcherView.model.attributes[d.name].attr; $('#serverModalTitle').html(d.name); $('#serverModalImage').html(""); // console.log(d.select("image")); for(attribute in data){ $('#serverModalTable').find('tbody').append('<tr><td>' + attribute + '</td><td>' + data[attribute] + '</td></tr>'); }; $('#serverModal').modal('show'); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 8378 | Joe Robinson |
- Server modal working. - Simplified backbone data fetching. - Log out of perforce now and not just empty session. - TODO: - Prettier/different icons for each server type. - Modal image and parent/child list. |
||
#1 | 8373 | Joe Robinson |
- Moved to d3 to handle image drawing (SVG). - Proper sessions (logging in/out) implemented. - TODO: Fix server modal style/formatting & populate with data. |