Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SVG - resizing a rectangle positioned at an angle

Tags:

rotation

svg

All,

I have a SVG rectangle in my application which can be stretched horizontally by dragging the end bar (left & right) on either side of the rectangle. The rectangle can be

(1) resized (by stretching as per above),

(2)dragged,

(3)& rotated.

Everything works fine, however, one strange experience is that when I rotate the rectangle to a degree close to 90, & then try to resize the rectangle, it starts stretching from the opposite border of the rectangle instead of the original borders. (here is the image):

rendition of functionality

It appears to be getting confused between left and right when I use the rotate function.

Here is the revised HTML, JS & SVG:

    <%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
<!--        <script type="text/javascript" src="CPolyline.js">

        </script>-->
    </head>
    <body>
        <object id="oo" data="rect2.svg" style="position:fixed;width: 800px;height:800px;bottom:-100px;right: 375px;">

    </object>
        path: <input type="button" id="path" onclick="X()">
        path2: <input type="button" id="path2" onclick="Y()">
     <input type="button" value="Rotate" onclick="Rotate1()">


        <script type="text/javascript">
            var ob=document.getElementById("oo")

            var svgDoc=null;
            var svgRoot=null;
            var MyGroupObjectsObj = null;
            var svgNS = "http://www.w3.org/2000/svg";
            var dragTarget = null;
            var rectTemplate = null;
            var grabPoint = null;
            var clientPoint = null;
            var rectX = null;
            var rectY = null;
            var rectWidth = null;
            var rectHeight = null;
            var arr=new Array();
            var resizingLeft = false;
            var resizingRight = false;
            var rectrot=null

            ob.addEventListener("load", function(){

                svgDoc=ob.contentDocument;

                svgRoot=svgDoc.documentElement;
                grabPoint = svgRoot.createSVGPoint();
                clientPoint = svgRoot.createSVGPoint();
                rectTemplate = svgDoc.getElementById('rectTemplate')

       rectrot=svgDoc.getElementById("rect1")



}, false)



var angel=0


function Rotate1()
{

       angel=angel+10
       //alert(rectrot)

       var c=rectTemplate.getAttribute("transform");
       var widt=Number(rectTemplate.getAttribute("width"))/2;

        var hie=Number(rectTemplate.getAttribute("height"))/2
        var tran=c.match(/[\d\.]+/g);
        var newxpo=Number(tran[0])+widt;
        var newypo=Number(tran[1])+hie;
        var r=Math.tan((newxpo)/(newypo))
      rectTemplate.parentNode.setAttribute("transform","translate("+newxpo+" "+newypo+")"+"rotate("+angel+") translate("+(newxpo*-1)+" "+(newypo*-1)+")");



}


function MouseDown(evt)
{

  var targetElement = evt.target;
       var checkForResizeAttempt = false;

        if (targetElement == rectTemplate)
        {
            //arr.push(cir ,cir1,rectTemplate)

               dragTarget = targetElement;
               checkForResizeAttempt = true;

                       var transMatrix = dragTarget.getCTM();


        grabPoint.x = evt.clientX - Number(transMatrix.e);
        grabPoint.y = evt.clientY - Number(transMatrix.f);

        }

        var transMatrix = dragTarget.getCTM();



//var transMatrix = dragTarget.getCTM().inverse();

        grabPoint.x = evt.clientX - Number(transMatrix.e);
        grabPoint.y = evt.clientY - Number(transMatrix.f);

        if (window.console) console.log(grabPoint.x + " " + grabPoint.y);
        if (window.console) console.log(evt.clientX + " " + evt.clientY);

        if (checkForResizeAttempt)
        {
          clientPoint.x = evt.clientX;
          clientPoint.y = evt.clientY;
          rectX = Number(dragTarget.getAttributeNS(null, "x"));
          rectY = Number(dragTarget.getAttributeNS(null, "y"));
          rectWidth = Number(dragTarget.getAttributeNS(null, "width"));
          rectHeight = Number(dragTarget.getAttributeNS(null, "height"));

          if ((grabPoint.x - rectX) < 10)
          {
            resizingLeft = true;
          }
          else if (((rectX + rectWidth) - grabPoint.x) < 10)
          {
            resizingRight = true;
          }

          if (resizingLeft || resizingRight)
          {
            dragTarget.setAttributeNS(null,"stroke","green");
          }
          else
          {
            dragTarget.setAttributeNS(null,"stroke","black");
          }
        }
      }

