d3 v4向受力方向图添加箭头

时间:2018-08-29 10:34:01

标签: javascript d3.js

我正在尝试在d3.js中创建一个力导向图,其中的箭头指向大小不一的节点。我遇到了这个示例here,但是为了我的生命,我无法适应我的代码来添加箭头。我不确定是否需要在tick函数中添加其他内容,或者是否我引用的东西不正确。有人可以帮我吗?

Codepen-https://codepen.io/quirkules/pen/dqXRwj

var links_data = [{"source":"ABS","target":"ABS","count":8},{"source":"ABS","target":"ATS","count":1},{"source":"ABS","target":"CR","count":8},{"source":"ABS","target":"ENV","count":1},{"source":"ABS","target":"INT","count":16},{"source":"ABS","target":"ITS","count":9},{"source":"ABS","target":"PDG","count":1},{"source":"ABS","target":"PER","count":4},{"source":"ABS","target":"PRAC","count":3},{"source":"AC","target":"AC","count":1},{"source":"AC","target":"INT","count":9},{"source":"AC","target":"ITS","count":1},{"source":"ACDC","target":"ACDC","count":1},{"source":"ACDC","target":"CR","count":2},{"source":"ACDC","target":"ITS","count":13},{"source":"ACDC","target":"PER","count":4},{"source":"APL","target":"APL","count":8},{"source":"APL","target":"CR","count":3},{"source":"APL","target":"ENV","count":1},{"source":"APL","target":"INT","count":1},{"source":"APL","target":"ITS","count":29},{"source":"APL","target":"LA","count":1},{"source":"APL","target":"PEG","count":1},{"source":"APL","target":"PER","count":3},{"source":"AST","target":"AST","count":17},{"source":"AST","target":"COP","count":1},{"source":"AST","target":"DBT","count":2},{"source":"AST","target":"DEVOPS","count":1},{"source":"AST","target":"IGN","count":1},{"source":"AST","target":"INT","count":2},{"source":"AST","target":"ITS","count":32},{"source":"AST","target":"PDG","count":2},{"source":"AST","target":"PER","count":8},{"source":"ATS","target":"ABS","count":1},{"source":"ATS","target":"ATS","count":21},{"source":"ATS","target":"DBT","count":1},{"source":"ATS","target":"INT","count":3},{"source":"ATS","target":"PDG","count":1},{"source":"ATS","target":"PEG","count":1},{"source":"CAR","target":"APL","count":1},{"source":"CAR","target":"CAR","count":9},{"source":"CAR","target":"COP","count":1},{"source":"CAR","target":"INT","count":9},{"source":"CAR","target":"ITS","count":8},{"source":"IGN","target":"CR","count":4},{"source":"IGN","target":"IGN","count":13},{"source":"IGN","target":"INT","count":5},{"source":"IGN","target":"ITS","count":13},{"source":"IGN","target":"PER","count":4},{"source":"IGN","target":"PRAC","count":1},{"source":"LA","target":"AC","count":1},{"source":"LA","target":"INT","count":1},{"source":"LA","target":"ITS","count":37},{"source":"LA","target":"LA","count":18},{"source":"LA","target":"PER","count":2},{"source":"LOT","target":"LOT","count":18},{"source":"PDG","target":"ABS","count":1},{"source":"PDG","target":"AST","count":4},{"source":"PDG","target":"ATS","count":1},{"source":"PDG","target":"CAR","count":1},{"source":"PDG","target":"CR","count":8},{"source":"PDG","target":"ICS","count":1},{"source":"PDG","target":"IGN","count":3},{"source":"PDG","target":"INT","count":18},{"source":"PDG","target":"ITS","count":6},{"source":"PDG","target":"NRB","count":4},{"source":"PDG","target":"ONT","count":1},{"source":"PDG","target":"PDG","count":24},{"source":"PDG","target":"PER","count":1},{"source":"PEG","target":"CAR","count":1},{"source":"PEG","target":"ENV","count":1},{"source":"PEG","target":"INFRA","count":1},{"source":"PEG","target":"ITS","count":22},{"source":"PEG","target":"LA","count":1},{"source":"PEG","target":"PEG","count":51},{"source":"PEG","target":"PER","count":6},{"source":"RPT","target":"ABS","count":1},{"source":"RPT","target":"APL","count":1},{"source":"RPT","target":"IGN","count":1},{"source":"RPT","target":"INT","count":9},{"source":"RPT","target":"ITS","count":2},{"source":"RPT","target":"RPT","count":11},{"source":"RPT","target":"RTR","count":1},{"source":"RWWA","target":"INT","count":1},{"source":"RWWA","target":"ITS","count":1},{"source":"RWWA","target":"PER","count":1},{"source":"RWWA","target":"RWWA","count":1},{"source":"SCOR","target":"SCOR","count":5},{"source":"SPK","target":"INT","count":4},{"source":"SPK","target":"ITS","count":4},{"source":"SPK","target":"SPK","count":21},{"source":"TS","target":"CS","count":1},{"source":"TS","target":"TS","count":10}];

