Question

I have the code below for dragging svg object.

$('#svg-drag')
   .draggable()
   .bind('mousedown', function(event, ui){
    // bring target to front
    $(event.target.parentElement).append( event.target );
   })
   .bind('drag', function(event, ui){
    // update coordinates manually, since top/left style props don't work on SVG
    event.target.setAttribute('x', ui.position.left);
    event.target.setAttribute('y', ui.position.top);

});

but when I start dragging the object, it always start from the corner. with the 0, 0 xy coordinates. I want to start dragging from its original coordinates. If I have 100, 300 xy coordinate, I want to start dragging from 100 x coordinate and 300 y coordinate.

Thanks in advance!!

Was it helpful?

Solution

When the drag is started, i.e. mouse down, you must gain access to its current x,y translation values. This is shown as the OffsetX, OffsetY values in the example below

This example uses Javascript. I guess this example may be more than you request at this time...But hopefully it will serve you in future needs to drag/drop svg elements.

It addresses the drag/drop of any svg element, no matter its previous transforms and/or viewPorts. It uses the SVGPoint as the drag reference so there is no need to access position attributes of an element. I call it the SVG Universal Drag/Drop ;)

Also, it does not require moving elements to the top to drag them. This may conflict with the desired layout unless they are returned on drag end.

This example uses SVG matrix transforms, with object methods, rather than transform strings.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>SVG 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>SVG 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 attaches the element to a <b>transform List</b>
</div>
<div id="svgDiv" style='background-color:lightgreen;width:400px;height:400px;'>
<svg id="mySVG" width="400" height="400"  onmousedown=startDrag(evt) onmousemove=drag(evt) onmouseup=endDrag()>
<circle id="redCircle" cx="120" cy="180" r="40" fill="red" stroke="black" stroke-width="2" />
<circle  id="orangeCircle" cx="200" cy="200" r="40" fill="orange" stroke="black" stroke-width="2" />
<svg viewBox="0 100 800 800">
<rect id="maroonRect"  x="220" y="250" width="60" height="60" fill="maroon" stroke="black" stroke-width="2"  />
</svg>
<g id="myG" >
<rect  id="blueRect"  x="220" y="250" width="60" height="60" fill="blue" stroke="black" stroke-width="2"  />
</g>
</svg>
</div>
</center>
<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;
}

document.addEventListener("onload",initTransforms(),false)
//---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(180,-260)
    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,-80)
    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()
}
</script>
</body>
</html>

OTHER TIPS

Here try this example,

<div id="containment-wrapper" class="wrap">


    <svg id="svg-drag" width="100" height="100">
   <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
   Sorry, your browser does not support inline SVG.
</svg>

</div>

Jquery:

$('#svg-drag')
   .draggable()
   .bind('mousedown', function(event, ui){
    // bring target to front
    $(event.target.parentElement).append( event.target );
   })
   .bind('drag', function(event, ui){
    // update coordinates manually, since top/left style props don't work on SVG
    event.target.setAttribute('x', ui.position.left);
    event.target.setAttribute('y', ui.position.top);
});

Demo fiddle

If you have transformed a path, the following will update its d attribute and remove the transformation. Thiis works on all svg path types, except the arc.

//---except arc paths---
function screenPath(path)
{
    var sCTM = path.getCTM()
    var svgRoot = path.ownerSVGElement

    var segList=path.pathSegList
    var segs=segList.numberOfItems
    //---change segObj values
    for(var k=0;k<segs;k++)
    {
        var segObj=segList.getItem(k)

        if(segObj.x && segObj.y )
        {
            var mySVGPoint = svgRoot.createSVGPoint();
            mySVGPoint.x = segObj.x
            mySVGPoint.y = segObj.y
            mySVGPointTrans = mySVGPoint.matrixTransform(sCTM)
            segObj.x=mySVGPointTrans.x
            segObj.y=mySVGPointTrans.y
        }

        if(segObj.x1 && segObj.y1)
        {
            var mySVGPoint1 = svgRoot.createSVGPoint();
            mySVGPoint1.x = segObj.x1
            mySVGPoint1.y = segObj.y1
            mySVGPointTrans1 = mySVGPoint1.matrixTransform(sCTM)
            segObj.x1=mySVGPointTrans1.x
            segObj.y1=mySVGPointTrans1.y
        }
        if(segObj.x2 && segObj.y2)
        {
            var mySVGPoint2 = svgRoot.createSVGPoint();
            mySVGPoint2.x = segObj.x2
            mySVGPoint2.y = segObj.y2
            mySVGPointTrans2 = mySVGPoint2.matrixTransform(sCTM)
            segObj.x2=mySVGPointTrans2.x
            segObj.y2=mySVGPointTrans2.y
        }


    }
    //---force removal of transform--
    path.setAttribute("transform","")
    path.removeAttribute("transform")
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top