-2

I've managed to setup a FIDDLE where I gave an example how to bind an element within svg boundary. It's working fine when dragging a normal element(without rotation). But when I apply this to a rotated object, the problem arises:

var s = Snap("#svgout");
var ROOM_WIDTH = 400;
var ROOM_HEIGHT = 200;
var SVG_BOUNDARY = s.rect(0, 0, ROOM_WIDTH, ROOM_HEIGHT);
SVG_BOUNDARY.attr({
  "stroke": "#FF0000",
  "fill": "#FFFFFF",
  id: "room-svg-boundary"
});
var BEFORE_ROTATION_GETBBOX = [];

s.attr({
  viewBox: "0 0 " + ROOM_WIDTH + " " + ROOM_HEIGHT
});
(function() {

  Snap.plugin(function(Snap, Element, Paper, global) {

    Element.prototype.limitDragging = function(params) {
      this.data('minx', params.minx);
      this.data('miny', params.miny);
      this.data('maxx', params.maxx);
      this.data('maxy', params.maxy);
      this.data('x', params.x);
      this.data('y', params.y);
      this.data('ibb', this.getBBox());
      this.data('ot', this.transform().local);
      this.drag(limitMoveDrag, limitStartDrag);
      return this;
    };

    function limitMoveDrag(dx, dy, posx, posy, ev) {
      var tdx, tdy;
      var sInvMatrix = this.transform().globalMatrix.invert();
      sInvMatrix.e = sInvMatrix.f = 0;
      tdx = sInvMatrix.x(dx, dy);
      tdy = sInvMatrix.y(dx, dy);

      this.data('x', +this.data('ox') + tdx);
      this.data('y', +this.data('oy') + tdy);
      if (this.data('x') > this.data('maxx') - this.data('ibb').width) {
        this.data('x', this.data('maxx') - this.data('ibb').width)
      };
      if (this.data('y') > this.data('maxy') - this.data('ibb').height) {
        this.data('y', this.data('maxy') - this.data('ibb').height)
      };
      if (this.data('x') < this.data('minx')) {
        this.data('x', this.data('minx'))
      };
      if (this.data('y') < this.data('miny')) {
        this.data('y', this.data('miny'))
      };

      this.transform(this.data('ot') + "t" + [this.data('x'), this.data('y')]);
    };

    function limitStartDrag(x, y, ev) {
      this.data('ox', this.data('x'));
      this.data('oy', this.data('y'));
    };
  });

})();

var SETUP_DRAG_MOVEMENT = function(ELEM, disable) {
  if (disable != undefined && disable == true) {
    ELEM.undrag();
  } else {
    var RECT_BOUNDARY = s.getBBox();
    var ELEM_BOX = ELEM.getBBox();
    var min_x = -ELEM_BOX.cx + ELEM_BOX.width / 2;
    var max_x = RECT_BOUNDARY.x2 - ELEM_BOX.x2 + ELEM_BOX.width;
    var min_y = -ELEM_BOX.cy + ELEM_BOX.height / 2;
    var max_y = RECT_BOUNDARY.y2 - ELEM_BOX.y2 + ELEM_BOX.height;

    ELEM.limitDragging({
      x: 0,
      y: 0,
      minx: min_x,
      miny: min_y,
      maxx: max_x,
      maxy: max_y
    });
  }
}

var SETUP_DRAG_MOVEMENT_ROTATED = function(ELEM, disable) {
  if (disable != undefined && disable == true) {
    BEFORE_ROTATION_GETBBOX[ELEM.node.id] = ELEM.getBBox();
    ELEM.undrag();
  } else {
    var RECT_BOUNDARY = s.getBBox();
    console.log(RECT_BOUNDARY);
    var ELEM_BOX = (BEFORE_ROTATION_GETBBOX[ELEM.node.id] != undefined && typeof BEFORE_ROTATION_GETBBOX[ELEM.node.id] == "object") ? BEFORE_ROTATION_GETBBOX[ELEM.node.id] : ELEM.getBBox();

    var min_x = -ELEM_BOX.x;
    var max_x = RECT_BOUNDARY.x2 - ELEM_BOX.x2 + ELEM_BOX.width;
    var min_y = -ELEM_BOX.y;
    var max_y = RECT_BOUNDARY.y2 - ELEM_BOX.y2 + ELEM_BOX.height;

    ELEM.limitDragging({
      x: 0,
      y: 0,
      minx: min_x,
      miny: min_y,
      maxx: max_x,
      maxy: max_y
    });
  }
}

