Separating zoom behaviour and drag behaviour in D3.js

I’m having troubles in separating the zoom and drag behaviour in a d3.js rendered svg force directed layout graph.

I’m following many of the Mike Bostock‘s examples like this that talks about this separation using

d3.event.sourceEvent.stopPropagation();

in the function where the drag behaviour (for nodes) is defined to stop the zoom event but uselessy.
What am I doing wrong?

Here’s the GitHub project page and a “live example” of the script: http://toniogela.org/


Here’s the script:

var width = window.innerWidth;
var height = window.innerHeight;

var svg = d3.select("body").append("svg");

d3.json("graph.json", function(error, graph) {

  graph.links.forEach(function(d) {
    d.source = graph.nodes[d.source];
    d.target = graph.nodes[d.target];
  });

  //LINKS
  var links = svg.append("g")
    .attr("class", "link")
    .selectAll("line")
    .data(graph.links)
    .enter()
    .append("g");

  links.append("line")
    .attr("x1", function(d) {
      return d.source.x * width / 100;
    })
    .attr("y1", function(d) {
      return d.source.y * height / 100;
    })
    .attr("x2", function(d) {
      return d.target.x * width / 100;
    })
    .attr("y2", function(d) {
      return d.target.y * height / 100;
    });

  links.append("text")
    .attr("text-anchor", "middle")
    .attr("x", function(d) {
      return (d.target.x + d.source.x) * width / 200;
    })
    .attr("y", function(d) {
      return (d.target.y + d.source.y) * height / 200;
    })
    .attr("dy", ".35em")
    .text(function(d) {
      return d.label;
    })
    .call(getBB);

  function getBB(selection) {
    selection.each(function(d) {
      d.bbox = this.getBBox();
    });
  }

  links.insert("rect", "text")
    .attr("x", function(d) {
      return (d.target.x + d.source.x) * width / 200;
    })
    .attr("y", function(d) {
      return (d.target.y + d.source.y) * height / 200;
    })
    .attr("width", function(d) {
      return d.bbox.width + 4;
    })
    .attr("height", function(d) {
      return d.bbox.height;
    })
    .style("fill", "white");

  //NODES
  var nodes = svg.append("g")
    .attr("class", "nodes")
    .selectAll("circle")
    .data(graph.nodes)
    .enter()
    .append("g")
    .attr("transform", function(d) {
      d.x = d.x * width / 100;
      d.y = d.y * height / 100;
      return "translate(" + d.x + "," + d.y + ")";
    });

  nodes.append("circle")
    .attr("r", function(d) {
      return d.radius;
    })
    .attr("class", function(d) {
      return "cerchio";
    })
    .attr("href", "#content")
    .style("fill", function(d) {
      return d.color;
    });

  nodes.append("text")
    .attr("text-anchor", "middle")
    .attr("dy", ".35em")
    .text(function(d) {
      return d.label;
    });

  //SINGLE CLICK BEHAVIOR
  function singleClick(d) {
    var html = $(d.target).attr('href') ? $($(d.target).attr('href'))[0].outerHTML : $($(d.target).prev('circle').attr('href'))[0].outerHTML;
    $.colorbox({
      html: html,
      width: "90%",
      height: "90%"
    });
  }

  //DOUBLE CLICK BEHAVIOR
  function dblclicked(d) {
    if (d3.event.defaultPrevented) return;
    var html = $(d.target).attr('href') ? d.target : $(d.target).prev('circle')[0];

    d3.selectAll("circle").attr("r", 60).style("fill", "#BDD2A6");
    d3.select(html).attr("r", 90).style("fill", "#345830");
  }

  //DRAG BEHAVIOR
  function draggedNode(d) {
    d.x = d3.event.x;
    d.y = d3.event.y;
    //HERE THE STOP PROPAGATION
    d3.event.sourceEvent.stopPropagation(); 

    d3.select(this).attr("transform", function(d) {
      return "translate(" + d.x + "," + d.y + ")";
    });
    links.select("line").filter(function(l) {
      return l.source === d;
    }).attr("x1", d.x).attr("y1", d.y);
    links.select("line").filter(function(l) {
      return l.target === d;
    }).attr("x2", d.x).attr("y2", d.y);
  }

  // //ZOOM BEHAVIOR
  function zoomed() {
    $('.nodes').attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
    $('.link').attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
  }

  //CLICK VS DOUBLE CLICK
  function clickVSDoubleClick() {
    var event = d3.dispatch('click', 'dblclick');

    function cc(selection) {
      var down,
        tolerance = 5,
        last,
        wait = null;
      // euclidean distance
      function dist(a, b) {
        return Math.sqrt(Math.pow(a[0] - b[0], 2), Math.pow(a[1] - b[1], 2));
      }
      selection.on('mousedown', function() {
        down = d3.mouse(document.body);
        last = +new Date();
      });
      selection.on('mouseup', function() {
        if (dist(down, d3.mouse(document.body)) > tolerance) {
          return;
        } else {
          if (wait) {
            window.clearTimeout(wait);
            wait = null;
            event.dblclick(d3.event);
          } else {
            wait = window.setTimeout((function(e) {
              return function() {
                event.click(e);
                wait = null;
              };
            })(d3.event), 300);
          }
        }
      });

    };
    return d3.rebind(cc, event, 'on');
  }

  var drag = d3.behavior.drag().origin(function(d) {
    return d;
  }).on("drag", draggedNode);
  var cc = clickVSDoubleClick();
  var zoom = d3.behavior.zoom().scaleExtent([0.1, 10]).on("zoom", zoomed);
  svg.call(zoom).on("dblclick.zoom", null);
  nodes.call(cc).call(drag);
  cc.on('click', singleClick);
  cc.on('dblclick', dblclicked);




  //  FORCE PART
  var force = d3.layout.force()
    .size([width, height])
    .nodes(graph.nodes)
    .links(graph.links)
    .linkDistance(width / 5)
    .gravity(0)
    .start();

  var animationStep = 100;

  force.on('tick', function() {

    nodes.transition().ease('linear').duration(animationStep)
      .attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
      });

    links.select("line").transition().ease('linear').duration(animationStep)
      .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;
      });

    links.select("text").transition().ease('linear').duration(animationStep)
      .attr("x", function(d) {
        return (d.target.x + d.source.x) / 2;
      })
      .attr("y", function(d) {
        return (d.target.y + d.source.y) / 2;
      });

    links.select("rect").transition().ease('linear').duration(animationStep)
      .attr("x", function(d) {
        return ((d.target.x + d.source.x) / 2 - d.bbox.width / 2) - 2;
      })
      .attr("y", function(d) {
        return ((d.target.y + d.source.y) / 2 - d.bbox.height / 2);
      });

    force.stop();
    setTimeout(function() {
      force.start();
    }, animationStep);
  });
  // END FORCE
});


