2014-02-18 32 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