2012-11-21 17 views
6

マウスホイールを使用してユーザーがスクロールしたりズームアウトしたりするときにズームの速度を調整できますか?D3でズームイン/ズームアウトするときの変換速度とスケールの変更方法(zoom.on&d3.event.translate、d3.event.zoomを使用)?

私の理解がzoom.on(https://github.com/mbostock/d3/wiki/Zoom-Behavior#wiki-on)リスナーは、2つのイベントが& d3.event.zoomをd3.event.translate生成行列を含有するか、変換またはスケール関数に渡されたとき、パンニング可能にすること座標とすることですグラフィックの再スケーリング。

しかし、私はどのようにこれをスピードアップするので、ユーザーがマウスホイールを少し動かすと、彼女は急速にズームインまたはズームアウトします。私は大きな視覚化をして、ユーザーがマウスホイールを使って素早くズームイン/ズームアウトできるようにしたいと考えています。上記の既存のイベントや関数の引数を単に変更/追加することはできますか?自分で作成する必要はありますか?私は上記のうちのいくつかが理解の点で不正確であるという感情を持っているので、もしそうなら説明してください。

ここで非常に簡単なjsfiddle例:http://jsfiddle.net/fiddler86/6jJe6/、以下同じコードで:

var svg = d3.select("body").append("svg:svg") 
     .attr("width", 1000) 
     .attr("height", 2000)  
     .append("svg:g") 
      .call(d3.behavior.zoom().on("zoom", redraw)) 
     .append("svg:g"); 

svg.append("svg:rect") 
.attr("width", 200) 
.attr("height", 300) 
.attr("fill", 'green'); 

function redraw() { 
    svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); 
};  
+0

これを把握しましたか? – kishanio

+1

@kishanio解決策を提案しました –

答えて

5

あなたは機能を選択したときに重要なのはということは、x = 0である数学関数で、関数内のスケールを調整する必要がありますy = 0あなたはpowを使うことができます。この場合、Math.pow(d3.event.scale,.1)は2番目のパラメータが小さくなるとズームをゆっくり行います。

ブラウザが遅くなるので、非常に複雑な機能を使用するのは良い考えではありません。

新しい縮尺を作成したら、翻訳を再計算する必要があります。あなたは問題を複雑にしません。SVGでは実際の高さはthis.getBBox().heightですが、これはあと1回の反復であるため正確ではありません。あなたは(originalHeight * scale)で新しい高さを計算でき、(originalHeight - (originalHeight * scale))/2

  • まあorigialHeight *スケールはnewHeight

  • originalHeightあると翻訳 - newHeightが違いである、とあなたが センターをしたい、あなたは除算必要2の場合は正方形の半分、半分の場合は です。

  • ここでは、幅を指定してアクションを実行する必要があります。私が作成した

    ...私はハードコードされ、あなたがプロパティを使用することができます200と300を入れ

    var svg = d3.select("body").append("svg:svg") 
           .attr("width", 1000) 
           .attr("height", 2000)  
           .append("svg:g") 
            .call(d3.behavior.zoom().on("zoom", redraw)) 
           .append("svg:g"); 
    
        svg.append("svg:rect") 
         .attr("width", 200) 
         .attr("height", 300) 
         .attr("fill", 'green'); 
    
        function redraw() { 
         var velocity = 1/10; 
         var scale = Math.pow(d3.event.scale,velocity); 
         var translateY = (300 - (300 * scale))/2; 
         var translateX = (200 - (200 * scale))/2; 
    
         svg.attr("transform", "translate(" + [translateX,translateY] + ")" + " scale(" +scale+ ")");    
        }; 
    

    注意、一定の使用:それは同じ

コードですfiddler:http://jsfiddle.net/t0j5b3e2/

1

私はmbostockのdrag+zoom exampleを4倍のズーム速度に変更してに入れました210。私は以下に私の考えを説明した。これはスタックオーバーフローの答えで私の最初の試みです、よかったよ。

RaúlMartínの答えで説明したように、redraw()関数内の式を使用してズームのレートを変更することができます。 d3の動作が修正されたズームレートでうまく動作するように、いくつかの追加ステップを実行する必要があります。デフォルトのD3の動作によって選択された点(例えばカーソル)
を中心

ズーム例えば、マウスポインタのズームの焦点を合わせますマウスポインタが画像の左上にある場合、画像の中央ではなく左上にズームインします。この効果を得るには、画像を拡大/縮小し、マウスカーソルの下の点が画面上の同じ位置にとどまるように画像の平行移動も変更します。このため、画像が画面上を移動しているように見えなくても、マウスホイールをスクロールするとzoom.translate()の値が変わるのはこのためです。