var nodes_data = [{"name":"ABS","total":11},{"name":"ATS","total":23},{"name":"CR","total":25},{"name":"ENV","total":3},{"name":"INT","total":78},{"name":"ITS","total":177},{"name":"PDG","total":28},{"name":"PER","total":33},{"name":"PRAC","total":4},{"name":"AC","total":2},{"name":"ACDC","total":1},{"name":"APL","total":10},{"name":"LA","total":20},{"name":"PEG","total":53},{"name":"AST","total":21},{"name":"COP","total":2},{"name":"DBT","total":3},{"name":"DEVOPS","total":1},{"name":"IGN","total":18},{"name":"CAR","total":11},{"name":"LOT","total":18},{"name":"ICS","total":1},{"name":"NRB","total":4},{"name":"ONT","total":1},{"name":"INFRA","total":1},{"name":"RPT","total":11},{"name":"RTR","total":1},{"name":"RWWA","total":1},{"name":"SCOR","total":5},{"name":"SPK","total":21},{"name":"CS","total":1},{"name":"TS","total":10}];

   //create node size scale
  var nodeSizeScale = d3.scaleLinear()
    .domain(d3.extent(nodes_data, d => d.total))
    .range([30, 70]);

  //create node size scale
  var linkSizeScale = d3.scaleLinear()
    .domain(d3.extent(links_data, d => d.count))
    .range([5, 30]);

  //create node size scale
  var linkColourScale = d3.scaleLinear()
    .domain(d3.extent(links_data, d => d.count))
    .range(['blue', 'red']);

//document.getElementsByTagName('body')[0].innerHTML = '<div>' + JSON.stringify(nodes_data) + '</div>';

//create somewhere to put the force directed graph
var height = 650,
  width = 950;

var svg = d3.select("body").append("svg")
      .attr('width',width)
      .attr('height',height);

var radius = 15;


//set up the simulation and add forces  
var simulation = d3.forceSimulation()
          .nodes(nodes_data);

var link_force =  d3.forceLink(links_data)
          .id(function(d) { return d.name; })
          ;

var charge_force = d3.forceManyBody()
    .strength(-1000); 

var center_force = d3.forceCenter(width / 2, height / 2);  

simulation
    .force("charge_force", charge_force)
    .force("center_force", center_force)
    .force("link",link_force)
 ;

//add tick instructions: 
simulation.on("tick", tickActions );

// THIS CODE SECTION ISN'T RENDERING
// Per-type markers, as they don't inherit styles.
svg.append("defs").selectAll("marker")
    .data(["dominating"])
    .enter().append("marker")
    .attr("id", function (d) {
        return d;
    })
    .attr("viewBox", "0 -5 10 10")
    .attr("refX", 15)
    .attr("refY", -1.5)
    .attr("markerWidth", 12)
    .attr("markerHeight", 12)
    .attr("orient", "auto")
    .append("path")
    .attr("d", "M0,-5L10,0L0,5");

//add encompassing group for the zoom 
var g = svg.append("g")
    .attr("class", "everything");

// add the curved links to our graphic
var link = g.selectAll(".link")
    .data(links_data)
    .enter()
    .append("path")
    .attr("class", "link")
    .style('stroke', d => {return linkColourScale(d.count);})
    .attr('stroke-opacity', 0.5)
    .attr('stroke-width', d => {return linkSizeScale(d.count);});

