"use strict"; var defaultSubtitle = d3.select(".subtitle").text(); function initGraph(url, corpus) { // VAR var loc = window.location.pathname, dir = loc.substring(0, loc.lastIndexOf('/')), corpus = JSON.parse(corpus); d3.json(url, function(error, graph) { if (error) throw error; var canvas = document.querySelector("canvas"), d3Canvas = d3.select("canvas"), color = d3.scaleOrdinal(d3.schemeCategory20), width = d3Canvas.attr("width"), height = d3Canvas.attr("height"), radius = 4, context = canvas.getContext("2d"); var simulation = d3.forceSimulation() .force("link", d3.forceLink().id(function(d) { return d.id; })) .force("charge", d3.forceManyBody()) .force("center", d3.forceCenter(width / 2, height / 2)); // FILTER & COMMUNITY var selectedData = getSelectedData(setGroup(graph), 4), selectedNode = null, nodes = selectedData.nodes, links = selectedData.links; // Set radius nodes.forEach(function(e) { e.radius = radius; return e; }); // FILL CANVAS simulation .nodes(nodes) .on("tick", draw); simulation.force("link") .links(links); // ZOOM var transform = d3.zoomIdentity; d3Canvas .call(d3.drag().subject(dragsubject) .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)) .call(d3.zoom().scaleExtent([-100, 100]).on("zoom", zoomed)) .call(draw); d3Canvas .on("click", click); function draw() { context.save(); context.clearRect(0, 0, width, height); context.translate(transform.x, transform.y); context.scale(transform.k, transform.k); // draw links context.strokeStyle = "#546e7a"; context.beginPath(); graph.links.forEach(function(d) { context.moveTo(Math.floor(d.source.x), Math.floor(d.source.y)); context.lineTo(Math.floor(d.target.x), Math.floor(d.target.y)); context.lineWidth = 1; }); context.stroke(); // draw nodes graph.nodes.forEach(function(d) { context.beginPath(); //for each node do begin path as context fill style and stroke are different. context.strokeStyle = "#fff"; context.fillStyle = color(d.group); if (d.clicked) context.rect(Math.floor(d.x - d.radius), Math.floor(d.y - d.radius), d.radius * 2, d.radius * 2); else context.rect(Math.floor(d.x - (d.radius / 2)), Math.floor(d.y - (d.radius / 2)), d.radius, d.radius); // context.arc(d.x, d.y, d.radius, 0, 2 * Math.PI); context.fill(); context.stroke(); }); context.restore(); } function click() { var position = d3.mouse(this), node = detectCollision({ 'x': transform.invertX(position[0]), 'y': transform.invertY(position[1]) }, nodes); if (selectedNode && selectedNode.id !== node.id) selectedNode.clicked = false; if (node) node.clicked = !node.clicked; // change clicked status selectedNode = node; // set current node in selectedNode showNodeInfos(selectedNode); } function dragsubject() { var node = detectCollision({ 'x': transform.invertX(d3.event.x), 'y': transform.invertY(d3.event.y) }, nodes); if (node) { node.x = transform.applyX(node.x); node.y = transform.applyY(node.y); } return node; } function dragstarted() { if (!d3.event.active) simulation.alphaTarget(0.3).restart(); d3.event.subject.fx = transform.invertX(d3.event.subject.x); d3.event.subject.fy = transform.invertY(d3.event.subject.y); } function dragged() { d3.event.subject.fx = transform.invertX(d3.event.x); d3.event.subject.fy = transform.invertY(d3.event.y); } function dragended() { if (!d3.event.active) simulation.alphaTarget(0); d3.event.subject.fx = null; d3.event.subject.fy = null; } function zoomed() { transform = d3.event.transform; draw(); } }); } function showNodeInfos(node) { if (node && node.clicked) { d3.select(".subtitle").text(node.data.id); } else { d3.select(".subtitle").text(defaultSubtitle); } } function detectCollision(source, targets) { var result = null, target, i, dx, dy; for (i = targets.length - 1; i >= 0; --i) { target = targets[i]; dx = Math.floor(source.x - target.x); dy = Math.floor(source.y - target.y); if ((dx * dx + dy * dy) < (target.radius * target.radius)) { result = target; } } return result; } // Set a group for each nodes in graph function setGroup(graph) { var edges = [], nodes = []; for (var i = 0; i < graph.nodes.length; i++) { nodes.push(i); } for (var i = 0; i < graph.links.length; i++) { var edge = graph.links[i]; edge.weight = edge.value; edges.push(edge); } // Create the "community" var community = jLouvain().nodes(nodes).edges(edges), res = community(); // Affect community for each node for (var key in res) { graph.nodes[nodes[key]].group = res[key]; } return graph; } function getSelectedData(graph, lim) { var deleted_links = {}, selectedLinks = graph.links.filter(function(d) { var res = (d.value >= lim); if (!res) { deleted_links[d.source] = deleted_links[d.source] + 1 || 1; deleted_links[d.target] = deleted_links[d.target] + 1 || 1; } return res; }), selectedNodes = graph.nodes.filter(function(d) { d.value = d.value - (deleted_links[d.id] || 0); var res = (d.value > 0); return res; }); return { 'links': selectedLinks, 'nodes': selectedNodes }; }