MediaWiki:Network-graph.js
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
var Ctrl = { baseUrl: '/sudepwiki/site-links', // Where to find external files related to the network graph canvas: { width: 500, // pixels height: 500, // pixels depth: 7, // levels to show (1 - 9) }, style: { strokeWidth: 2, strokeColor: [ 'red', // level 0 'orange', // level 1 ... 'yellow', 'green', 'blue', 'purple', '#880000', '#008800', '#000088', '#888800', // level 9 ], fillColor: [ 'purple', // level 0 'blue', // level 1 ... 'green', 'yellow', 'orange', 'red', '#FFFF00', '#FF00FF', '#0000FF', '#00FF00', // level 9 ], }, physical: { charge: -10, linkDistance: 10, distance: 120, gravity: .01, }, circle: { radius: 6, strokeWidth: 2, // 0 = no stroke }, arrow: { size: 6, strokeWidth: 1, // 0 = no arrow }, svg: null, nodes: null, links: null, force: null, } String.prototype.toTitleCase = function() { return this.replace( /\w\S*/g, function(txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); } ); } function getQuery(name) { // e.g., https://devapps.pathology.jhu.edu/sudepwiki/index.php/Excess_mortality_and_sudden_unexpected_death_in_epilepsy var url = $(location).attr('href').split('/'); var title = url[url.length - 1]; return title; } function tickHandler() { Ctrl.links .attr('x1', function(link) { return link.source.x; }) .attr('y1', function(link) { return link.source.y; }) .attr('x2', function(link) { return link.target.x; }) .attr('y2', function(link) { return link.target.y; }); Ctrl.nodes.attr('transform', function(node) { return 'translate(' + node.x + ',' + node.y + ')'; }); } function centerNode(node, index) { // Translate the graph to center around the selected node. // node - the clicked node // index - the index of the clicked node in Ctrl.nodes[] for(var i = 0; i < Ctrl.nodes[0].length; i++) { if (i != index) { Ctrl.nodes[0][i].fixed = false; Ctrl.nodes[0][i].cx = 0; Ctrl.nodes[0][i].cy = 0; } else { Ctrl.nodes[0][i].fixed = true; Ctrl.nodes[0][i].cx = Math.floor(Ctrl.canvas.width / 2); Ctrl.nodes[0][i].cy = Math.floor(Ctrl.canvas.height / 2); } } tickHandler(); }; function main() { var title = getQuery('title'); // Create the canvas Ctrl.svg = d3.select('#network-graph') .append('svg') .attr('width', Ctrl.canvas.width) .attr('height', Ctrl.canvas.height); // Define the arrow head for (var level = 0; level < 10; level++ ) { let fullSize = Ctrl.arrow.size; let halfSize = Math.floor(fullSize / 2); Ctrl.svg.append('defs').selectAll('marker') .data(['arrow' + level]) .enter() .append('marker') .attr('id', function(node, index) { return node; }) .attr('viewBox', '0 -' + halfSize + ' ' + fullSize + ' ' + fullSize) .attr('refX', Ctrl.circle.radius / 2 + Ctrl.arrow.size + Ctrl.circle.strokeWidth / 4) .attr('refY', 0) .attr('markerWidth', fullSize) .attr('markerHeight', fullSize) .attr('orient', 'auto') .append('path') .attr('d', 'M0,-' + halfSize + 'L' + fullSize + ',0L0,' + halfSize + 'L' + fullSize + ',0L0,-' + halfSize) .style('stroke', Ctrl.style.strokeColor[level]) .style('stroke-width', Ctrl.arrow.strokeWidth) .style('opacity', '0.6'); } // Define the characteristics of the force simulation Ctrl.force = d3.layout.force() .size([Ctrl.canvas.width, Ctrl.canvas.height]) .charge(Ctrl.physical.charge) .linkDistance(Ctrl.physical.linkDistance) .distance(Ctrl.physical.distance) .gravity(Ctrl.physical.gravity); // Read the data and use it to build the graph var url = Ctrl.baseUrl + '/network-graph.php?depth=' + Ctrl.canvas.depth + '&title=' + title; d3.json(url, function(json) { // Introduce the data to the force simulation Ctrl.force .nodes(json.nodes) .links(json.links); // Add the links (lines and arrows) Ctrl.links = Ctrl.svg .selectAll('.link') .data(json.links) .enter() .append('line') .attr('class', 'link') .style('stroke', function(node, index) { return Ctrl.style.strokeColor[node.level]; }) .style('stroke-width', Ctrl.style.strokeWidth) .style('marker-end', function(node, index) { return 'url(#arrow' + node.level + ')'; }); // Add the nodes Ctrl.nodes = Ctrl.svg .selectAll('.node') .data(json.nodes) .enter() .append('g') .attr('class', 'node') .on('dblclick', centerNode) .append('circle') .attr('r', Ctrl.circle.radius) .style('stroke', function(node, index) { return Ctrl.style.strokeColor[node.level]; }) .style('stroke-width', Ctrl.circle.strokeWidth) .style('fill', function(node, index) { return Ctrl.style.fillColor[node.level]; }) .call(Ctrl.force.drag); // Add text to each node // Ctrl.nodes // .append('text') // .attr('dx', 12) // .attr('dy', '.35em') // .text(function(node, index) { return index; }); // was node.name, which is the title of the article // Add a title to each node Ctrl.nodes .append('title') .data(json.nodes) .text(function(node, index) { return node.name.replace(/_/g, ' ').toTitleCase(); }); Ctrl.svg.append('polyline') .style('stroke', 'black') .style('fill', 'none') .attr('points', '1,1,' + + Ctrl.canvas.width + ',1,' + Ctrl.canvas.width + ',' + Ctrl.canvas.height + ',' + '1,' + Ctrl.canvas.height ); // Set up the tick handler Ctrl.force.on('tick', function() { tickHandler(); }); // Start the force simulation Ctrl.force.start(); }); } $(document).ready(function() { main(); });