ズーム速度を変更した場合、d3 zoom.translate()の値は正しくなりません。あなたは、以下の情報を(数値を無視)を知る必要があり、正しい翻訳ワークアウトするには:

var prev_translate = [100,100] // x, y translation of the image in last redraw 
var prev_scale = 0.1   // Scale applied to the image last redraw 
var new_scale = 0.4   // The new scale being applied 
var zoom_cp = [150, 150]  // The zoom "center point" e.g. mouse pointer 

を画像に適用するnew_translateをうまくするための式は次のようになります。

new_translate[0] = zoom_cp[0] - (zoom_cp[0] - prev_translate[0]) 
    * new_scale/prev_scale; 
new_translate[1] = zoom_cp[1] - (zoom_cp[1] - prev_translate[1]) 
    * new_scale/prev_scale; 

あなたはあなたはその後、prev_scale = new_scaleprev_translate = new_translateの準備を更新する必要があります

svg.attr("transform", "translate(" + new_translate + ")scale(" + new_scale + ")"); 

:とあなたの新しいスケールと一緒に画像にこれを適用することができます

D3ズーム動作をスケーリングせずにredraw()

パンの次の反復では、クリックしてドラッグすることにより、スケーリングせずにパンすることができます。クリックしてドラッグすると、zoom.scale()は同じままですが、変更はzoom.translate()になります。ズーム速度を変更した後でも、新しいzoom.translate()の値は正しいです。ただし、このzoom.translate()値を使用するタイミングと、中心点をズームインするために計算する変換値を使用するタイミングを知る必要があります。

prev_scalenew scaleと同じかどうかを調べることで、パンまたはズームが行われているかどうかを調べることができます。 2つの値が同じ場合、パンが発生していることがわかります。new_translate = zoom.translate()を使用してイメージを移動できます。そうでない場合は、ズームが行われていることがわかり、前述のようにnew_translateの値を計算できます。私はzoomstartイベントに関数を追加することでこれを行います。

var zoom_type = "?"; 
var scale_grad = 4; // Zoom speed multiple 
var intercept = 1 * (1 - scale_grad) 

var svg = d3.select("body").append("svg:svg") 
      .attr("width", 1000) 
      .attr("height", 2000)  
      .append("svg:g") 
       .call(d3.behavior.zoom() 
         .on("zoom", redraw) 
         .on("zoomstart", zoomstarted)) 
      .append("svg:g"); 

function zoomstarted() { 
    zoom_type = "?"; 
} 

function redraw() { 
    var scale = d3.event.scale; 

    // Use a linear scale, don't let it go below the minimum scale 
    // extent 
    var new_scale = Math.max(scale_grad * scale + intercept, 
         scale_extent[0]); 

    // If hit the minimum scale extent then stop d3 zoom from 
    // going any further 
    if (new_scale == scale_extent[0]) { 
     zoom.scale((scale_extent[0] - intercept)/scale_grad); 
    } 

    // Set up zoom_type if have just started 
    // If the scale hasn't changed then a pure translation is 
    // taking place, otherwise it is a scale 
    if (zoom_type == "?") { 
     if (new_scale == prev_scale) { 
      zoom_type = "translate" 
     } else { 
      zoom_type = "scale" 
     } 
    } 

    // zoom_cp is the static point during the zoom, set as 
    // mouse pointer position (you need to define a listener to track) 
    var new_translate = [0, 0]; 
    zoom_cp = [mouse_x, mouse_y]; 

    // If the event is a translate just apply d3 translate 
    // Otherwise calculate what translation is required to 
    // keep the zoom center point static 
    if (zoom_type == "translate") { 
     new_translate = d3.event.translate 
    } else if (zoom_type == "scale") { 
     new_translate[0] = zoom_cp[0] 
      - (zoom_cp[0] - prev_translate[0]) * new_scale/prev_scale; 
     new_translate[1] = zoom_cp[1] 
      - (zoom_cp[1] - prev_translate[1]) * new_scale/prev_scale; 
} 

     // Update the variables that track the last iteration of the 
     // zoom 
     prev_translate = new_translate; 
     prev_scale = new_scale; 
     zoom.translate(new_translate); 

     // Apply scale and translate behaviour 
     svg.attr("transform", "translate(" + new_translate + 
      ")scale(" + new_scale + ")"); 
}