5

当我用鼠标缩放时,myZoom将执行以下附加的功能:

myZoom.on('zoom', function() {

    someElement.attr('transform', 'translate(' + d3.event.translate[0] + ',' + d3.event.translate[1] + ') scale(' + d3.event.scale + ')');

....
// redraw axes, which should stay where they are at.
....

}

要在没有鼠标或其他指针设备的情况下模拟缩放,我只需更改上面的属性“transform”的值。简单的。

但问题是在这个函数中我实际上重绘了轴,它的比例是自动重新计算的。请参阅 d3 中的此官方文档:

缩放.y([y])

指定缩放时应自动调整其域的 y 比例。如果未指定,则返回当前的 y 比例,默认为 null。如果以编程方式修改了比例的域,则应将其重新分配给缩放行为。

我需要以编程方式缩放(可能使用缩放按钮)。如何触发缩放事件,以便自动重新计算轴的比例?

4

4 回答 4

6

程序化缩放在 D3 库中似乎是一项艰巨的任务,因为 D3 缩放与鼠标事件密切相关。程序化缩放的一个常见实例是使用滑块控件放大或缩小。令人惊讶的是,我找不到一个工作示例来说明如何使用滑块控件使 D3 缩放工作。在投入了一些时间和精力后,我开发了这个工作演示,可以在这里找到D3SliderZoom。关键是使用滑块抛出的比例值更改嵌入“<svg>”元素中的“<g>”SVGElement 的转换属性。

function zoomWithSlider(scale) {
    var svg = d3.select("body").select("svg");
    var container = svg.select("g");
    var h = svg.attr("height"), w = svg.attr("width");

    // Note: works only on the <g> element and not on the <svg> element
    // which is a common mistake
    container.attr("transform",
            "translate(" + w/2 + ", " + h/2 + ") " +
            "scale(" + scale + ") " +
            "translate(" + (-w/2) + ", " + (-h/2) + ")");

}

然后必须从滑块的更改事件调用此方法,如下所示。

$(function() {
$( "#slider-vertical" ).slider({
    orientation: "vertical",
    range: "min",
    min: 1000,
    max: 10000,
    value: 1000,
    slide: function( event, ui ) {
        zoomWithSlider(ui.value/1000);
    }
});

});

这个解决方案比生成伪鼠标滚动事件要优雅得多。

于 2013-11-13T18:38:06.237 回答
2

我最终自己为新的缩放级别计算了新域。有了这个新域,我可以重新绘制两个 y 轴。对于有同样问题的人,我发布了我的代码。它对我的项目非常具体,因此可能很难理解。只是为了你的兴趣。

wr.zoomSim = function(sNew) {

    var s = wr.zoom.scale(),
        tx = wr.zoom.translate()[0],
        ty = wr.zoom.translate()[1],
        sReal = sNew / s,
        dtx = wr.width / 2 * (1 - sReal),
        dty = wr.height / 2 * (1 - sReal),
        txNew = sReal * tx + dtx,
        tyNew = sReal * ty + dty,

        a = wr.scaleYBZoom.domain()[0],
        b = wr.scaleYBZoom.domain()[1],
        c = wr.scaleYBZoom.range()[0],
        d = wr.scaleYBZoom.range()[1],
        r = (b-a)/(d-c);

    wr.scaleYBZoom.domain([a + r * ( (c - dty) / sReal - c), a + r * ( (d - dty) / sReal - c)]);

    wr.zoom.scale(sNew);
    wr.zoom.translate([txNew, tyNew]);

    wr.svg2.select('g#bar')
            .attr('transform', 'translate(' + txNew + ',' + tyNew + ') scale(' + sNew + ')');

    wr.svg2.select('g#axisl')
            .call(d3.svg.axis().scale(wr.scaleYBZoom).orient('left'))
        .selectAll('line.tick')
            .attr('x2', wr.width - wr.bar.left - wr.bar.right + 2 * wr.padding);
    wr.svg2.select('g#axisr')
            .call(d3.svg.axis().scale(wr.scaleYBZoom).orient('right'))
        .selectAll('line')
            .remove();

};
于 2012-11-07T11:46:09.760 回答
2

不幸的是,@Debasis 的回答对我不起作用,因为我想通过我已经在force layout中使用的缩放行为来实现这一点。经过两天的绝望,我终于在这个帖子中找到了解决方案:

https://groups.google.com/forum/#!msg/d3-js/qu4lX5mpvWY/MnnRMLz_cnUJ

function programmaticZoom ($svg, $zoomContainer, zoomBehavior, factor) {

    var width = $svg.attr('width');
    var height = $svg.attr('height');

    var newScale = zoomBehavior.scale() * factor;
    var newX = (zoomBehavior.translate()[0] - width / 2) * factor + width / 2;
    var newY = (zoomBehavior.translate()[1] - height / 2) * factor + height / 2;

    zoomBehavior
      .scale(newScale)
      .translate([newX,newY])
      .event($zoomContainer);
}
于 2014-10-10T13:13:23.747 回答
0

我通过使用 zoomListener 来做到这一点。对我来说,在简单的步骤中效果很好:

  1. 定义 zoomListener: var zoomListener = d3.behavior.zoom();
  2. 调用缩放监听器 d3.select(the-element-that-you-need-zoom-on).call(zoomListener);
  3. 决定你的缩放步长。我采取了0.1的步骤。(放大使用 1.1,缩小使用 0.9)
  4. 乘以当前缩放比例 var newScale = zoomListener.scale() * step;
  5. 设置新的缩放值 zoomListener.scale(newScale);
于 2017-01-25T23:11:32.930 回答