wasserholz
wasserholz

Reputation: 2433

d3.js version 4 - rect zoom - cannot get the transformation right

d3.js verison 4: I have a line chart, which should have a rectangle zoom. I used this example: http://bl.ocks.org/jasondavies/3689931

I don't want to apply the rectangle data to the scales, like in the example

Instead I want to apply this to my normal zoom Element.

For that I have the math:

.on("mouseup.zoomRect", function() {
        d3.select(window).on("mousemove.zoomRect", null).on("mouseup.zoomRect", null);
        d3.select("body").classed("noselect", false);
        var m = d3.mouse(e);
        m[0] = Math.max(0, Math.min(width, m[0]));
        m[1] = Math.max(0, Math.min(height, m[1]));
        if (m[0] !== origin[0] && m[1] !== origin[1]) {

          //different code here

          //I have the scale factor
          var zoomRectWidth = Math.abs(m[0] - origin[0]);
          scaleFactor = width / zoomRectWidth;

          //Getting the translation
          var translateX = Math.min(m[0], origin[0]);

          //Apply to __zoom Element
          var t = d3.zoomTransform(e.node());
          e.transition()
                            .duration(that.chart.animationDuration)
                            .call(that.chart.zoomX.transform, t
                                .translate(translateX, 0)
                                .scale(scaleFactor)
                                .translate(-translateX, 0)
                            );
        }
        rect.remove();
        refresh();
      }, true);

So I actually get the scaleFactor right and it zooms in smoothly. Only problem is, that I don't seem to get the translation correct. So it zooms in to the wrong position.

Upvotes: 0

Views: 693

Answers (1)

wasserholz
wasserholz

Reputation: 2433

So, now I got it right: All transformations by earlier zooms need to be undone.

so that k = 1, x = 0, y = 0; This is the d3.zoomIdentity. From that point the current zoom needs to be applied and afterwards the translation.

After that the old transform needs to be applied, first translate and then scale

var t = d3.zoomTransform(e.node());

//store x translation
var x = t.x;

//store scaling factor
var k = t.k;

//apply first rect zoom scale and then translation
//then old translate and old zoom scale
e.transition()
  .call(that.chart.zoomX.transform, d3.zoomIdentity
  .scale(scaleFactor)
  .translate(-translateX, 0)
  .translate(x)
  .scale(k)
);

Working Fiddle only for X-Axis here: https://jsfiddle.net/9j4kqq1v/3/

Working fiddle for X and Y-axis here: https://jsfiddle.net/9j4kqq1v/5/

Upvotes: 1

Related Questions