d3 / d3-zoom

Pan and zoom SVG, HTML or Canvas using mouse or touch input.
https://d3js.org/d3-zoom
ISC License
507 stars 143 forks source link

Request d3v5: simpler function and examples for zoom in/center/zoom out without a mouse wheel #159

Closed Talador12 closed 5 years ago

Talador12 commented 5 years ago

I have three buttons that need to smoothly zoom in, zoom center, and zoom out. For the life of me, I cannot find a way to do zoom in/out in v5 without a mouse wheel. The d3 mouse wheel event makes zooming trivial, but we have to support zoom buttons as well on my product. I have found an example of what I am trying to do for zoom in/out, but this is a v3 example that does not work in v5 even when converted. Finding a v5 example for this and many other d3 features has been troubling to say the least.

d3v3 example with functioning buttons similar to what I am looking for http://bl.ocks.org/linssen/7352810

My code for reference (Typescript)

setZoom(dx, dy) {
    this.dx = dx;
    this.dy = dy;
    this.zoom = d3.zoom()
      .extent([[dx - 390, dy - 390], [dx + 390, dy + 390]])
      .on('zoom', () => {
        localStorage['scale'] = d3.event.transform.k;
        this.svg.attr('transform', d3.event.transform);
      });

    d3.select(this.id + 'zoom_center').on('click', () => {
      localStorage['scale'] = 1;
      this.zoomCenter(750, 0);
    });

    d3.select(this.id + 'zoom_in').on('click', () => {
      localStorage['scale'] = localStorage['scale'] / .75;
      const offset = -175 * Math.pow(localStorage['scale'], 1);
      this.zoomCenter(500, offset);
    });

    d3.select(this.id + 'zoom_out').on('click', () => {
      localStorage['scale'] = localStorage['scale'] * .75;
      const offset = 175 / Math.pow(localStorage['scale'], 1);
      this.zoomCenter(500, offset);
    });
    this.baseSvg.call(this.zoom);
    this.zoomCenter(750, 0);
  }

  zoomCenter(duration, offset) {
    this.baseSvg.transition().duration(duration).call(this.zoom.transform as any,
      d3.zoomIdentity.translate(offset, this.dy / 2.5).scale(localStorage['scale']));
  }
milnerm commented 5 years ago

Second this - all I want is a slider input to call the same action as the mouse wheel event. I can't get the contraints to set in the same way. I'm using zoom.scaleTo, and storing the scale

currentScale=$(this).slider("value"); svg.call(zoom.scaleTo,currentScale);

Looks like this line zoom.js 249 is what I'm after, but have no clue as to how to call it: g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));

If I set extent to the full width and height of the svg, it doens't seem to work either.

zoom = d3.zoom()
        .scaleExtent([0.1, 4])
        .extent([[0, 0], [cfg.w, cfg.h]])
        .on("zoom",function(){

It scales fine, but the translation is strange - mousewheel scales the x,y appropriately (the way I want), while scaleTo alters it - the result is that the vizualization creeps across the page as the user zooms in and out. I've also tried scaleBy, which doesn't work.

Long and short - I want to call the wheelzoom functionality, and have the same results using a slider. Doesn't seem to be a way to do this, and as per the above, loads of examples in v3, little in v5.

mbostock commented 5 years ago

Here’s a simple example of using zoom.scaleBy:

https://observablehq.com/@d3/programmatic-zoom

mbostock commented 5 years ago

Also see #178 for some proposed convenience methods.