d3js: Use view port center for zooming focal point

前端 未结 3 628
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-07 01:53

We are trying to implement zoom buttons on top of a map created in D3 - essentially as it works on Google maps. The zoom event can be dispatched programmatically using

3条回答
  •  自闭症患者
    2021-01-07 02:21

    I've recently had to do the same thing, and I've got a working example up here http://bl.ocks.org/linssen/7352810. Essentially it uses a tween to smoothly zoom to the desired target scale as well as translating across by calculating the required difference after zooming to centre.

    I've included the gist of it below, but it's probably worth looking at the working example to get the full effect.

    html

    
    
    

    js

    var zoom = d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoomed);
    
    function zoomed() {
        svg.attr("transform",
            "translate(" + zoom.translate() + ")" +
            "scale(" + zoom.scale() + ")"
        );
    }
    
    function interpolateZoom (translate, scale) {
        var self = this;
        return d3.transition().duration(350).tween("zoom", function () {
            var iTranslate = d3.interpolate(zoom.translate(), translate),
                iScale = d3.interpolate(zoom.scale(), scale);
            return function (t) {
                zoom
                    .scale(iScale(t))
                    .translate(iTranslate(t));
                zoomed();
            };
        });
    }
    
    function zoomClick() {
        var clicked = d3.event.target,
            direction = 1,
            factor = 0.2,
            target_zoom = 1,
            center = [width / 2, height / 2],
            extent = zoom.scaleExtent(),
            translate = zoom.translate(),
            translate0 = [],
            l = [],
            view = {x: translate[0], y: translate[1], k: zoom.scale()};
    
        d3.event.preventDefault();
        direction = (this.id === 'zoom_in') ? 1 : -1;
        target_zoom = zoom.scale() * (1 + factor * direction);
    
        if (target_zoom < extent[0] || target_zoom > extent[1]) { return false; }
    
        translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k];
        view.k = target_zoom;
        l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y];
    
        view.x += center[0] - l[0];
        view.y += center[1] - l[1];
    
        interpolateZoom([view.x, view.y], view.k);
    }
    
    d3.selectAll('button').on('click', zoomClick);
    

提交回复
热议问题