Multiple Links Between Two Nodes in D3.js Force Directed Layout

A simple way to handle if there are multiple links between to nodes in the force directed layout implemented in D3.js.

by HUAN ZHANG

HTML

<script type="text/javascript" src="http://d3js.org/d3.v2.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
<div id="graphContainer" class="graphContainer">
</div>

CSS

path.link {
    fill: none;
    stroke: #666;
    stroke-width: 1.5px;
}	

circle {
    fill: #ccc;
    stroke: #333;
    stroke-width: 1.5px;
}

text {
    font: 10px sans-serif;
    pointer-events: none;
}

text.shadow {
    stroke: #fff;
    stroke-width: 3px;
    stroke-opacity: .8;
}

body {
    background-color: white;
    margin: 0px;
}

.graphContainer {
    text-shadow: -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white, 1px 1px 0 white;
}

JavaScript

$(function(){
    var data = {
        "nodes": [
            { "id": 0, "name": "A" },
            { "id": 1, "name": "B" },
            { "id": 2, "name": "C" },
            { "id": 3, "name": "D" },
            { "id": 4, "name": "E" }
        ],
        "links": [     
            { "source": 0, "target": 1, "name": "A-B" },
            { "source": 0, "target": 2, "name": "A-C-1" },
            { "source": 0, "target": 2, "name": "A-C-2" },
            { "source": 0, "target": 2, "name": "A-C-3" },
            { "source": 0, "target": 3, "name": "A-D-1" },
            { "source": 0, "target": 3, "name": "A-D-2" },
            { "source": 0, "target": 4, "name": "A-E-1" },
            { "source": 0, "target": 4, "name": "A-E-2" },
            { "source": 0, "target": 4, "name": "A-E-3" },
            { "source": 0, "target": 4, "name": "A-E-4" },
            { "source": 0, "target": 4, "name": "A-E-5" }
        ]
    };			
    
    // used to store the number of links between two nodes. 
    // mLinkNum[data.links[i].source + "," + data.links[i].target] = data.links[i].linkindex;
    var mLinkNum = {};
    
    // sort links first
    sortLinks();								
    
    // set up linkIndex and linkNumer, because it may possible multiple links share the same source and target node
    setLinkIndexAndNum();
    
    var w = 600,
        h = 500;
    
    var force = d3.layout.force()
                  .nodes(d3.values(data.nodes))
                  .links(data.links)
                  .size([w, h])
                  .linkDistance(150)
                  .charge(-300)
                  .on("tick", tick)
                  .start();
    
    var svg = d3.select(".graphContainer").append("svg:svg")
                .attr("width", w)
                .attr("height", h);
    
    var path = svg.append("svg:g")
                  .selectAll("path")
                  .data(force.links())
                  .enter().append("svg:path")
                  .attr("class", "link");;
   ...