//draw circles for the nodes 
var node = g.append("g")
        .attr("class", "nodes") 
        .selectAll("circle")
        .data(nodes_data)
        .enter()
        .append("circle")
        .attr("r", d => {return nodeSizeScale(d.total);})
        .attr("fill", "#333")
        .on("mouseover", mouseOver(.1))
        .on("mouseout", mouseOut); 

//add text labels
var text = g.append("g")
    .attr("class", "labels")
    .selectAll("text")
    .data(nodes_data)
    .enter().append("text")
    .style("text-anchor","middle")
    .style("font-weight", "bold")
    .style("pointer-events", "none")
    .attr("dy", ".35em")
    .text(function(d) { return d.name });

//add drag capabilities  
var drag_handler = d3.drag()
  .on("start", drag_start)
  .on("drag", drag_drag)
  .on("end", drag_end); 

drag_handler(node);


//add zoom capabilities 
var zoom_handler = d3.zoom()
    .on("zoom", zoom_actions);

zoom_handler(svg);     

/** Functions **/

//Drag functions 
//d is the node 
function drag_start(d) {
 if (!d3.event.active) simulation.alphaTarget(0.3).restart();
    d.fx = d.x;
    d.fy = d.y;
}

//make sure you can't drag the circle outside the box
function drag_drag(d) {
  d.fx = d3.event.x;
  d.fy = d3.event.y;
}

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

//Zoom functions 
function zoom_actions(){
    g.attr("transform", d3.event.transform)
}

function tickActions() {
    //update circle positions each tick of the simulation 
       node
        .attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });

    //update link positions 
    link.attr("d", positionLink);

    text.attr("x", function(d) { return d.x; })
        .attr("y", function(d) { return d.y; });
}

// links are drawn as curved paths between nodes,
// through the intermediate nodes
function positionLink(d) {
    var offset = 30;

    var midpoint_x = (d.source.x + d.target.x) / 2;
    var midpoint_y = (d.source.y + d.target.y) / 2;

    var dx = (d.target.x - d.source.x);
    var dy = (d.target.y - d.source.y);

    var normalise = Math.sqrt((dx * dx) + (dy * dy));

    var offSetX = midpoint_x + offset * (dy / normalise);
    var offSetY = midpoint_y - offset * (dx / normalise);

    return "M" + d.source.x + "," + d.source.y +
        "S" + offSetX + "," + offSetY +
        " " + d.target.x + "," + d.target.y;
}

// build a dictionary of nodes that are linked
var linkedByIndex = {};
links_data.forEach(function(d) {
    linkedByIndex[d.source.index + "," + d.target.index] = 1;
});

// check the dictionary to see if nodes are linked
function isConnected(a, b) {
    return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
}

// fade nodes on hover
function mouseOver(opacity) {
    return function(d) {
        // check all other nodes to see if they're connected
        // to this one. if so, keep the opacity at 1, otherwise
        // fade
        node.style("stroke-opacity", function(o) {
            thisOpacity = isConnected(d, o) ? 1 : opacity;
            return thisOpacity;
        });
        node.style("fill-opacity", function(o) {
            thisOpacity = isConnected(d, o) ? 1 : opacity;
            return thisOpacity;
        });
        text.style("fill-opacity", function(o) {
            thisOpacity = isConnected(d, o) ? 1 : opacity;
            return thisOpacity;
        });
        // also style link accordingly
        link.style("stroke-opacity", function(o) {
            return o.source === d || o.target === d ? 1 : opacity;
        });
        link.style("stroke", function(o) {
            return o.source === d || o.target === d ? linkColourScale(o.count) : "#333";
        });
    };
}

function mouseOut() {
    node.style("stroke-opacity", 1);
    node.style("fill-opacity", 1);
    text.style("fill-opacity", 1);
    link.style("stroke-opacity", 0.5);
    link.style("stroke", d => {return linkColourScale(d.count);});
}

1 个答案:

答案 0 :(得分:1)

在您引用的示例中,我对您的代码进行了相同的代码更改,似乎工作正常。

唯一需要做的额外更新是,由于您有节点连接到自身,因此我只能将marker-end属性和路径长度更新仅应用于经过过滤的链接集。

