Brushing to select nodes on a fixed d3 force-directed graph with panning
===

I'd like to use D3 to create a force-directed graph with fixed draggable nodes after converging that also has panning and zooming and selecting nodes features. In addition, I'd like the graph to have a brushing feature that can be used to select a group of nodes and drag the selection on the canvas. 

So far I've the fixed nodes, zooming and panning in place (and tooltips created with qtip). The problem is that even though there's [an example][1] of how brushing could be implemented, it would interfere with panning. How can I modify the example I have so that it works with both panning and brushing: can panning for example be delayed for a half a second so mousedown would not interfere with brushing? Are there any proper examples that would illustrate the co-existance of panning and brushing with selection of group of nodes?

    <!DOCTYPE html>
    <html><head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8">
        <title>d3.js ~ Force-Directed Graph</title>
        <link rel="stylesheet" type="text/css" href="http://craigsworks.com/projects/qtip2/packages/latest/jquery.qtip.min.css">
        <style type="text/css">
        .link { }
        </style>
        <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/d3/2.8.1/d3.v2.min.js"></script>
        <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
        <script type="text/javascript" src="http://craigsworks.com/projects/qtip2/packages/latest/jquery.qtip.min.js"></script>
        <script type='text/javascript'>
          function onLoad() {
    
          var width = $(window).width() - 50,
              height = $(window).height() - 50;
          var default_opacity = 0.6;
    
          var color = d3.scale.category20();
          var fill = d3.scale.category10();
          var force = d3.layout.force()
              .charge(-200)
              .linkDistance(150)
              .gravity(.07)
              .size([width, height]);
    
    
          var svg = d3.select("#chart").append("svg:svg")
              .attr("width", width)
              .attr("height", height)
              .attr("pointer-events", "all")
              .append('svg:g')
              // .attr('class', 'brush') 
              // .call(brush.x(brushX).y(brushY))
              .call(d3.behavior.zoom().on("zoom", redraw))
              .append('svg:g');
    
          // append a white rectangle to background to use in zooming
          svg.append('svg:rect')
              .attr('width', width)
              .attr('height', height)
              .attr('fill', 'white');
              //.style("stroke", "#000");
    
          function redraw() {
            svg.attr("transform",
                "translate(" + d3.event.translate + ")"
                + " scale(" + d3.event.scale + ")");
          }
    
          d3.json("edges_nodes.json", function(json) {
            force
                .nodes(json.nodes)
                .links(json.links)
                .size([width,height])
                .start();
          
    
            // converge
            for(var i =0; i < 50;++i )//force.nodes().length; i++)
            {
              force.tick();
            }
            var link = svg.selectAll("line.link")
                .data(json.links)
              .enter().append("line")
                .attr("class", "link")
                .style("stroke", "black")
                .style("stroke-width", function(d) { return d.value; })
                .style("stroke-opacity", default_opacity );
    
            var node = svg.selectAll("path.node")
            //var node = svg.selectAll("text.node")
                .data(json.nodes, function(d) { return d.id } )
              .enter().append("svg:path")
                .attr("class", "node")
                .attr("id", function(d) { return "node" + d.id; } )
                .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
                .attr("d", d3.svg.symbol()
                  .size(function(d) { return Math.random()*100 + 100; })
                  .type(function(d) 
                  {
                    if( d.class === "a" )
                    {
                      return "circle";
                    }
                    if( d.class === "b" )
                    {
                      return "cross";
                    }
                    if( d.class === "c" )
                    {
                      return "diamond";
                    }
                    if( d.class === "d" )
                    {
                      return "square";
                    }                                
                    if( d.class === "e" )
                    {
                      return "triangle-down";
                    }
                  } ) )
                .text( function(d) { return d.name;})
                .on("click", fade(default_opacity))
                .on("drag", fade(default_opacity))
                .on("mouseover", fade(.1)).on("mouseout", fade(default_opacity) )
                .style("fill", function(d) { return color(d.group); })
                .style("stroke", function(d) { return d3.rgb(fill(d.group)).darker(); } )
                .call(force.drag);
    
              var linkedByIndex = {};
              json.links.forEach(function(d) {
                  linkedByIndex[d.source.index + "," + d.target.index] = 1;
              });          
    
              function isConnected(a, b) {
                  return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
              }            
    
              function fade(opacity) {
                  return function(d) {
                      node.transition().style("stroke-opacity", function(o) {
                          thisOpacity = isConnected(d, o) ? 1 : opacity;
                          this.setAttribute('fill-opacity', thisOpacity);
                          return thisOpacity;
                      });
    
                      link.style("stroke-opacity", function(o) {
                          return o.source === d || o.target === d ? default_opacity : opacity;
                      });
                  };
              }      
    
            var getText = function()
            {
              var id = this.attr("id");
              var data = d3.select("path#" + id).data()[0];
              var html = "<p><b>Id:</b> " + data.id + "</p>";
              html += "<p><b>Name:</b> " + data.name + "</p>";
    
              return html;
    
            };
    
            $('path.node').qtip({
              show: { 
                delay: 500 },
              content: {
                text: getText, 
                  },
              position: {
            my: 'right bottom',
            //    target: 'mouse',
               viewport: $(window),
                adjust: {
                  x:-5, y:-5
                },
              },
              hide: { delay: 60 }
            });
    
            force.on("tick", function() {
              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("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
        
            });
    
            // force.stop();
              for(var i = 0; i < force.nodes().length; ++i )
              {
                force.nodes()[i].fixed = true;
              }
    
    
          });
    
    
        }    
        </script>
      </head>
    
      <body onload="onLoad()">
            <div class="sidebar">
              <h1>d3.js</h1>
            </div>
    
            <h1 id="forcedirected_graph">Force-Directed Graph</h1>
            <div class="gallery" id="chart"></div>
      </body>
    </html>

And the related JSON is just random data:

    {"nodes": [{"id": 0, "name": "kWgnOo", "class": "c"}, {"id": 1, "name": "NkFcIw", "class": "a"}, {"id": 2, "name": "Ik8Swl", "class": "c"}, {"id": 3, "name": "VjEtdy", "class": "c"}, {"id": 4, "name": "i0DvXL", "class": "b"}, {"id": 5, "name": "GrQ90j", "class": "b"}, {"id": 6, "name": "t57FKG", "class": "d"}, {"id": 7, "name": "3QlLaf", "class": "c"}, {"id": 8, "name": "FJGvDm", "class": "d"}, {"id": 9, "name": "Nb8SfI", "class": "b"}, {"id": 10, "name": "bc1GOz", "class": "b"}, {"id": 11, "name": "YzJrbD", "class": "d"}, {"id": 12, "name": "OhZA7G", "class": "e"}, {"id": 13, "name": "BYcix6", "class": "d"}, {"id": 14, "name": "kCj21H", "class": "c"}, {"id": 15, "name": "rHXZfd", "class": "a"}, {"id": 16, "name": "JgO71B", "class": "c"}, {"id": 17, "name": "ZqtATo", "class": "c"}, {"id": 18, "name": "n7kTNY", "class": "d"}, {"id": 19, "name": "8FsOfp", "class": "b"}, {"id": 20, "name": "JtvcSs", "class": "e"}, {"id": 21, "name": "em37dx", "class": "b"}, {"id": 22, "name": "f9PwRh", "class": "b"}, {"id": 23, "name": "35a0lp", "class": "b"}, {"id": 24, "name": "scGDmy", "class": "c"}, {"id": 25, "name": "t5mX2n", "class": "a"}, {"id": 26, "name": "syUoQb", "class": "c"}, {"id": 27, "name": "lofyK7", "class": "a"}, {"id": 28, "name": "NeIDGH", "class": "c"}, {"id": 29, "name": "XeR95a", "class": "d"}, {"id": 30, "name": "cGvONI", "class": "d"}, {"id": 31, "name": "iYQc8s", "class": "b"}, {"id": 32, "name": "OFz5BE", "class": "d"}, {"id": 33, "name": "iLXqMD", "class": "c"}, {"id": 34, "name": "fUKqDj", "class": "c"}, {"id": 35, "name": "XIRCAg", "class": "b"}, {"id": 36, "name": "sMuFDb", "class": "b"}, {"id": 37, "name": "qPJuvc", "class": "e"}, {"id": 38, "name": "V3KY7X", "class": "e"}, {"id": 39, "name": "Lfiv4V", "class": "c"}, {"id": 40, "name": "rqyoC7", "class": "c"}, {"id": 41, "name": "IAtTLm", "class": "e"}, {"id": 42, "name": "EM4kWF", "class": "a"}, {"id": 43, "name": "V3xem4", "class": "b"}, {"id": 44, "name": "MsDamf", "class": "c"}, {"id": 45, "name": "huFtyv", "class": "a"}, {"id": 46, "name": "tk1s5U", "class": "d"}, {"id": 47, "name": "uJrcAw", "class": "a"}, {"id": 48, "name": "p3AViK", "class": "d"}, {"id": 49, "name": "aEUwP7", "class": "b"}, {"id": 50, "name": "ToCMfg", "class": "b"}, {"id": 51, "name": "uysAhc", "class": "e"}, {"id": 52, "name": "HTvyQq", "class": "b"}, {"id": 53, "name": "vDmtOY", "class": "b"}, {"id": 54, "name": "avMsV2", "class": "b"}, {"id": 55, "name": "9qywQd", "class": "d"}, {"id": 56, "name": "Mxhg3X", "class": "e"}, {"id": 57, "name": "ApdtKF", "class": "b"}, {"id": 58, "name": "LhQDEy", "class": "c"}, {"id": 59, "name": "ueS71g", "class": "a"}], "links": [{"source": 35, "target": 20, "value": 4}, {"source": 22, "target": 18, "value": 4}, {"source": 1, "target": 36, "value": 5}, {"source": 56, "target": 55, "value": 4}, {"source": 24, "target": 57, "value": 6}, {"source": 59, "target": 53, "value": 4}, {"source": 25, "target": 43, "value": 2}, {"source": 45, "target": 29, "value": 1}, {"source": 35, "target": 42, "value": 5}, {"source": 14, "target": 41, "value": 3}, {"source": 39, "target": 34, "value": 6}, {"source": 40, "target": 5, "value": 4}, {"source": 34, "target": 18, "value": 3}, {"source": 10, "target": 38, "value": 3}, {"source": 46, "target": 32, "value": 2}, {"source": 29, "target": 33, "value": 2}, {"source": 19, "target": 15, "value": 2}, {"source": 42, "target": 58, "value": 2}, {"source": 1, "target": 40, "value": 6}, {"source": 19, "target": 5, "value": 3}, {"source": 14, "target": 40, "value": 2}, {"source": 58, "target": 23, "value": 2}, {"source": 0, "target": 26, "value": 1}, {"source": 15, "target": 28, "value": 3}, {"source": 32, "target": 20, "value": 2}, {"source": 33, "target": 20, "value": 5}, {"source": 37, "target": 6, "value": 2}, {"source": 14, "target": 32, "value": 4}, {"source": 21, "target": 48, "value": 3}, {"source": 44, "target": 20, "value": 2}, {"source": 2, "target": 1, "value": 1}, {"source": 1, "target": 38, "value": 4}, {"source": 19, "target": 28, "value": 3}, {"source": 29, "target": 19, "value": 2}, {"source": 14, "target": 14, "value": 1}, {"source": 35, "target": 3, "value": 4}, {"source": 9, "target": 35, "value": 1}, {"source": 8, "target": 11, "value": 2}, {"source": 4, "target": 39, "value": 2}, {"source": 13, "target": 13, "value": 4}, {"source": 14, "target": 51, "value": 5}, {"source": 3, "target": 47, "value": 1}, {"source": 6, "target": 11, "value": 5}, {"source": 49, "target": 46, "value": 5}, {"source": 53, "target": 36, "value": 3}, {"source": 0, "target": 53, "value": 2}, {"source": 24, "target": 3, "value": 5}, {"source": 13, "target": 2, "value": 6}, {"source": 22, "target": 59, "value": 5}, {"source": 8, "target": 40, "value": 5}, {"source": 34, "target": 14, "value": 3}, {"source": 33, "target": 52, "value": 2}, {"source": 30, "target": 52, "value": 3}, {"source": 12, "target": 5, "value": 6}, {"source": 54, "target": 57, "value": 4}, {"source": 21, "target": 0, "value": 1}, {"source": 30, "target": 31, "value": 1}, {"source": 38, "target": 3, "value": 3}, {"source": 56, "target": 46, "value": 2}, {"source": 0, "target": 41, "value": 3}, {"source": 6, "target": 30, "value": 1}, {"source": 22, "target": 59, "value": 1}, {"source": 49, "target": 16, "value": 3}, {"source": 15, "target": 33, "value": 4}, {"source": 39, "target": 1, "value": 5}, {"source": 56, "target": 40, "value": 6}, {"source": 41, "target": 27, "value": 1}, {"source": 7, "target": 5, "value": 3}, {"source": 6, "target": 25, "value": 3}, {"source": 21, "target": 7, "value": 3}, {"source": 14, "target": 21, "value": 6}, {"source": 53, "target": 38, "value": 2}, {"source": 24, "target": 24, "value": 5}, {"source": 1, "target": 15, "value": 1}, {"source": 43, "target": 8, "value": 3}, {"source": 19, "target": 50, "value": 2}, {"source": 3, "target": 37, "value": 1}, {"source": 32, "target": 31, "value": 1}, {"source": 38, "target": 35, "value": 3}, {"source": 25, "target": 39, "value": 1}, {"source": 4, "target": 40, "value": 5}, {"source": 15, "target": 49, "value": 6}, {"source": 12, "target": 14, "value": 2}, {"source": 53, "target": 50, "value": 3}, {"source": 20, "target": 49, "value": 6}, {"source": 31, "target": 37, "value": 4}, {"source": 6, "target": 56, "value": 2}, {"source": 53, "target": 48, "value": 5}, {"source": 13, "target": 7, "value": 6}, {"source": 16, "target": 57, "value": 4}, {"source": 56, "target": 20, "value": 2}, {"source": 26, "target": 6, "value": 2}, {"source": 16, "target": 8, "value": 3}, {"source": 46, "target": 51, "value": 3}, {"source": 29, "target": 42, "value": 1}, {"source": 7, "target": 18, "value": 5}, {"source": 16, "target": 10, "value": 5}, {"source": 14, "target": 56, "value": 1}, {"source": 48, "target": 45, "value": 3}, {"source": 38, "target": 53, "value": 2}]}

  [1]: https://gist.github.com/2522963