2013-09-01 53 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. 
}; 

任何指導,將不勝感激。

編輯:上述「節點」是一個力佈局節點,所以它的x和y屬性是由仿真設置,並保持恆定的仿真達到靜止後,不管施加什麼類型的變換。

編輯:我使用的是改造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屬性將變換應用於容器元素。

編輯:我周圍的工作問題,通過使用鼠標的座標,而不是節點座標,因爲我很感興趣,當節點懸停鼠標指針的節點位置。這並不完全是我所追求的行爲,但它在大多數情況下都有效,而且勝於無。

編輯:解決的辦法是與獲得element.getCTM()svg元素的當前變換矩陣,然後用它來抵消x和y座標的畫面相對的狀態。見下文。

+0

我懷疑答案可能涉及到使用SVG元素的getCTM()和/或getScreenCTM()[基本數據類型](http://www.w3.org/TR/SVG/types.html#__svg__SVGLocatable__getCTM )。我想知道是否有輔助方法在由這些函數返回的矩陣上操作,例如Inverse(tm)或類似的效果。 –

回答

7

在應用任何transform之後,您可以嘗試node.getBBox()以獲取圍繞節點形狀的緊密邊界框的像素位置。請參閱這裏瞭解更多:link

編輯:

getBBox不工作很我以爲的方式。由於矩形是根據變換後的座標空間定義的,因此它總是相對於父項<g>,因此對於包含的形狀將始終相同。

還有另外一個叫element.getBoundingClientRect的函數,它似乎得到了相當廣泛的支持,它返回了相對於瀏覽器視圖端口左上角的像素位置的矩形。這可能會讓你更接近你想要的,而不需要直接混淆變換矩陣。

+0

感謝您的鏈接。 doc肯定地說getBBox()是post變換,但是我得到的node.x和node.y的座標與我爲el.getBBox()。x和el.getBBox()。y所做的一樣。需要注意的是,'節點'是屬於選擇數據一部分的力佈局節點。 –

+0

調用getBBox時,應用於元素的變換是什麼? –

+0

我編輯我的帖子,試圖回答你的問題。我正在通過容器的transform屬性應用translate和scale變換。 [SVG幾何縮放](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

嗡嗡聲,你能確認,這個功能在旋轉適用時仍然不起作用嗎?因爲您沒有使用ctm.b和ctm.c來轉換座標。 – Overdrivr

+0

任何人都知道如何將旋轉變換應用於getElementCoords()函數? – poliu2s