Keep SVG line by always connecting two objects

Asked

Viewed 135 times

4

I have two objects circle, that I can move with the mouse. I wanted a line between the two circles, that whenever one moves, the line is always glued.

The code I have for moving objects:

var dragged = null; //L'élément en cours de drag

function start_drag(objet,event)
{
  dragged = objet;

  if( event.preventDefault ) event.preventDefault();
}

function drag_onmousemove(event)  //Lorsque la souris se déplace
{
  if( dragged ) 
  {
    x = event.clientX;
    y = event.clientY;
    elementHeight = dragged.clientHeight; //hauteur du obj
    elementWidth = dragged.clientWidth;
    dragged.style.position = 'absolute';
    dragged.style.left = x - elementWidth/2 + 'px'; //divise longueur par 2 pour le milieu
    dragged.style.top = y - elementHeight/2 + 'px';


  }
}

function drag_onmouseup(event)  
{
  dragged = null; 

}

function addEvent(obj,event,fct)
{
  if( obj.attachEvent)
    obj.attachEvent('on' + event,fct);
  else
    obj.addEventListener(event,fct,true);
}

addEvent(document,'mousemove',drag_onmousemove);
addEvent(document,'mouseup',drag_onmouseup);	
<div id="divcircle" onmousedown="start_drag(document.getElementById('divcircle'), event);" style="position:absolute; height:50px; width:50px;"> 
  <svg id="svg">
    <circle cx="50" cy="50" r="5" stroke="black" stroke-width="3" fill="green" />
  </svg>	
</div>
<div id="divcircle2" onmousedown="start_drag(document.getElementById('divcircle2'), event);" style="position:absolute; height:50px; width:50px;"> 
  <svg id="svg">
    <circle cx="40" cy="40" r="5" stroke="black" stroke-width="3" fill="green" />
  </svg>	
</div>

1 answer

8


Considering the line syntax:

<line x1="20" y1="100" x2="200" y2="220" stroke="black" stroke-width="2"/>

What you need to do is animate the desired property. In your case, you will have to make one of the pairs, or x1 and y1, or x2 and y2 have the same value as the circle moved.


Practical example of use:

I took the technique of drag 'n' drop found at this link, which is more stable than yours, and I adapted by adding the part that connects the elements:

var selectedElement = 0;
var selectedLine = 0;
var selectedLineX = 0;
var currentX = 0;
var currentY = 0;
var currentMatrix = 0;

function selectElement(evt,lin,linx) {
  selectedElement = evt.target;
  selectedLine = document.getElementById( lin );
  selectedLineX = linx;
  currentX = evt.clientX;
  currentY = evt.clientY;
  currentMatrix = selectedElement.getAttributeNS(null, "transform").slice(7,-1).split(' ');
  for(var i=0; i<currentMatrix.length; i++) {
    currentMatrix[i] = parseFloat(currentMatrix[i]);
  }
  selectedElement.parentNode.setAttributeNS(null, "onmousemove", "moveElement(evt)");
  selectedElement.setAttributeNS(null, "onmouseup", "deselectElement(evt)");
}


function moveElement(evt){
  dx = evt.clientX - currentX;
  dy = evt.clientY - currentY;
  currentMatrix[4] += dx;
  currentMatrix[5] += dy;
  newMatrix = "matrix(" + currentMatrix.join(' ') + ")";
  selectedElement.setAttributeNS(null, "transform", newMatrix);
  currentX = evt.clientX;
  currentY = evt.clientY;
  if ( selectedLineX == 1 ) {
    selectedLine.x1.baseVal.value = selectedElement.cx.baseVal.value + currentMatrix[4];
    selectedLine.y1.baseVal.value = selectedElement.cy.baseVal.value + currentMatrix[5];
  } else {
    selectedLine.x2.baseVal.value = selectedElement.cx.baseVal.value + currentMatrix[4];
    selectedLine.y2.baseVal.value = selectedElement.cy.baseVal.value + currentMatrix[5];
  }
}

function deselectElement(evt){
  if(selectedElement != 0){
    selectedElement.parentNode.removeAttributeNS(null, "onmousemove");
    selectedElement.removeAttributeNS(null, "onmouseup");
    selectedElement = 0;
  }
}
body,html,#dd,#svg1{padding:0;margin:0;width:100%;height:100%}
circle {cursor:move}
<div id="dd">
  <svg id="svg1">
    <line id="l1-2" x1="80" y1="80" x2="40" y2="40" stroke="black" stroke-width="2"/>
    <circle
       cx="80" cy="80" r="5" stroke="black" stroke-width="3" fill="green"
       transform="matrix(1 0 0 1 0 0)" onmousedown="selectElement(evt,'l1-2',1);"
    />
    <circle
       cx="40" cy="40" r="5" stroke="black" stroke-width="3" fill="green"
       transform="matrix(1 0 0 1 0 0)" onmousedown="selectElement(evt,'l1-2',2);"
    />
    <line id="l3-4" x1="80" y1="40" x2="40" y2="80" stroke="black" stroke-width="2"/>
    <circle
       cx="80" cy="40" r="5" stroke="black" stroke-width="3" fill="red"
       transform="matrix(1 0 0 1 0 0)" onmousedown="selectElement(evt,'l3-4',1);"
    />
    <circle
       cx="40" cy="80" r="5" stroke="black" stroke-width="3" fill="red"
       transform="matrix(1 0 0 1 0 0)" onmousedown="selectElement(evt,'l3-4',2);"
    />
  </svg>	
</div>

The parameters of the function: selectElement(evt, 'ID DA LINHA', ponta_desejada_1_ou_2 );

  • Thank you, and how can I keep the position of the two circles?

  • @akm can take the attribute ELEMENT.cx.baseVal.value and Cy from the desired circle.

  • I used for example circle1.cx.baseVal.value, and from the initial position, what I want is the position whenever the object changes.

  • @akm take from the tip of the line instead of catch from Circle selectedLine.y2.baseVal.value

  • And if you want to add more elements, just add the svg circles, and selectedLine.X3 so successively?

  • Every line has one X1 and one x2, are the separate ends. In case, if you want more circles, you have to put more lines as well. I put an example with another set of lines and circles. Remember that this is an example, the idea is not you copy and paste as is, but rather learn how to use, and improve for your own use.

  • For example, if you have too many circles, it pays to do the lines automatically, not in the SVG source. If you have interconnected chains, then you have to increase the function to move two lines or more in each circle. Remember that depending on the use, you can have more efficient ways. Use this as a starting point only.

  • @akm I think here you can see working legal. I did so to be independent of the function of drag 'n' drop http://jsfiddle.net/t26ou3u6/

  • Thanks, it works well. I don’t understand the code Circ.transform.animVal[0].matrix.e

  • @akm as the drag'n'drop is using a transformation matrix (a kind of "space distortion" instead of dragging objects originally), I am adding the original position of the object with the distortion factor applied to the drag, to obtain the final destination of the circle. To tell you the truth, you can change all the code so you don’t use transformation matrices, but it would hinder using Svgs at different scales from the original. Kind of tricky to explain around here.

  • I added the circles and the line, but I wanted to have the 3 in line for example. I put them in the corectas positions, but the line does not move. In other words, the middle circles would have 2 tips of 2 lines.

  • It would only increase the function to receive two lines instead of one, but look at all the possibilities, because depending on the combinations it pays to rethink the function or automate the generation of lines.

Show 7 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.