2012-04-24 65 views
33

我遇到了有關SVG文檔中鼠標光標位置的問題。我想設計一個電位器,它將在拖動時跟隨光標,在HTML頁面中使用JavaScript自動調整SVG內的鼠標位置

我試過evt.clientX/Y和evt.screenX/Y但是由於我的SVG在自動縮放,我的SVG裏面的座標是不同的。我幾天來一直在尋找答案,但我找不到任何解決方案(要麼實時瞭解我的SVG縮放因子,要麼在SVG座標系中有鼠標位置的功能)。

旋轉將遵循一個簡單的規則:

如果(evt.screenX < XC)

ANG = Math.atan((evt.screenY - YC)/(evt.screenX - XC ))* 360 /(2 * Math.PI) - 90; (evt.screenX_xc)/(evt.screenX_xc))* 360 /(2 * Math.PI)+90;(3)如果(evt.screenX> xc)
ang = Math.atan((evt.screenY_yc)/

將(xc; yc)作爲旋轉中心,並將所有evt.screenX/Y替換爲SVG中鼠標的座標。

+0

您必須使用變換矩陣來獲取正確的座標。一個jsfiddle會有幫助。 – mihai 2012-04-24 13:25:46

回答

85

參見該代碼,這不僅說明了如何從屏幕空間到全球SVG空間變換,又是如何從SVG空間中的點轉換爲一個元素的變換空間:
http://phrogz.net/svg/drag_under_transformation.xhtml

在短:

// Find your root SVG element 
var svg = document.querySelector('svg'); 

// Create an SVGPoint for future math 
var pt = svg.createSVGPoint(); 

// Get point in global SVG space 
function cursorPoint(evt){ 
    pt.x = evt.clientX; pt.y = evt.clientY; 
    return pt.matrixTransform(svg.getScreenCTM().inverse()); 
} 

svg.addEventListener('mousemove',function(evt){ 
    var loc = cursorPoint(evt); 
    // Use loc.x and loc.y here 
},false); 

編輯:我創建適合您的需求的樣本(儘管只是在全球SVG空間):
http://phrogz.net/svg/rotate-to-point-at-cursor.svg

它添加下列方法上面:

function rotateElement(el,originX,originY,towardsX,towardsY){ 
    var angle = Math.atan2(towardsY-originY,towardsX-originX); 
    var degrees = angle*180/Math.PI + 90; 
    el.setAttribute(
    'transform', 
    'translate('+originX+','+originY+') ' + 
     'rotate('+degrees+') ' + 
     'translate('+(-originX)+','+(-originY)+')' 
); 
} 
+1

嗨,對不起,我沒有迴應,事實是,我不能,使用Firefox(我不知道爲什麼)。所以我看到你的代碼可以獨立工作,但我仍然在處理一些奇怪的問題,只要我找到一種方法讓它在我的項目中工作,我會盡快回復你!謝謝 – Riwall 2012-04-25 12:10:20

+0

看來,我的getBBox()不能正常工作,所以我無法獲得正確的原點(您需要這樣做)(我需要這是自動的,以便使用inkscape可以輕鬆移動元素,甚至可以複製/粘貼到另一個svg)。我一直在嘗試很多事情,但沒有成功。 – Riwall 2012-04-26 14:49:46

+0

@Riwall我建議你爲你的BBox問題提出一個新問題;請確保包含一個簡單的,簡化的測試用例(用問題代碼或JSFiddle)來重現您的問題,並描述給您帶來麻煩的操作系統/瀏覽器/版本。 – Phrogz 2012-04-26 15:04:13

2

@Phrogz:謝謝你的很好的例子,我從教訓。我已經改變了它的一些如下,使它有點容易的權利。正如我認爲就像我們在覈心Java中處理鼠標事件一樣,我們也可以在這裏處理相同的方式,所以我在你的例子中嘗試了我的方式。

我已經刪除了「rotateElement」函數,因爲我認爲它有些困難,如果它找到替代品。

請參見下面的代碼:

var svg=document.getElementById("svg1"); 
var pt=svg.createSVGPoint(); 
var end_small=document.getElementById("end_small"); 
var line=document.getElementById("line1"); 

end_small.addEventListener('mousemove', function(evt) { 

    var loc=getCursor(evt); 
    end_small.setAttribute("cx",loc.x); 
    end_small.setAttribute("cy",loc.y); 

    loc = getCursor(evt); // will get each x,y for mouse move 

    line.setAttribute('x2',loc.x); // apply it as end points of line 
    line.setAttribute('y2',loc.y); // apply it as end points of line 

}, false); 

function getCursor(evt) { 
    pt.x=evt.clientX; 
    pt.y=evt.clientY; 
    return pt.matrixTransform(svg.getScreenCTM().inverse()); 
} 

所以我所做的就是我剛纔添加監聽器只小圈不完整SVG,每次當鼠標被你感動我會得到x, ygetCursor()功能如上所述我會給這x, y作爲x2, y2我的線這就是它不翻譯和不旋轉。您必須將鼠標移至圓圈,然後緩慢移動,如果鼠標離開圓圈,則線條不會移動,因爲我們剛剛僅在小圓圈右側添加了偵聽器。

0

獲得正確的svg鼠標座標很棘手。首先,常用的方法是使用event屬性的clientX和clientY,並分別用getBoundingClientRect()和clientLeft分別代表clientTop。

svg.addEventListener('click', event => 
{ 
    let bound = svg.getBoundingClientRect(); 

    let x = event.clientX - bound.left - svg.clientLeft - paddingLeft; 
    let y = event.clientY - bound.top - svg.clientTop - paddingTop; 
} 

但是,如果SVG具有更高的填充樣式信息然後爲零,則座標被移位。因此,這些信息必須是也。減去:

let paddingLeft = parseFloat(style['padding-left'].replace('px', '')); 
let paddingTop = parseFloat(style['padding-top'].replace('px', '')); 

let x = event.clientX - bound.left - svg.clientLeft - paddingLeft; 
let y = event.clientY - bound.top - svg.clientTop - paddingTop; 

而且不是很好的思考是,在某些瀏覽器border屬性也轉向座標,和其他沒有。我發現,如果事件屬性的x和y是而不是可用,則發生轉換。

if(event.x === undefined) 
{ 
    x -= parseFloat(style['border-left-width'].replace('px', '')); 
    y -= parseFloat(style['border-top-width'].replace('px', '')); 
} 

在這個轉換之後,x和y座標可以超出限制,這應該是固定的。但那不是這個想法。

let width = svg.width.baseVal.value; 
let height = svg.height.baseVal.value; 

if(x < 0 || y < 0 || x >= width || y >= height) 
{ 
    return; 
} 

該解決方案可用於點擊,鼠標移動,鼠標按下,...等等。 您可以在此處進行實時演示:https://codepen.io/martinwantke/pen/xpGpZB