2014-02-18 1 views
2

jsFiddle: http://jsfiddle.net/az6Ug/SVG, как получить позицию мыши на внутренней матрицы

Использование библиотеки Snap.svg, я хочу перетащить на SVG и получить позицию мыши. Мне нужна позиция мыши на внутренней матрице, а не на позиции мыши браузера. У меня есть работа с одной проблемой, которая есть, если есть какая-либо прокрутка в окне, к которому принадлежит SVG, вычисленная позиция мыши смещается на количество прокрутки на полосе прокрутки.

Например, без прокрутки он работает нормально. Или с 10px вертикальной прокрутки на полосе прокрутки, позиция мыши вычисляется как: истинное положение + 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 не работает, вы можете взять clientX/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

Ниже приведен пример в Javascript того, что я использую во всех браузерах и всех viewPorts. Он использует преобразование матрицы 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 Удивительный! Мне пришлось немного почистить код, чтобы заставить его работать, но это первый пример, который я видел, который на самом деле работал для меня (насколько правильные вычисления для нескольких видовых экранов/преобразований)! – Gerrat

Смежные вопросы