111
111

Reputation: 1918

d3/cola programmatic node drag using initMouseEvent

I need to mock a mouse drag event in the browser to drag a d3 force node. I'm using this as a workaround for a constraint bug the WebCola force layout solver.

Cola home page: http://marvl.infotech.monash.edu/webcola/

A similar question was asked before but not answered satisfactorily for my application How to programmatically trigger a D3 drag event?

Here is what I have so far:

http://jsfiddle.net/7oc0ez6q/14/

mouse events do seem to be working on some level, but not how I want. What I expect from the following code is that on each tick, each node should be dragged a few pixels in x and y, since the xTest and yTest values are incremented.

Instead what I see is that when the mouse moves into the resulting frame, only one of the nodes moves unexpectedly in a circle. There's obviously something I'm not understanding about how to use these fake mouse events.

Thanks for your help.

var graph = {
  "nodes": [{
      "name": "a",
      "width": 60,
      "height": 40
    },
    {
      "name": "b",
      "width": 70,
      "height": 190
    },
    {
      "name": "c",
      "width": 60,
      "height": 40
    },
    {
      "name": "d",
      "width": 60,
      "height": 80
    },
    {
      "name": "e",
      "width": 60,
      "height": 40
    }
  ],
  "links": [{
      "source": 1,
      "target": 2
    },
    {
      "source": 2,
      "target": 0
    },
    {
      "source": 2,
      "target": 3
    },
    {
      "source": 2,
      "target": 4
    }
  ],
  "constraints": [{
      "type": "alignment",
      "axis": "x",
      "offsets": [{
          "node": "1",
          "offset": "0"
        },
        {
          "node": "2",
          "offset": "0"
        },
        {
          "node": "3",
          "offset": "0"
        }
      ]
    },
    {
      "type": "alignment",
      "axis": "y",
      "offsets": [{
          "node": "0",
          "offset": "0"
        },
        {
          "node": "1",
          "offset": "0"
        },
        {
          "node": "4",
          "offset": "0"
        }
      ]
    }
  ]
}


var width = 350,
  height = 320

var color = d3.scale.category20();

var d3cola = cola.d3adaptor()
  .linkDistance(120)
  .avoidOverlaps(true)
  .size([width, height]);

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

graph.nodes.forEach(function(v) {
  v.x = 400, v.y = 50
});
d3cola
  .nodes(graph.nodes)
  .links(graph.links)
  .constraints(graph.constraints)
  .start(10, 10, 10);

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


var node = svg.selectAll(".node")
  .data(graph.nodes)
  .enter().append("rect")
  .attr("class", "node")
  .attr("width", function(d) {
    return d.width;
  })
  .attr("height", function(d) {
    return d.height;
  })
  .attr("rx", 5).attr("ry", 5)
  .style("fill", function(d) {
    return color(1);
  })
  .call(d3cola.drag);



var label = svg.selectAll(".label")
  .data(graph.nodes)
  .enter().append("text")
  .attr("class", "label")
  .text(function(d) {
    return d.name;
  })
  .call(d3cola.drag);

node.append("title")
  .text(function(d) {
    return d.name;
  });

var xTest = 1;
var yTest = 1;

d3cola.on("tick", function() {

  xTest += 5;
  yTest += 5;

  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("x", function(d) {
      return d.x - d.width / 2;
    })
    .attr("y", function(d) {
      return d.y - d.height / 2;
    });

  label.attr("x", function(d) {
      return d.x;
    })
    .attr("y", function(d) {
      var h = this.getBBox().height;
      return d.y + h / 4;
    });

  progDrag();

});

function progDrag() {

  var evObjStart = document.createEvent('MouseEvents');
  var evObj = document.createEvent("MouseEvents");
  var evObjEnd = document.createEvent("MouseEvents");

  node.each(function(el) {

    console.log(evObj);

    evObjStart.initMouseEvent("mousedown", true, true, window, 1, xTest, yTest, xTest, yTest, false, false, false, false, 0, null);
    evObj.initMouseEvent("mousemove", true, true, window, 1, xTest, yTest, xTest, yTest, false, false, false, false, 0, null);
    //evObjEnd.initMouseEvent("mouseup", true, true, window, 1, xTest, yTest, xTest, yTest, false, false, false, false, 0, null);

    this.dispatchEvent(evObjStart);
    this.dispatchEvent(evObj);
    //this.dispatchEvent(evObjEnd);

  });

}
svg {
  border: 1px dotted #000;
}

.node {
  stroke: #fff;
  stroke-width: 1.5px;
  cursor: move;
}

.link {
  stroke: #999;
  stroke-width: 3px;
  stroke-opacity: 1;
}

.label {
  fill: white;
  font-family: Verdana;
  font-size: 25px;
  text-anchor: middle;
  cursor: move;
}

.guideline {
  stroke: orangered;
  stroke-width: 4px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="http://marvl.infotech.monash.edu/webcola/cola.min.js"></script>
<div id="content"></div>

Upvotes: 0

Views: 943

Answers (1)

Aayush Gaur
Aayush Gaur

Reputation: 104

You can create a custom mouse event using the following function

function createCustomMouseEvent (type,x,y) {
    var event = document.createEvent("MouseEvents");
    event.initMouseEvent(type, true, (type != "mousemove"), window, 0, x, y, x, y, false, false, false, false, 0, document.body.parentNode);
    return event;
}

and then d3 to select the element and dispatch the mousedown, mousemove and mouseup events to programmatically implement the drag functionality

var node = d3.select('.node').node();
var x = 0.1, y = 0.1;
node.dispatchEvent(createCustomMouseEvent('mousedown', x,y,false));
node.dispatchEvent(createCustomMouseEvent('mousemove', x,y,false));
node.dispatchEvent(createCustomMouseEvent('mouseup', x,y,false));

Upvotes: 2

Related Questions