2014-02-18 50 views
2

的jsfiddle鼠標位置:http://jsfiddle.net/az6Ug/SVG如何獲得內部基質

使用Snap.svg庫,我想對SVG的阻力,讓鼠標的位置。我需要在內部矩陣上的鼠標位置,而不是瀏覽器的鼠標位置。 我有這個問題的工作,這是如果SVG所屬的窗口上有任何滾動,計算出的鼠標位置被滾動條上的滾動量偏移。

例如,沒有滾動,然後它工作正常。或者在滾動條上有10px的垂直滾動,鼠標位置計算爲:true position + 10px。 如果有任何水平滾動,這是相同的交易:由滾動量抵消。

在jsFiddle中,我使用矩形在拖動時顯示計算的鼠標位置。 正如你所看到的,如果沒有滾動,那麼矩形會保持鼠標光標(左上角)。但是用一些滾動,矩形偏離鼠標光標。

儘管我使用的是Snap.svg庫,但我只用它來獲取拖動事件,鼠標計算是純Javascript。一個可能的解決方案是通過滾動量減去X和Y,但我認爲使用SVG的變換函數會有更好的方法。

var S; 
var pt; 
var svg 
var box; 

window.onload = function(){ 
    svg = $('#mysvg')[0]; 
    S = Snap(svg); 

    pt = pt = svg.createSVGPoint(); // create the point 

    // add the rectangle 
    box = S.rect(10, 10, 50, 50); 
    box.attr({ fill : 'red', stroke : 'none' }); 

    S.drag(
     function(dx, dy, posX, posY, e){ 
      //onmove 
      pt.x = posX; 
      pt.y = posY; 

      // convert the mouse X and Y so that it's relative to the svg element 
      var transformed = pt.matrixTransform(svg.getScreenCTM().inverse()); 
      box.attr({ x : transformed.x, y : transformed.y }); 
     }, 
     function(){ 
      //onstart 
     }, 
     function(){ 
      //onend 
     } 
    ); 

} 

回答

0

也許你可以只使用getCTM而非getScreenCTM,所以......

var transformed = pt.matrixTransform(svg.getCTM().inverse()); 

,我想你可能需要的東西來調整像

pt.x = posX - S.node.offsetLeft; 
pt.y = posY - S.node.offsetTop; 

jsfiddle here

更新:如上所述在Firefox中不起作用,您可以將客戶端X/Y與原始getS creenCTM,所以

pt.x = e.clientX 
pt.y = e.clientY; 

fiddle here

我猜你需要的不僅僅是這裏的例子,但(在這種情況下,你可以只使用捕捉自己拖funcs中)比較多,所以它很難說,如果這個解決方案將適用於您需要的其他案例。

+0

感謝您的回覆......這在Chrome中可用,但不適用於Firefox。在FF中,'S.node.offsetLeft'是未定義的。 – ServerBloke

+0

已經更新了我認爲更適合的替代方案,該方案也適用於FFX。 – Ian

6

以下是我在所有瀏覽器和所有viewPort中使用的Javascript示例。它使用svg矩陣變換。事件附加到每個要拖動的元素。在這個例子中,我包含了html和svg的鼠標位置讀數。

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
    <title>E - Universal Drag/Drop</title> 
