Accepted answer

After some intense staring at the screen for a couple hours, I realised a number of little housekeeping tips to make mine, and hopefully to any other programmers new to D3, applications easier to understand and less prone to errors.

As it turns out from my last example, I was trying to perform zoom functions when the zoom variable containing the D3 .zoom() method hadn't been added to the links variable (as I have pointed out below). Once I had done this, everything worked perfectly.

I've also added some comments as to make the improve the readability of the code from the original question, these changes make it easier to understand and much easier to build upon (much like the inheritance with python classes that I'm familiar with).

So hopefully my little moment of frustration is useful to someone in the future, until the next question, happy debugging :)

Mr Incompetent.

function selectableForceDirectedGraph(){

var width ='svg').attr('width');
var height ='svg').attr('height');

var color = d3.scaleOrdinal(d3.schemeCategory20);

//As the height and width have already been set, no need to reset them.
var svg ="svg");

//This is the container group for the zoom
var container = svg.append("g")

//see the above question for explanation for purpose of these variable.
var json_nodes = _dict['one']['nodes'];
var json_links = _dict['one']['links'];

var simulation = d3.forceSimulation()
    .force("link", d3.forceLink().id(function(d){return}))
    .force("charge", d3.forceManyBody())
    .force("center", d3.forceCenter(width / 2, height / 2));

//drawing lines for the links
  var link = container.append("g")
    .attr("class", "links")
    .attr("stroke-width", function(d) { return Math.sqrt(d.value); })

//draw the circles for the nodes
  var node = container.append("g")
    .attr("class", "nodes")
    .attr("r", 5)
    .attr("fill", function(d) { return color(; });

//HOUSE KEEPING NOTE: add handlers for drag and zoom as to prevent DRY
var drag_controls = d3.drag()

drag_controls(node); //adding the drag event handlers to the nodes

var zoom_controls = d3.zoom()

zoom_controls(svg); //adding the zoom event handler to the svg container

      .text(function(d) { return; });

      .on("tick", ticked);


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

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

function dragstarted(d) {
  if (! 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 (! simulation.alphaTarget(0);
  d.fx = null;
  d.fy = null;

//Zoom functions 
function zoomed(){

Related Query

More Query from same tag