Source: stackoverflow-javascript

Snap Labels Draggable with Circles

Building on some of the work created in here to building something similar.

Trying to add labels (customisation on click) below every point that move whenever one of the circles is dragged. Already seen this answer on stack overflow.

With how the data points are set out, what would be the easiest way to do it?

<html ng-app>
<html lang="en">
<title>Test</title>
<head>
    <meta charset="utf-8">
    https://d3js.org/d3.v4.min.js
    https://giottojs.org/d3-canvas-transition/0.3.6/d3-canvas-transition.js
    <link rel="stylesheet" type="text/css" href="static/stylesheets/style.css?q=1280549780">
</head>
<body>
<body>
  
</div> </body> var PrimCol = "Blue" SeconCol = "Black" var example = d3.select("#example"), width = 368, height = 583, radius = 9, area = Math.PI*radius*radius, margin = 2*radius, text = ''; var shapes = ['Circle'], color = d3.scaleSequential(d3.interpolateViridis), N = 11, // Number of Circles points = d3.range(N).map(function(i) { return { type: "Circle", x: Math.round(Math.random() * (width - 2*margin) + margin), y: Math.round(Math.random() * (height - 2*margin) + margin) }; }); draw('svg'); function draw(type, r) { example.select('.paper').remove(); var paper = example .append(type) .classed('paper', true) .style('stroke', '#333') .attr('width', width).attr('height', height).canvasResolution(r).canvas(true); var marks = d3.symbol().type(function (d) {return d3['symbol' + d.type];}).size(function (d) {return area;}); // Background Information paper.append('rect') .attr('x', 0) .attr('y', 0) .attr('width', width) .attr('height', height) .style("stroke-width", 0) .style('fill', 'White') .style('fill-opacity', 1); paper .selectAll("path") .data(points) .enter() .append("path") .attr("transform", translate) .attr("d", marks) .style("fill", PrimCol) .style("stroke", SeconCol) .style("stroke-width", '1px') .on("mouseenter.hover", mouseenter) .on("mouseleave.hover", end) .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", mouseenter)); function mouseenter () { d3.select(this).style('cursor', 'move'); } function dragstarted () { d3.select(this).raise().style('stroke-width', '3px'); } function dragged(d) { d.x = d3.event.x; d.y = d3.event.y; d3.select(this).attr("transform", translate(d)); } function end() { var el = d3.select(this), d = el.datum(); el.style('cursor', 'default').style('stroke-width', '1px'); } function translate (d) { return "translate(" + d.x + "," + d.y + ")"; } } </html> Source: stackoverflow-javascript