var links_data = [{"source":"ABS","target":"ABS","count":8},{"source":"ABS","target":"ATS","count":1},{"source":"ABS","target":"CR","count":8},{"source":"ABS","target":"ENV","count":1},{"source":"ABS","target":"INT","count":16},{"source":"ABS","target":"ITS","count":9},{"source":"ABS","target":"PDG","count":1},{"source":"ABS","target":"PER","count":4},{"source":"ABS","target":"PRAC","count":3},{"source":"AC","target":"AC","count":1},{"source":"AC","target":"INT","count":9},{"source":"AC","target":"ITS","count":1},{"source":"ACDC","target":"ACDC","count":1},{"source":"ACDC","target":"CR","count":2},{"source":"ACDC","target":"ITS","count":13},{"source":"ACDC","target":"PER","count":4},{"source":"APL","target":"APL","count":8},{"source":"APL","target":"CR","count":3},{"source":"APL","target":"ENV","count":1},{"source":"APL","target":"INT","count":1},{"source":"APL","target":"ITS","count":29},{"source":"APL","target":"LA","count":1},{"source":"APL","target":"PEG","count":1},{"source":"APL","target":"PER","count":3},{"source":"AST","target":"AST","count":17},{"source":"AST","target":"COP","count":1},{"source":"AST","target":"DBT","count":2},{"source":"AST","target":"DEVOPS","count":1},{"source":"AST","target":"IGN","count":1},{"source":"AST","target":"INT","count":2},{"source":"AST","target":"ITS","count":32},{"source":"AST","target":"PDG","count":2},{"source":"AST","target":"PER","count":8},{"source":"ATS","target":"ABS","count":1},{"source":"ATS","target":"ATS","count":21},{"source":"ATS","target":"DBT","count":1},{"source":"ATS","target":"INT","count":3},{"source":"ATS","target":"PDG","count":1},{"source":"ATS","target":"PEG","count":1},{"source":"CAR","target":"APL","count":1},{"source":"CAR","target":"CAR","count":9},{"source":"CAR","target":"COP","count":1},{"source":"CAR","target":"INT","count":9},{"source":"CAR","target":"ITS","count":8},{"source":"IGN","target":"CR","count":4},{"source":"IGN","target":"IGN","count":13},{"source":"IGN","target":"INT","count":5},{"source":"IGN","target":"ITS","count":13},{"source":"IGN","target":"PER","count":4},{"source":"IGN","target":"PRAC","count":1},{"source":"LA","target":"AC","count":1},{"source":"LA","target":"INT","count":1},{"source":"LA","target":"ITS","count":37},{"source":"LA","target":"LA","count":18},{"source":"LA","target":"PER","count":2},{"source":"LOT","target":"LOT","count":18},{"source":"PDG","target":"ABS","count":1},{"source":"PDG","target":"AST","count":4},{"source":"PDG","target":"ATS","count":1},{"source":"PDG","target":"CAR","count":1},{"source":"PDG","target":"CR","count":8},{"source":"PDG","target":"ICS","count":1},{"source":"PDG","target":"IGN","count":3},{"source":"PDG","target":"INT","count":18},{"source":"PDG","target":"ITS","count":6},{"source":"PDG","target":"NRB","count":4},{"source":"PDG","target":"ONT","count":1},{"source":"PDG","target":"PDG","count":24},{"source":"PDG","target":"PER","count":1},{"source":"PEG","target":"CAR","count":1},{"source":"PEG","target":"ENV","count":1},{"source":"PEG","target":"INFRA","count":1},{"source":"PEG","target":"ITS","count":22},{"source":"PEG","target":"LA","count":1},{"source":"PEG","target":"PEG","count":51},{"source":"PEG","target":"PER","count":6},{"source":"RPT","target":"ABS","count":1},{"source":"RPT","target":"APL","count":1},{"source":"RPT","target":"IGN","count":1},{"source":"RPT","target":"INT","count":9},{"source":"RPT","target":"ITS","count":2},{"source":"RPT","target":"RPT","count":11},{"source":"RPT","target":"RTR","count":1},{"source":"RWWA","target":"INT","count":1},{"source":"RWWA","target":"ITS","count":1},{"source":"RWWA","target":"PER","count":1},{"source":"RWWA","target":"RWWA","count":1},{"source":"SCOR","target":"SCOR","count":5},{"source":"SPK","target":"INT","count":4},{"source":"SPK","target":"ITS","count":4},{"source":"SPK","target":"SPK","count":21},{"source":"TS","target":"CS","count":1},{"source":"TS","target":"TS","count":10}];