function MouseMove(evt)
{
evt.stopPropagation();
 if (dragTarget == null)
      {
        return;
      }
      if (resizingLeft)
      {
        if (window.console) console.log(evt.clientX + " " + evt.clientY);
        deltaX = (clientPoint.x - evt.clientX);
        if (window.console) console.log("deltaX = " + deltaX);
        dragTarget.setAttributeNS(null,"width",rectWidth + deltaX);
        dragTarget.setAttributeNS(null,"x",rectX - deltaX);
      }
      else if (resizingRight)
      {
        deltaX = (clientPoint.x - evt.clientX);
        if (window.console) console.log("rectWidth = " + rectWidth + " deltaX = " + deltaX);
        dragTarget.setAttributeNS(null,"width",rectWidth - deltaX);


      }
      else
      {


        var newXX = evt.clientX-grabPoint.x;
        var newYX = evt.clientY-grabPoint.y;


        dragTarget.setAttributeNS(null,'transform','translate(' + newXX + ',' + newYX + ')');
      }

}
function MouseUp(evt)
{
  evt.stopPropagation();
   if (dragTarget == null)
      {
        return;
      }
      resizingLeft = false;
      resizingRight = false;
      resizingTop = false;
      resizingBottom = false;
     // var transMatrix = dragTarget.getCTM().inverse();
      dragTarget.setAttributeNS(null,"stroke","blue");
      dragTarget = null;


}


        </script>
    </body>
</html>



--



=======SVG ====

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
     x="0px" y="0px" width="612px" height="792px" xml:space="preserve"
onmousedown="ecmascript:top.MouseDown(evt)"
onmousemove="ecmascript:top.MouseMove(evt)"
onmouseup="ecmascript:top.MouseUp(evt)">




<g id="rect1">
  <rect id="rectTemplate" x="0" y="0" stroke="blue" width="100" height="30" />

 </g>
like image 281
Kayote Avatar asked Jan 19 '11 07:01

Kayote


2 Answers

I have posted a sample of dragging and resizing transformed SVG rects in my answer here:
SVG coordinates with transform matrix

You can see the working example on my site here:
http://phrogz.net/svg/drag_under_transformation.xhtml

The key is to:

  1. When you start dragging (mousedown) record the mouse location (in SVG global space).
  2. During dragging (mousemove) calculate the offset (in SVG global space) for the drag, and then
  3. Transform that offset from global space into the local space of the object, and use that to inform your changes.

This works regardless of the transformation hierarchy applied (as shown in my example).

like image 200
Phrogz Avatar answered Sep 27 '22 18:09

Phrogz


Have you tried to change your code to rotate the shape around the center of the shape?

Here is an excerpt of the W3C draft on transform:

rotate(<rotate-angle> [<cx> <cy>]),
which specifies a rotation by <rotate-angle> degrees about a given point.

If optional parameters <cx> and <cy> are not supplied, the rotate is about the origin of the current user coordinate system. 

The operation corresponds to the matrix [cos(a) sin(a) -sin(a) cos(a) 0 0].

If optional parameters <cx> and <cy> are supplied, the rotate is about the point (cx, cy). 

The operation represents the equivalent of the following specification: 
translate(<cx>, <cy>) rotate(<rotate-angle>) translate(-<cx>, -<cy>).

If you set cx and cy to the center of your ribbon, this may help from what context I can pick up from your code.

like image 20
Garet Claborn Avatar answered Sep 27 '22 18:09

Garet Claborn