2013-09-01 79 views
17

d3.behavior.zoom()によってレイアウトが変換された後にノードの画面位置を取得しようとしていますが、運があまりありません。レイアウトを翻訳してスケーリングした後に、ノードの実際の位置をウィンドウで取得するにはどうすればよいですか?変換後のD3ノードの画面位置の取得

mouseOver = function(node) { 
    screenX = magic(node.x); // Need a magic function to transform node 
    screenY = magic(node.y); // positions into screen coordinates. 
}; 

ガイダンスをいただければ幸いです。

EDIT:上のノードは強制レイアウトノードなので、xおよびyプロパティはシミュレーションによって設定され、シミュレーションの実行後にはどのタイプの変換が適用されるかにかかわらず一定のままです。

EDIT:私がSVGを変換するために使用している戦略は、d3のズーム動作(ここではSVG Geometric Zooming)に基づいています。

var svg = d3.select("body").append("svg") 
    .attr("width", width) 
    .attr("height", height) 
    .append("g") 
    .call(d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom)) 
    .append("g"); 

svg.append("rect") 
    .attr("class", "overlay") 
    .attr("width", width) 
    .attr("height", height); 

svg.selectAll("circle") 
    .data(data) 
    .enter().append("circle") 
    .attr("r", 2.5) 
    .attr("transform", function(d) { return "translate(" + d + ")"; }); 

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

これはかなり簡単です。 d3のズーム動作は、パンとズームのイベントをハンドラに渡します。ハンドラは、transform属性を使用してコンテナ要素にトランスフォームを適用します。

EDIT:ノード座標の代わりにマウス座標を使用して問題を回避しています。なぜなら、ノードがマウスポインタで覆われているときにノード位置に興味があるからです。それはまさに私が後にしている行動ではありませんが、それは大部分のために働き、何よりも優れています。

EDIT:解決策は、element.getCTM()を使用してsvg要素の現在の変換行列を取得し、それを使用してx座標とy座標をスクリーン相対状態にオフセットすることでした。下記参照。

+0

SVG要素[基本データ型](http://www.w3.org/TR/SVG/types.html#__svg__SVGLocatable__getCTM)のgetCTM()および/またはgetScreenCTM()を使用して何かを行う必要があると思われます。 )。 Inverse(tm)やそのような関数のような、それらの関数によって返された行列を操作するヘルパーメソッドがあるかどうか疑問に思っています。 –

答えて

7

transformが適用された後に、node.getBBox()を試して、ノードシェイプの周囲にタイトなバウンディングボックスのピクセル位置を取得できます。詳しくはlinkをご覧ください。

EDIT:

getBBoxは私が思っかなりのように動作しません。矩形は変換された座標空間で定義されているため、親との相対座標は常に<g>であるため、含まれる図形の場合は常に同じになります。

element.getBoundingClientRectと呼ばれる別の機能が広くサポートされているように見え、ブラウザビューポートの左上を基準にピクセル位置に矩形を戻します。それは、変換行列を直接混乱させることなく、あなたが望むものに近づけるかもしれません。

+0

リンクありがとうございます。このドキュメントでは、getBBox()はポストトランスフォームだと言いますが、el.getBBox()。xとel.getBBox()。yの場合と同じnode.xとnode.yの座標を取得しています。注意すべき点として、 'node'は選択データの一部である強制レイアウトノードです。 –

+0

getBBoxが呼び出されたときに要素に適用される変換は何ですか? –

+0

あなたの質問に答えるために投稿を編集しました。コンテナのトランスフォームアトリビュートを使用してトランスレートとスケール変換を適用しています。 [SVG Geometric Zooming](http://bl.ocks.org/mbostock/3680999) –

21

私の元の質問に対する解決策は、このようなものになります表示されます:

(。回転変換をサポートするように更新)

// The magic function. 
function getScreenCoords(x, y, ctm) { 
    var xn = ctm.e + x*ctm.a + y*ctm.c; 
    var yn = ctm.f + x*ctm.b + y*ctm.d; 
    return { x: xn, y: yn }; 
} 

var circle = document.getElementById('svgCircle'), 
cx = +circle.getAttribute('cx'), 
cy = +circle.getAttribute('cy'), 
ctm = circle.getCTM(), 
coords = getScreenCoords(cx, cy, ctm); 
console.log(coords.x, coords.y); // shows coords relative to my svg container 

代わりに、これはから翻訳し、スケールのプロパティを使用してもを行うことができますd3.event(回転変換が必要とされていない場合):

// This function is called by d3's zoom event. 
function zoom() { 

// The magic function - converts node positions into positions on screen.  
function getScreenCoords(x, y, translate, scale) { 
    var xn = translate[0] + x*scale; 
    var yn = translate[1] + y*scale; 
    return { x: xn, y: yn }; 
} 

// Get element coordinates and transform them to screen coordinates. 
var circle = document.getElementById('svgCircle'); 
cx = +circle.getAttribute('cx'), 
cy = +circle.getAttribute('cy'), 
coords = getScreenCoords(cx, cy, d3.event.translate, d3.event.scale); 
console.log(coords.x, coords.y); // shows coords relative to my svg container 

    // ... 
} 

編集:私は、関数の下のフォームは、最も有用かつ汎用的であることが判明し、 getBoundingClientRectが倒れているように見えます。具体的には、D3フォースレイアウトプロジェクトで正確なSVGノードの位置を取得しようとしたときに、getBoundingClientRectが不正確な結果を生成しましたが、以下のメソッドは複数のブラウザにわたって要素の正確な中心座標circleを返しました。

(回転変換をサポートするために更新しました。)

// Pass in the element and its pre-transform coords 
function getElementCoords(element, coords) { 
    var ctm = element.getCTM(), 
    x = ctm.e + coords.x*ctm.a + coords.y*ctm.c, 
    y = ctm.f + coords.x*ctm.b + coords.y*ctm.d; 
    return {x: x, y: y}; 
}; 

// Get post-transform coords from the element. 
var circle = document.getElementById('svgCircle'), 
x = +circle.getAttribute('cx'), 
y = +circle.getAttribute('cy'), 
coords = getElementCoords(circle, {x:x, y:y}); 

// Get post-transform coords using a 'node' object. 
// Any object with x,y properties will do. 
var node = ..., // some D3 node or object with x,y properties. 
circle = document.getElementById('svgCircle'), 
coords = getElementCoords(circle, node); 

機能は、DOM要素の変換行列を取得し、その後、行列の回転を使用して動作規模、および変換後戻すための情報を翻訳指定されたノードオブジェクトの座標。

+1

ありがとう、これは私の一日を作った、私は解決策のために何時間もインターネットを探していた。 –

+1

Hum、回転機能が正しく適用されても、この機能はまだ動作しませんか? ctm.bとctm.cを使用して座標を変換していないためです。 – Overdrivr

+0

getElementCoords()関数にローテーション変換を適用する方法を知っていますか? – poliu2s

関連する問題