var nodes_data = [{"name":"ABS","total":11},{"name":"ATS","total":23},{"name":"CR","total":25},{"name":"ENV","total":3},{"name":"INT","total":78},{"name":"ITS","total":177},{"name":"PDG","total":28},{"name":"PER","total":33},{"name":"PRAC","total":4},{"name":"AC","total":2},{"name":"ACDC","total":1},{"name":"APL","total":10},{"name":"LA","total":20},{"name":"PEG","total":53},{"name":"AST","total":21},{"name":"COP","total":2},{"name":"DBT","total":3},{"name":"DEVOPS","total":1},{"name":"IGN","total":18},{"name":"CAR","total":11},{"name":"LOT","total":18},{"name":"ICS","total":1},{"name":"NRB","total":4},{"name":"ONT","total":1},{"name":"INFRA","total":1},{"name":"RPT","total":11},{"name":"RTR","total":1},{"name":"RWWA","total":1},{"name":"SCOR","total":5},{"name":"SPK","total":21},{"name":"CS","total":1},{"name":"TS","total":10}];

   //create node size scale
  var nodeSizeScale = d3.scaleLinear()
    .domain(d3.extent(nodes_data, d => d.total))
    .range([30, 70]);

  //create node size scale
  var linkSizeScale = d3.scaleLinear()
    .domain(d3.extent(links_data, d => d.count))
    .range([5, 30]);

  //create node size scale
  var linkColourScale = d3.scaleLinear()
    .domain(d3.extent(links_data, d => d.count))
    .range(['blue', 'red']);

//document.getElementsByTagName('body')[0].innerHTML = '<div>' + JSON.stringify(nodes_data) + '</div>';

//create somewhere to put the force directed graph
var height = 650,
  width = 950;

var svg = d3.select("body").append("svg")
      .attr('width',width)
      .attr('height',height);
    
var radius = 15;


//set up the simulation and add forces  
var simulation = d3.forceSimulation()
          .nodes(nodes_data);
                              
var link_force =  d3.forceLink(links_data)
          .id(function(d) { return d.name; })
          ;
         
var charge_force = d3.forceManyBody()
    .strength(-1000); 
    
var center_force = d3.forceCenter(width / 2, height / 2);  
                      
simulation
    .force("charge_force", charge_force)
    .force("center_force", center_force)
    .force("link",link_force)
 ;
  
//add tick instructions: 
simulation.on("tick", tickActions );

// THIS CODE SECTION ISN'T RENDERING
// Per-type markers, as they don't inherit styles.
svg.append("defs").selectAll("marker")
	.data(["dominating"])
	.enter().append("marker")
	.attr('markerUnits', 'userSpaceOnUse')
	.attr("id", function (d) {
		return d;
	})
	.attr("viewBox", "0 -5 10 10")
	.attr("refX", 0)
	.attr("refY", 0)
	.attr("markerWidth", 12)
	.attr("markerHeight", 12)
	.attr("orient", "auto-start-reverse")
	.append("path")
	.attr("d", "M0,-5L10,0L0,5")
	.attr("fill", "red");

//add encompassing group for the zoom 
var g = svg.append("g")
    .attr("class", "everything");

// add the curved links to our graphic
var link = g.selectAll(".link")
    .data(links_data)
    .enter()
    .append("path")
    .attr("class", "link")
    .style('stroke', d => {return linkColourScale(d.count);})
    .attr('stroke-opacity', 0.5)
    .attr('stroke-width', d => {return linkSizeScale(d.count);})
	  .attr("marker-end", function(d) {
        if(JSON.stringify(d.target) !== JSON.stringify(d.source))
           return "url(#dominating)";
    });