d3.js tree-click one children node in depth 1 to extend its children and collapse other branch?

describe´╝Ü
As shown in the diagram,I just want to expend one branch (e.g. the red branch) when i click children node in depth 1 . Is there any way to do it in D3?
enter image description here
here is my code but it’s not enough.

function click(d) {
    if (d.children) {
     d._children = d.children;
     d.children = null;
    } 
       else {
        d.children = d._children;
        d._children = null;
       }

    if (d.parent && d.children) {
     d.parent.children.forEach(function(element) {
        if (d !== element) {
            collapse(element); 
        }
     });
    }

update(d);


Source: stackoverflow-javascript

Modify and display abbreviated data in the table generated using D3

I have a table generated using D3 and a json file ma_voteshare.json based on the following tutorial http://bl.ocks.org/jfreels/6734025. The first column of the generated table displays party name and the other columns show the corresponding numbers (see example below). What I need is to display abbreviated version of the party data for example: Bharathiya Janatha Party as (BJP) and so on. How can I modify the specific party column data. I have attached the Json file.

enter image description here

    d3.queue()
    .defer(d3.json, "https://jsonblob.com/api/2700cb25-fccc-11e6-a0ba-c7b961ce26a7")
    .await(ready)

function ready (error, up) {
    if (error) throw error;

    function tabulate(data, columns, tableName) {
        console.log(columns[0]);
        var table = d3.select(tableName).append('table')
        var thead = table.append('thead')
        var tbody = table.append('tbody');

        // append the header row
        thead.append('tr')
           .selectAll('th')
           .data(columns).enter()
           .append('th')
           .text(function (column) {
                return column;
            });

          // create a row for each object in the data
          var rows = tbody.selectAll('tr')
              .data(data)
              .enter()
              .append('tr')

          // create a cell in each row for each column
          var cells = rows.selectAll('td')
              .data(function (row) {
                  return columns.map(function (column) {
                      return {column: column, value: row[column]};
                  });
               })
               .enter()
               .append('td')
               .text(function (d) { return d.value; });
                   return table;
                }

              // render the table(s)
    tabulate(up, ['party', 'won', 'leading', 'total'], 'div#jsontable-up');
} // function ready


Source: stackoverflow-javascript

How to display two d3 wordclouds on one page

I’m trying to put two (or even more -> that depends on the users settings) d3 Wordclouds to one page. However I’ll get the following result:

(sorry the image upload doesn’t work) Therefore I’ll insert a link to the output image:
http://jdev.pemasoft.de/_stackoverflow/StackOverflow_d3_wordcloud_output.jpg

It seems, that the word list won’t be parsed correct.

My code looks like this:
(The php $Block variable specifies the position, where the recent wordcloud should be shown.)

var container = "svg_<?php echo $Block;?>";

var w = $('#word_cloud_<?php echo $Block;?>').width();
var h = w*0.75;

if($( window ).width()<400){
    var maxRange=20;
}else if($( window ).width()<800){
    var maxRange=40;
}else if($( window ).width()<1200){
    var maxRange=60;
}else if($( window ).width()>=1200){
    var maxRange=95;
}

var list_<?php echo $Block;?>=<?php echo $jsonWort; ?>;

var wordSize=12;
var layout;

generate_<?php echo $Block;?>(list_<?php echo $Block;?>);

function generate_<?php echo $Block;?>(list) {

    //Blacklist wird gefiltert!
    var blacklist=["ein","sind"];
    list=list.filter(function(x) { return blacklist.indexOf(x) < 0 });

    // Liste wird verarbeitet
    result = { };
    for(i = 0; i < list.length; ++i) {
        if(!result[list[i]])
            result[list[i]] = 0;
        ++result[list[i]];
    }

    var newList = _.uniq(list);



    var frequency_list = [];
    var len = newList.length;
    for (var i = 0; i < len; i++) {

        var temp = newList[i];
        frequency_list.push({
            text : temp,
            freq : result[newList[i]],
            time : 0 
        });

    }
    frequency_list.sort(function(a,b) { return parseFloat(b.freq) - parseFloat(a.freq) } );  


    for(var t = 0 ; t < len ; t++)
    {
        var addTime = (100 * t) +500;
        frequency_list[t].time=addTime;
    }


    for(i in frequency_list){
        if(frequency_list[i].freq*wordSize > 160)   
            wordSize = 3;
    }


    var sizeScale = d3.scale.linear().domain([0, d3.max(frequency_list,  function(d) { return d.freq} )]).range([5, maxRange]);
    layout= d3.layout.cloud().size([w, h])
        .words(frequency_list)
        .padding(5)
        .rotate(function() { return ~~(Math.random() * 2) * 90; })
        .font("Impact")
        .fontSize(function(d) { return sizeScale(d.freq); })
        .on("end",draw)
        .start();
}


function draw(words) {

    var fill = d3.scale.category20();

    d3.select(container).remove();

    d3.select("#word_cloud_<?php echo $Block;?>").append(container)
        .attr("width", w)
        .attr("height", h) 
        .append("g")
        .attr("transform", "translate(" + [w/2, h/2] + ")")
        .selectAll("text")
        .data(words)
        .enter().append("text")

        .transition()
        .duration(function(d) { return d.time}  )
        .attr('opacity', 1)
        .style("font-size", function(d) { return d.size + "px"; })
        .style("font-family", "Impact")
        .style("fill", function(d, i) { return fill(i); })
        .attr("text-anchor", "middle")
        .attr("transform", function(d) {
        return "rotate(" + d.rotate + ")";
    })
        .attr("transform", function(d) {
        return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
    })
        .text(function(d) { return d.text; });
}

I believe that the mistake has to be somewhere in

   var sizeScale = d3.scale.linear().domain([0, d3.max(frequency_list,  function(d) { return d.freq} )]).range([5, maxRange]);
layout= d3.layout.cloud().size([w, h])
    .words(frequency_list)
    .padding(5)
    .rotate(function() { return ~~(Math.random() * 2) * 90; })
    .font("Impact")
    .fontSize(function(d) { return sizeScale(d.freq); })
    .on("end",draw)
    .start();

But I’m not able to find it.


Source: stackoverflow-php