Newer
Older
indexation / public / js / force-directed-graph.js
"use strict";

function initGraph(url, corpus) {
  var loc = window.location.pathname,
    dir = loc.substring(0, loc.lastIndexOf('/')),
    corpus = JSON.parse(corpus);

  var svg = d3.select("svg"),
    container = d3.select("#container"),
    color = d3.scaleOrdinal(d3.schemeCategory20),
    width = +container.attr("width"),
    height = +container.attr("height");

  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));

  console.log(url);

  d3.json(url, function(error, graph) {
    if (error) throw error;

    var deleted_links = {},
      selectedLinks = graph.links.filter(function(d) {
        var res = (d.value >= 3);
        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;
      });

    var edges = [],
      nodes = [];
    for (var i = 0; i < selectedNodes.length; i++) {
      nodes.push(i);
    }
    for (var i = 0; i < selectedLinks.length; i++) {
      var edge = selectedLinks[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) {
      selectedNodes[nodes[key]].group = res[key];
    }

    var link = svg.append("g")
      .attr("class", "links")
      .selectAll("line")
      .data(selectedLinks)
      .enter().append("line")
      .attr("stroke-width", function(d) {
        return d.value;
      });

    link.append("title")
      .text(function(d) {
        return d.value;
      });

    var node = svg.append("g")
      .attr("class", "nodes")
      .selectAll("circle")
      .data(selectedNodes)
      .enter().append("circle")
      .attr("r", function(d) {
        return 7;
        // return 10 * d.specificity;
      })
      .attr("fill", function(d) {
        return color(d.group);
      })
      .call(d3.drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended))
      .on("click", function(d) {
        window.open('/' + corpus.in + '/' + d.data.id + '.txt');
      })
      .on("mouseover", function(d) {
        d3.select("#subtitle")
          .style("opacity", 1)
          .text(() => {
            return d3.select(this).selectAll("title").text();
          });
        d3.select(this)
          .attr("r", 14);
      })
      .on("mouseleave", function(d) {
        d3.select("#subtitle")
          .style("opacity", 0);
        d3.select(this)
          .attr("r", 7);
      });

    node.append("title")
      .text(function(d) {
        return d.data.id;
      });

    simulation
      .nodes(selectedNodes)
      .on("tick", ticked);

    simulation.force("link")
      .links(selectedLinks);

    function ticked() {
      link
        .attr("x1", function(d) {
          return d.source.x;
        })
        .attr("y1", function(d) {
          return d.source.y;
        })
        .attr("x2", function(d) {
          return d.target.x;
        })
        .attr("y2", function(d) {
          return d.target.y;
        });

      node
        .attr("cx", function(d) {
          return d.x;
        })
        .attr("cy", function(d) {
          return d.y;
        });
    }
  });

  function dragstarted(d) {
    if (!d3.event.active) simulation.alphaTarget(0.3).restart();
    d.fx = d.x;
    d.fy = d.y;
  }

  function dragged(d) {
    d.fx = d3.event.x;
    d.fy = d3.event.y;
  }

  function dragended(d) {
    if (!d3.event.active) simulation.alphaTarget(0);
    d.fx = null;
    d.fy = null;
  }
}