//draw circles for the nodes 
var node = g.append("g")
        .attr("class", "nodes") 
        .selectAll("circle")
        .data(nodes_data)
        .enter()
        .append("circle")
        .attr("r", d => {return nodeSizeScale(d.total);})
        .attr("fill", "#333")
        .on("mouseover", mouseOver(.1))
        .on("mouseout", mouseOut); 

//add text labels
var text = g.append("g")
    .attr("class", "labels")
    .selectAll("text")
    .data(nodes_data)
    .enter().append("text")
    .style("text-anchor","middle")
    .style("font-weight", "bold")
    .style("pointer-events", "none")
    .attr("dy", ".35em")
    .text(function(d) { return d.name });

//add drag capabilities  
var drag_handler = d3.drag()
  .on("start", drag_start)
  .on("drag", drag_drag)
  .on("end", drag_end); 
  
drag_handler(node);


//add zoom capabilities 
var zoom_handler = d3.zoom()
    .on("zoom", zoom_actions);

zoom_handler(svg);     

/** Functions **/

//Drag functions 
//d is the node 
function drag_start(d) {
 if (!d3.event.active) simulation.alphaTarget(0.3).restart();
    d.fx = d.x;
    d.fy = d.y;
}

//make sure you can't drag the circle outside the box
function drag_drag(d) {
  d.fx = d3.event.x;
  d.fy = d3.event.y;
}

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

//Zoom functions 
function zoom_actions(){
    g.attr("transform", d3.event.transform)
}

function tickActions() {
    //update circle positions each tick of the simulation 
       node
        .attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
        
    //update link positions 
    link.attr("d", positionLink1);
	  link.filter(function(d){ return JSON.stringify(d.target) !== JSON.stringify(d.source); })
      .attr("d",positionLink2);

    text.attr("x", function(d) { return d.x; })
        .attr("y", function(d) { return d.y; });
}


function positionLink1(d) {
    var dx = d.target.x - d.source.x,
        dy = d.target.y - d.source.y,
        dr = Math.sqrt(dx * dx + dy * dy);
    return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
}

  // recalculate and back off the distance
function positionLink2(d) {
	    // length of current path
    var pl = this.getTotalLength(),
        // radius of circle plus marker head
        r = nodeSizeScale(d.target.total)+ 12, //12 is the "size" of the marker Math.sqrt(12**2 + 12 **2)
        // position close to where path intercepts circle	
        m = this.getPointAtLength(pl - r);          

     var dx = m.x - d.source.x,
        dy = m.y - d.source.y,
        dr = Math.sqrt(dx * dx + dy * dy);

      return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + m.x + "," + m.y;
}

// build a dictionary of nodes that are linked
var linkedByIndex = {};
links_data.forEach(function(d) {
    linkedByIndex[d.source.index + "," + d.target.index] = 1;
});

// check the dictionary to see if nodes are linked
function isConnected(a, b) {
    return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
}

// fade nodes on hover
function mouseOver(opacity) {
    return function(d) {
        // check all other nodes to see if they're connected
        // to this one. if so, keep the opacity at 1, otherwise
        // fade
        node.style("stroke-opacity", function(o) {
            thisOpacity = isConnected(d, o) ? 1 : opacity;
            return thisOpacity;
        });
        node.style("fill-opacity", function(o) {
            thisOpacity = isConnected(d, o) ? 1 : opacity;
            return thisOpacity;
        });
        text.style("fill-opacity", function(o) {
            thisOpacity = isConnected(d, o) ? 1 : opacity;
            return thisOpacity;
        });
        // also style link accordingly
        link.style("stroke-opacity", function(o) {
            return o.source === d || o.target === d ? 1 : opacity;
        });
        link.style("stroke", function(o) {
            return o.source === d || o.target === d ? linkColourScale(o.count) : "#333";
        });
    };
}

function mouseOut() {
    node.style("stroke-opacity", 1);
    node.style("fill-opacity", 1);
    text.style("fill-opacity", 1);
    link.style("stroke-opacity", 0.5);
    link.style("stroke", d => {return linkColourScale(d.count);});
}
body {
    width:99%;
    height:100%;
    background: #111111;
}

.svg {
    width:1000;
    height:1000;
}

.link {
	fill: none;
}

.labels {
	font-family: Arial;
	fill: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>