简体   繁体   中英

Snap.svg drag multiple groups

I don't know how to drag multiple groups in snap.svg after selecting them. When two elements are selected (opacity is changed for two of them) and I use the dragGroup function I would like to drag both elements, not only the one which was clicked. Can you please give me some support how to accomplish it ?

Please see the JSFiddle, which shows the issue - JSFiddle

SelectMultipleGroups();
dragGroup(Snap.select("#extGrid1"));
dragGroup(Snap.select("#extGrid2"));


function SelectMultipleGroups () {

  var paper = Snap('#svgArea')

  // group that will receive the selected items
  //var selections = paper.group()
  selections = Snap.set(); 

  // DRAG FUNCTIONS
  // when mouse goes down over background, start drawing selection box
  var box = paper.rect(-2000, -2000, 0, 0).attr('stroke', 'black'); //obszar zaznaczania (x, y, width, height);
  function dragstart (x, y, event) {

   //if path or circle were clicked don't draw box
   if(event.target.nodeName == "path" || event.target.nodeName == "circle" )
   {    
      return false;
   } 
   box = paper.rect(x, y-32, 0, 0).attr('stroke', 'black'); 
  }
  // when mouse moves during drag, adjust box. If to left or above original point, you have to translate the whole box and invert the dx or dy values since .rect() doesn't take negative width or height
  function dragmove (dx, dy, x, y, event) {          
      var xoffset = 0,
          yoffset = 0

      if (dx < 0) {
        xoffset = dx
        dx = -1 * dx
      }

      if (dy < 0) {
        yoffset = dy
        dy = -1 * dy
      }

      box.transform('T' + xoffset + ',' + yoffset)
      box.attr('width', dx)
      box.attr('height', dy)
      box.attr('fill', 'none')
  }
  function dragend (event) {    

      var border = box.getBBox()
      box.remove()    

      var items = Snap.selectAll('#svgArea g');

      items.forEach(function (el) {
        // here, we want to get the x,y vales of each object regardless of what sort of shape it is, but rect uses rx and ry, circle uses cx and cy, etc
        // so we'll see if the bounding boxes intercept instead
        var mybounds = el.getBBox()

        // do bounding boxes overlap?
        // is one of this object's x extremes between the selection's xextremes?
        if (Snap.path.isBBoxIntersect(mybounds, border)) {       
            el.attr({
              attr: "selected",
              opacity: 0.5,          
            });   
        }
      });
  }
  Snap.select('#svgArea').drag(dragmove, dragstart, dragend);
};


function dragGroup (element) {

  startFnc = function (e) {   

    var matrixSplit = element.transform().localMatrix.split();

    ox = matrixSplit.dx
    oy = matrixSplit.dy

  }, // handler for drag start
  moveFnc = function (dx, dy) { // handler for moving

    lx = dx + ox // add the new change in x to the drag origin
    ly = dy + oy // add the new change in y to the drag origin  

    // limit the area for drag
    lx = insideContainer(element, lx, ly).x
    ly = insideContainer(element, lx, ly).y 

    element.transform('translate(' + lx + ',' + ly + ')')   

  },
  endFnc = function () { // handler for drag end
    ox = 0
    oy = 0
  }
  element.drag(moveFnc, startFnc, endFnc);
};

// limit the area for drag
function insideContainer (element, lx, ly) { 

  var thisGroup = element.getBBox();


  if (lx < 0) {
    lx = 0
  }
  if (ly < 0) {
    ly = 0
  }
  if (lx > ($("#svgArea").width() - thisGroup.width)) { 
    lx = ($("#svgArea").width()  - thisGroup.width)
  }
  if (ly > ($("#svgArea").height() - thisGroup.height)) {
    ly = ($("#svgArea").height()  - thisGroup.height)
  }

  return {
    x: lx,
    y: ly
  }
}

The simplest way, would be to put both the group elements inside another group. That way you just put the handler on the parent group element, and when you drag it, everything inside moves with it.

dragGroup(Snap.select("#parentGroup"));

jsfiddle example

If for some reason you can't do this, you would have to iterate over each of those group elements and transform them, storing each groups starting position before the drag. So it could look something like this...

startFnc = function (e) {   

    selections.forEach(function(el) {
      var matrixSplit = el.transform().localMatrix.split();

      el.data('ox',matrixSplit.dx)
      el.data('oy',matrixSplit.dy)
    });

  }, // handler for drag start
  moveFnc = function (dx, dy) { // handler for moving

    selections.forEach(function(el) {

      lx = dx + el.data('ox') // add the new change in x to the drag origin
      ly = dy + el.data('oy') // add the new change in y to the drag origin  

      // limit the area for drag
      lx = insideContainer(el, lx, ly).x
      ly = insideContainer(el, lx, ly).y 

      el.transform('translate(' + lx + ',' + ly + ')')
    });
}

jsfiddle

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM