2

D3 で作成されたマップの上にズーム ボタンを実装しようとしています - 基本的に Google マップで動作するように。ズーム イベントは、次を使用してプログラムでディスパッチできます。

d3ZoomBehavior.scale(myNewScale);
d3ZoomBehavior.event(myContainer);

マップは、ビューの現在の翻訳を使用してズームします。ズーム ボタンを使用する場合、焦点 (ズームの中心) は移動ではなく、ビュー ポートの中心になります。スクロール ホイールを使用してズームする場合は、使用するオプションがありますがzoom.center、独自のイベントをディスパッチする場合、これは明らかに効果がありません。

新しいスケーリング係数とビューポートの中心を考慮して、次の変換を計算する方法について混乱しています。

現在の縮尺、次の縮尺、現在の平行移動、およびマップ ビュー ポートの寸法がわかっている場合、ビュー ポートの中心が変わらないように次の平行移動を計算するにはどうすればよいですか?

4

3 に答える 3

11

私は最近同じことをしなければならなかっ. 基本的に、トゥイーンを使用して目的のターゲット スケールにスムーズにズームし、中心にズームした後に必要な差を計算して変換します。

その要点を以下に示しますが、完全な効果を得るには、実際のを見る価値があるでしょう。

html

<button id="zoom_in">+</button>
<button id="zoom_out">-</button>

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);
于 2013-11-07T11:08:28.010 に答える
3

これを実際に行うのは非常に難しいことがわかりました。ここで採用したアプローチは、ズーム ボタンが使用されたときにズームをトリガーするマウス イベントを単純に作成することです。このイベントは、マップの中央に作成されます。

関連するコードは次のとおりです。

.on("click", function() {
                var evt = document.createEvent("MouseEvents");
                evt.initMouseEvent(
                  'dblclick', // in DOMString typeArg,
                   true,  // in boolean canBubbleArg,
                   true,  // in boolean cancelableArg,
                   window,// in views::AbstractView viewArg,
                   120,   // in long detailArg,
                   width/2,     // in long screenXArg,
                   height/2,     // in long screenYArg,
                   width/2,     // in long clientXArg,
                   height/2,     // in long clientYArg,
                   0,     // in boolean ctrlKeyArg,
                   0,     // in boolean altKeyArg,
                   (by > 0 ? 0 : 1),     // in boolean shiftKeyArg,
                   0,     // in boolean metaKeyArg,
                   0,     // in unsigned short buttonArg,
                   null   // in EventTarget relatedTargetArg
                );
                this.dispatchEvent(evt);
            });

全体は少しハックですが、実際には機能し、すべてのオフセット/ズームの正しい中心を計算するよりもはるかに簡単であることがわかりました。

于 2013-08-28T13:45:00.077 に答える