<meta http-equiv="content-type" content="text/html; charset=UTF-8"> 
</head> 
<body style='padding:10px;font-family:arial'> 
<center> 
<h4>Universal Drag/Drop</h4> 
<div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:6px;'> 
This example uses matrix transforms, with object methods, not strings. It can seamlessly drag/drop elements that have previously been transformed and reside it different viewPorts. It employs <b>getScreenCTM</b>, <b>createSVGTransform</b> and binds the element to a <b>transform List</b> 
</div> 
<table> 
<tr><td align=left> 
Scenerio:<br /> 
A 400x400 DIV contains an SVG with viewBox=0 0 330 330.<br /> 
1.) The blue rect element is contained in a &lt;g&gt;.<br /> 
2.) The &lt;g&gt; element has been transformed.<br /> 
3.) The maroon rect resides in a different viewPort.<br /> 
4.) The orange circle has been transformed.<br /> 
5.) Drag/Drop the circles and rectangles.<br /> 
</td> 
<td align=left> 
<div id="svgDiv" style='background-color:lightgreen;width:400px;height:400px;'> 
<svg id="mySVG" width="100%" height="100%" viewBox="0 0 300 300" onmousemove="svgCursor(evt)"> 
<circle onmousedown=startDrag(evt) onmousemove=drag(evt) onmouseup=endDrag() id="redCircle" cx="120" cy="180" r="40" fill="red" stroke="black" stroke-width="2" /> 
<circle onmousedown=startDrag(evt) onmousemove=drag(evt) onmouseup=endDrag() id="orangeCircle" cx="200" cy="200" r="40" fill="orange" stroke="black" stroke-width="2" /> 
<svg viewBox="0 100 800 800"> 
<rect onmousedown=startDrag(evt) onmousemove=drag(evt) onmouseup=endDrag() id="maroonRect" x="220" y="250" width="60" height="60" fill="maroon" stroke="black" stroke-width="2" /> 
</svg> 
<g id="myG" > 
<rect onmousedown=startDrag(evt) onmousemove=drag(evt) onmouseup=endDrag()  id="blueRect" x="220" y="250" width="60" height="60" fill="blue" stroke="black" stroke-width="2" /> 
</g> 
</svg> 
</div> 
</td> 
<td align=left> 
<b>HTML Page Values:</b><br /> 
<input type=text id=htmlMouseXValue size=1 />: mouse X<br /> 
<input type=text id=htmlMouseYValue size=1 />: mouse Y<br /> 
<br /> 
<b>SVG Image Values:</b><br /> 
<input type=text id=svgXValue size=1 />: svg X<br /> 
<input type=text id=svgYValue size=1 />: svg Y<br /> 
</td> 
</tr></table> 
<br />SVG Source:<br /> 
<textarea id=svgSourceValue style='font-size:110%;font-family:lucida console;width:90%;height:200px'></textarea> 
<br />Javascript:<br /> 
<textarea id=jsValue style='border-radius:26px;font-size:110%;font-weight:bold;color:midnightblue;padding:16px;background-color:beige;border-width:0px;font-size:100%;font-family:lucida console;width:90%;height:400px'></textarea> 
</center> 
<div id='browserDiv' style='padding:3px;position:absolute;top:5px;left:5px;background-color:gainsboro;'></div> 
<script id=myScript> 
var TransformRequestObj 
var TransList 
var DragTarget=null; 
var Dragging = false; 
var OffsetX = 0; 
var OffsetY = 0; 
//---mouse down over element--- 
function startDrag(evt) 
{ 
    if(!Dragging) //---prevents dragging conflicts on other draggable elements--- 
    { 
     DragTarget = evt.target; 
     //---reference point to its respective viewport-- 
     var pnt = DragTarget.ownerSVGElement.createSVGPoint(); 
     pnt.x = evt.clientX; 
     pnt.y = evt.clientY; 
     //---elements transformed and/or in different(svg) viewports--- 
     var sCTM = DragTarget.getScreenCTM(); 
     var Pnt = pnt.matrixTransform(sCTM.inverse()); 

     TransformRequestObj = DragTarget.ownerSVGElement.createSVGTransform() 
     //---attach new or existing transform to element, init its transform list--- 
     var myTransListAnim=DragTarget.transform 
     TransList=myTransListAnim.baseVal 

     OffsetX = Pnt.x 
     OffsetY = Pnt.y 

     Dragging=true; 
    } 
} 
//---mouse move--- 
function drag(evt) 
{ 
    if(Dragging) 
    { 
     var pnt = DragTarget.ownerSVGElement.createSVGPoint(); 
     pnt.x = evt.clientX; 
     pnt.y = evt.clientY; 
     //---elements in different(svg) viewports, and/or transformed --- 
     var sCTM = DragTarget.getScreenCTM(); 
     var Pnt = pnt.matrixTransform(sCTM.inverse()); 
     Pnt.x -= OffsetX; 
     Pnt.y -= OffsetY; 

     TransformRequestObj.setTranslate(Pnt.x,Pnt.y) 
     TransList.appendItem(TransformRequestObj) 
     TransList.consolidate() 
    } 
} 
//--mouse up--- 
function endDrag() 
{ 
    Dragging = false; 
    svgSourceValue.value=svgDiv.innerHTML 
} 
//---onload--- 
function initTransforms() 
{ 
//---place some transforms on the elements--- 

    //--- transform orange circle--- 
    var transformRequestObj=mySVG.createSVGTransform() 
    var animTransformList=orangeCircle.transform 
    var transformList=animTransformList.baseVal 
    //---translate--- 
    transformRequestObj.setTranslate(130,-300) 
    transformList.appendItem(transformRequestObj) 
    transformList.consolidate() 
    //----scale--- 
    transformRequestObj.setScale(.5,.9) 
    transformList.appendItem(transformRequestObj) 
    transformList.consolidate() 
    //----skewY--- 
    transformRequestObj.setSkewY(52) 
    transformList.appendItem(transformRequestObj) 
    transformList.consolidate() 

    //--init Transform on myG--- 
    var transformRequestObj=mySVG.createSVGTransform() 
    var animTransformList=myG.transform 
    var transformList=animTransformList.baseVal 
    //---translate--- 
    transformRequestObj.setTranslate(-50,-120) 
    transformList.appendItem(transformRequestObj) 
    transformList.consolidate() 
    //----skewX--- 
    transformRequestObj.setSkewX(15) 
    transformList.appendItem(transformRequestObj) 
    transformList.consolidate() 
    //----skewY--- 
    transformRequestObj.setSkewY(20) 
    transformList.appendItem(transformRequestObj) 
    transformList.consolidate() 
    //---rotate--- 
    transformRequestObj.setRotate(30,200,200) 
    transformList.appendItem(transformRequestObj) 
    transformList.consolidate() 

} 

document.onmousemove = htmCursor 
//---event is the html event object--- 
function htmCursor(event) 
{ 
    var event = event || window.event; 
    myMouseX=event.clientX; 
    myMouseY=event.clientY; 
    myMouseX = myMouseX + document.documentElement.scrollLeft; 
    myMouseY = myMouseY + document.documentElement.scrollTop; 

    htmlMouseXValue.value=myMouseX 
    htmlMouseYValue.value=myMouseY 
} 
//---evt is the svg event object-- 
function svgCursor(evt) 
{ 
    var rect = svgDiv.getBoundingClientRect(); 
    svgXValue.value=evt.clientX-rect.left 
    svgYValue.value=evt.clientY-rect.top 
} 
</script> 
<script> 
document.addEventListener("onload",init(),false) 
function init() 
{ 
    initTransforms() 
    svgSourceValue.value=svgDiv.innerHTML 
    jsValue.value=myScript.text 
} 
</script> 

</body> 

</html> 
+0

+1太棒了!我不得不清理一下代碼才能使它工作,但這是我見過的第一個實際爲我工作的例子(就爲多個視口/變換獲得calc的正確答案)! – Gerrat