2

I use a transform when panning, copied from several examples.

zoom = d3.behavior.zoom()
    .x(this.xScale)
    .scaleExtent([0.5, 2])
    .on("zoom", zoomFunction(this))
    .on("zoomend", zoomEndFunction(this));

svg = histogramContainer.append("svg")
    .attr('class', 'chart')
    .attr('width', width)
    .attr('height', height)
    .call(zoom)
    .append('g')
    .attr('transform', 'translate(' + this.margin.left  + ' , ' +
            (height - this.margin.bottom) + ')');

function zoomFunction(scope) {
    return function() {
        var that = scope;

        that.xDelta = d3.event.translate[0];
        that.zoomScale = d3.event.scale;

        // some other code removed for simplicity

        svg.selectAll(".stackedBar").attr("transform", "translate(" +
                                that.xDelta + ",0)scale(" +
                                that.zoomScale + ", 1)");
    };
}

The problem is that since new elements enter after the pan then 'old' elements have the transform attribute applied but the new elements don't.

This breaks future panning because the old elements will be transformed from where the pre-zoom xScale drew them while the new elements will be transformed from the zoom-adjusted xScale.

It seems to me that I could redraw the old elements with the zoom-adjusted xScale, though I'm unsure when and how to do that "behind the scenes".

Alternatively I could draw the new elements with the old xScale and apply the same transform on them that the old elements have. This seems messier since elements will come and go and I'll have to keep track of the 'current transform'. My gut tells me "too much state".

ari gold
  • 2,074
  • 3
  • 25
  • 51

1 Answers1

2

Usually if you're attaching a scale to the zoom behaviour, you use the modified scale to redraw the bars using the exact same code as how you position the bars initially, letting the scales do all the work.

I linked to this discussion in my previous answer, so you might have read it by now; if not, it might be a good start for getting your head around the different ways of approaching zooming in d3; it breaks down the each method step-by-step. You're currently using a mix of two approaches (transforms versus scales), and I think that's causing problems keeping track.

Community
  • 1
  • 1
AmeliaBR
  • 27,344
  • 6
  • 86
  • 119
  • Goodness gracious I just read that other answer.. you should write a book. Two actually, one for data visualization and the other should probably be an autobiography. FWIW, I'm doing another type of zoom (maybe) as I mention in [this question](http://stackoverflow.com/questions/20155844/d3-zoom-into-data-not-image-in-bar-chart-or-histogram). Basically, deeper into the data. I've actually got it working quite nicely (by parsing arrays before I pass them to D3) so I'll answer that pronto. Thanks. – ari gold Mar 15 '14 at 04:11
  • I'm still trying to figure out how & when to redraw the elements with the new xScale. Maybe on 'zoomend'? Interestingly I think I'll need a `redrawChart` function in addition to my `drawChart` and `updateChart` functions since I don't want to join the old data to new but rather "refresh" it (to remove the transforms). – ari gold Mar 15 '14 at 04:18
  • Also, FWIW, I used both transform and scales to give the user visual feedback. Then I'd redraw the entire chart, after re-binning the data (on zoom, not pan). Now that I'm going for transitions with data joins I have to rework all of this.. In any event, that was my thinking (potentially incorrect) for using both - to explode or shrink the SVG to give the user feedback. – ari gold Mar 15 '14 at 04:22
  • 1
    There's nothing wrong with having a quick-zoom function using transforms. However, it would be easier to put all the graphics in a `` element and transform that, instead of transforming each rectangle. That way the transform would by default apply to any new elements added to the group, and you don't throw off your scale positions. (Although you still might want to reset the zoom after update so the user can clearly see any changed data.) – AmeliaBR Mar 15 '14 at 17:10