2017-07-22 105 views
1

我使用Interactjs在SVG视口周围拖动SVG元素,主要是因为它支持手势,我最终将在手机上使用它进行轮换。但是我的简单拖动有问题。与SVG的交互

<div class="container"> 
    <!--?xml version="1.0" encoding="UTF-8"?--> 
    <svg viewBox="0 0 100 100"> 
    <g class="shape" transform="scale(0.1) translate(-300, 0) rotate(10)"> 
     <polygon xmlns="http://www.w3.org/2000/svg" points="350,75 379,161 469,161 397,215      423,301 350,250 277,301 303,215      231,161 321,161" /> 
    </g> 
    </svg> 
</div> 

Interactjs不给当前光标的x,y,所以它是从一个增量X计算,Y,(event.dx,event.dy)积累的事件,从起始位置偏移(事件.x0,event.y0)。然后,在将其应用为元素当前变换的平移变换之前,将其转换为目标元素的局部坐标(以防旋转,偏斜等)(按照SO answer)。

interact('.shape').draggable({ 
    onstart: dragStartListener, 
    onmove: dragMoveListener, 
    onend: dragEndListener 
}); 

var svg = document.getElementsByTagName('svg')[0]; 
var pt = svg.createSVGPoint(); 

function dragStartListener(event) { 
    event.target.transform.baseVal.consolidate(); 
    console.clear(); 
} 

function dragMoveListener(event) { 
    var target = event.target; 
    var currentCursor = getCurrentCursor(event); 
    var translationMatrix = getMatrixForTranslation(target, currentCursor.x, currentCursor.y); 
    target.transform.baseVal.getItem(0).setMatrix(target.transform.baseVal.getItem(0).matrix.multiply(translationMatrix)); 
} 

function dragEndListener(event) { 
    var target = event.target; 
    target.removeAttribute('data-x'); 
    target.removeAttribute('data-y'); 
} 

function getMatrixForTranslation(target, x, y) { 
    return target.ownerSVGElement.createSVGMatrix().translate(x, y); 
} 

function getCurrentCursor(event) { 
    var target = event.target; 
    // keep the change in cursor on page in the data-x/data-y attributes 
    var x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx; 
    var y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy; 
    target.setAttribute('data-x', x); 
    target.setAttribute('data-y', y); 
    pt.x = event.x0 + x; // calculate the new whole page coordinates 
    pt.y = event.y0 + y; 
    // convert to object space coordinates ... https://stackoverflow.com/a/5223921/5610106 
    var globalPoint = pt.matrixTransform(svg.getScreenCTM().inverse()); 
    var globalToLocal = target.getTransformToElement(svg).inverse(); 
    var inObjectSpace = globalPoint.matrixTransform(globalToLocal); 
    console.log('cursor: x: ' + inObjectSpace.x + '; y: ' + inObjectSpace.y); 
    return {x: inObjectSpace.x, y: inObjectSpace.y}; 
} 

JSFiddle here。我通过target.transform.baseVal.getItem(0).setMatrix()操纵元素的“transform”属性,而不是通过CSS转换,因为我需要的单位与SVG空间的单位相同。此外,我可以轻松地将它们合并()成单个矩阵,然后我可以将其发送回服务器,以便可以在其他视图上轻松渲染这些形状。

但是,简单的拖动会导致第一个事件发生大的跳转,然后目标元素在跟随光标时不在光标之下。

任何想法,我应该如何做到这一点?

回答

0

我这样做前段时间:

<script> 
     var ns = 'http://www.w3.org/2000/svg' 
     var svg = document.createElementNS(ns,'svg') 
      svg.id = 'svg' 
      svg.style.height = '100%' 
      svg.style.width = '100%' 

      rect = document.createElementNS(ns,'rect') 
      rect.setAttribute('width', '100px') 
      rect.setAttribute('height', '100px') 
      rect.setAttribute('fill', 'green') 
      svg.append(rect) 
     document.body.append(svg) 


     svg = document.getElementById('svg') 

     var mousedown = false; 

     window.onmousemove = (e) => { 
     var x = e.clientX 
     var y = e.clientY 

      svg.onmousedown = (e) => { 
       var x = e.clientX 
       var y = e.clientY 
        diffX = Math.abs(e.target.getBoundingClientRect().left - x) 
        diffY = Math.abs(e.target.getBoundingClientRect().top - y) 
       console.log(diffY +' || '+e.target.getBoundingClientRect().top+' || '+y) 

       mousedown = true; 
      } 

      if(mousedown) { 
       e.target.setAttribute('x', x - diffX) 
       e.target.setAttribute('y', y - diffY) 
       window.onmouseup =() => { 
        mousedown = false; 
       } 
      } 
     } 
    </script> 
+0

您的解决方案不会考虑变换对矩形拖动之前​​。尝试在设置时添加“rect.setAttribute('transform','translate(50 0)rotate(45)')”,您将看到矩形不再跟随鼠标,因为没有鼠标的帐户在对象空间坐标中的位置。此外,我无法操纵x&y属性,因为标签没有它们,因此我试图操作transform属性。 – marlboroman