var DBLCLICK_HANDLER = function(ELEM) {
  SETUP_DRAG_MOVEMENT(THIS_RECT, true);
  var THIS_ELEM_BB = ELEM.getBBox();
  var transformProp = new Snap.Matrix();
  transformProp.rotate(45, THIS_ELEM_BB.cx, THIS_ELEM_BB.cy);
  transformProp.add(ELEM.matrix);
  ELEM.transform(transformProp);
  SETUP_DRAG_MOVEMENT_ROTATED(THIS_RECT, false);
}

var myCircle = s.circle(380, 20, 20).attr({
  fill: 'blue'
});
var THIS_CIRCLE_LABEL = s.paper.text(376, 25, "1").attr({
  fill: "#FFFFFF"
});
var THIS_CIRCLE = s.group(myCircle, THIS_CIRCLE_LABEL);
THIS_CIRCLE.attr({
  id: "THIS_CIRCLE"
});
SETUP_DRAG_MOVEMENT_ROTATED(THIS_CIRCLE, false);

var myRect = s.rect(0, 0, 30, 30).attr({
  fill: 'green'
});
var THIS_RECT_LABEL = s.paper.text(11, 19, "2").attr({
  fill: "#FFFFFF"
});
var THIS_RECT = s.group(myRect, THIS_RECT_LABEL);
THIS_RECT.attr({
  id: "THIS_RECT"
});
SETUP_DRAG_MOVEMENT_ROTATED(THIS_RECT, false);

THIS_RECT.node.addEventListener("dblclick", function() {
  DBLCLICK_HANDLER(THIS_RECT);
}, false);
<script src="http://snapsvg.io/assets/js/snap.svg-min.js"></script>
<p>Double click on the rectangle to rotate it and then try to drag. When you drag without rotating, it's perfect (The drag boundary). But while dragging a rotated object, then the problem arises..</p>
<svg id="svgout" height="400" width="600"></svg>

How do I solve this one?

Bojangles
  • 99,427
  • 50
  • 170
  • 208
Pritam
  • 16
  • 2
  • Desribe your problem more. – Refilon Dec 03 '14 at 08:24
  • go to that fiddle and just double click on rectangle to rotate it, then try to drag it. I want that rotated object to be bound inside the svg boundary, which is not happenning.. – Pritam Dec 03 '14 at 10:30

1 Answers1

0

As that includes some of my old code, thought I would do an answer....

Originally that doesn't take into account existing transforms easier. I wrote some updated code that would do this...

The main bits that are different are the getInversePoint() function, which gets the inverse transformation to the screen. Also I've changed the order of transformations, so the element is always panned first.

Example

Element.prototype.getInversePoint = function( x, y ) {
        var pt = this.paper.node.createSVGPoint();  
        pt.x = x; pt.y = y;
        return pt.matrixTransform( this.paper.node.getScreenCTM().inverse());
}

Element.prototype.limitDrag = function( params ) {
    this.data('dragParams', params );
    this.data('x', params.x); this.data('y', params.y);
    this.drag( limitMoveDrag, limitStartDrag );
    return this;    
};

function limitMoveDrag( xxdx, xxdy, ax, ay ) {
    var tdx, tdy;
    var params = this.data('dragParams');
    var pt = this.getInversePoint( ax, ay );
    var dx = pt.x - this.data('op').x;
    var dy = pt.y - this.data('op').y;

    var ibb = this.data('ibb');
    if( ibb.x + ibb.width + +dx > params.maxx ) 
        { dx = params.maxx - (ibb.x + ibb.width) };

    if( ibb.y + ibb.height + +dy > params.maxy ) 
        { dy = params.maxy - (ibb.y + ibb.height)  };
    if( ibb.x + +dx < params.minx ) { dx = params.minx - ibb.x; };
        if( ibb.y + +dy < params.miny ) { dy = params.miny - ibb.y; };

    this.transform(  "t" + [  dx, dy ] +   this.data('ot').toTransformString());
};

function limitStartDrag( x, y, ev ) {
    this.data('ibb', this.getBBox());
    this.data('op', this.getInversePoint( x, y ));
    this.data('ot', this.transform().localMatrix);
};
Ian
  • 13,724
  • 4
  • 52
  • 75