1

The full code is visible and modifiable on observablehq

The relevant parts:

  const columns = svg.selectAll("g")
                    .data(nested_city)
                    .enter()
                    .append("g")
                    .attr("city", function(d) { return d.key ;})
                    .attr("x",  function(d) { return x(d.key) ;})
                    .attr("y", "0")
                    .attr("transform",  function(d) { return "translate(" + x(d.key) + ",0)" ;})
                    .attr("class", "column")
                   .on("mouseover", function(d) {
                      d3.select(this)
                        .style("cursor","pointer");
                  })
                  .on("mouseout", function(d){
                    d3.select(this)
                      .style("cursor","default");
                  })
                    .call(d3.drag()
                    .subject(function() { 
                            var t = d3.select(this);
                            var tr = getTranslation(t.attr("transform"));
                            return {x: t.attr("x") + tr[0],
                                    y: t.attr("y") + tr[1]};
                     })
                    .on("start", dragstarted)
                    .on("drag", dragged)
                    .on("end", dragended)); 

and the drag handlers:

      function dragstarted(d) {
       
        d3.select(this).raise().classed("active", true);
      }

      function dragged(d) {
         
          d3.select(this).attr("transform", function(d,i){
            var coordinates = d3.mouse(this);
            var mx = coordinates[0]
            console.log( coordinates[0])
                return "translate(" + [mx,0] + ")"})
      }

      function dragended(d) {
        d3.select(this).classed("active", false);
      }

I'm trying to adapt the new drag and drop with translation (found here on SO) for d3 v4 version to my example on observableHQ, without success.

I have a very strange flickering behavior when i drag any of the two column (alternate between jump with old x values and new x values).

If you have any idea why ?

blackgreen
  • 34,072
  • 23
  • 111
  • 129
reyman64
  • 523
  • 4
  • 34
  • 73

1 Answers1

3

There is a d3.mouse(this) statement in the dragged() function. This returns the x and y coordinates of the current event relative to the specified Container (ref). Your container for mouse(<container>) is this and means the dragged <g> the element. But it should be the <svg>. Therefore you should use d3.mouse(svg.node()) instead.

But be careful, since you haven't taken the offset inside the <g> into account (it's hard to describe). Maybe you have to add the coordinates of the cursor position inside the <g>.

IMHO I would anyway prefere to use d3.event over d3.mouse example.

Edit: New drag functions with correct coordinates

// New: Coordinates inside <g>
var coordG = 0;

function dragstarted(d) {

    // New: Read out coordinates inside <g>
    coordG = d3.mouse(this)[0];
    d3.select(this).raise().classed("active", true);
}

function dragged(d) {
    d3.select(this).attr("transform", function(d,i){
        var coordinates = d3.mouse(svg.node());
        var mx = coordinates[0] - coordG;
        console.log( coordG);
        return "translate(" + [mx,0] + ")";
    });
 }

 function dragended(d) {
     d3.select(this).classed("active", false);
 }
roland
  • 900
  • 12
  • 25
  • Thanks, i first try using the d3.event, but the x and y retourned by d3 was very weird, and i don't understand why – reyman64 Aug 08 '18 at 12:12
  • @reyman64: Get the translation (with your `getTranslation()`) and add `d3.event.dx`. But this is only my preference. If `d3.mouse` work for you, just go with it. – roland Aug 08 '18 at 12:59