Amirhossein Hassani
Amirhossein Hassani

Reputation: 409

I want draw line between elements with JQuery and JavaScript only

Question: I have many "divs" in first and second row, I can create a Rectangle with "pageY" and "pageX" and position, but I'd like to create a Line.
Does anyone know how can I do that?

Details : when the user clicks on two points for the first time, a line is created and one class is added to the points for better visibility.
The second time the user clicks, classes are removed and, then, if no class are appended for two point, a new line is created again.
If the user clicks on a line, the line will be removed.
When I talk about "lines" I mean "rectangles" that I would like to replace with lines.
Here is my view

Below is my JS code :

let pTop = '', pLeft = '', pBottom = '', pRight = '';
$('.row-rope-1 .pin').off('click').on('click', function (topLeft) {
  if ($(this).hasClass('rope-loop')) {
    $(this).removeClass('rope-loop');
    pTop = '';
    pLeft = '';
  } else {
    $(this).addClass('rope-loop');
    pTop = $(this).offset().top + 37;
    pLeft = $(this).offset().left;
  }
  createElement();
});
$('.row-rope-2 button.pin').off('click').on('click', function(bottomRight) {
  if ($(this).hasClass('rope-loop')) {
    $(this).removeClass('rope-loop');
    pBottom = '';
    pRight = '';
  } else {
    $(this).addClass('rope-loop');
    pBottom = $(this).offset().top + 37;
    pRight = $(this).offset().left;
  }
  createElement();
});
    
function createElement() {
  let FpTop,FpLeft,FpBottom,FpRight;
  if (pTop !== '' && pLeft !== '' && pBottom !== '' && pRight !== '') {
    let line = document.createElement("span");
    line.setAttribute('class', 'rope-line');
    FpTop = pTop;
    FpLeft = pLeft;
    FpBottom = pBottom;
    FpRight = pRight;
    if (pLeft > pRight){
      FpLeft = pRight;
      FpRight = pLeft;
    }
    if (pTop > pBottom){
      FpTop = pBottom;
      FpBottom = pTop;
    }
    line.setAttribute('style', 'top:' + FpTop + 'px;left:' + FpLeft + 'px;bottom:calc(100% - ' + FpBottom + 'px);right:calc(100% - ' + FpRight + 'px);');
    $('body').append(line);
    pTop = '';
    pLeft = '';
    pBottom = '';
    pRight = '';
    removeElement();
   }
}
function removeElement() {
   $('.rope-line').off('click').on('click', function () {
      $(this).remove();
   });
}
span.rope-line {
   position: absolute;
   background-color: yellow;
   cursor: pointer;
   z-index: 9;
}
let pTop = '', pLeft = '', pBottom = '', pRight = '';
$('.row-rope-1 .pin').off('click').on('click', function (topLeft) {
  if ($(this).hasClass('rope-loop')) {
     $(this).removeClass('rope-loop');
     pTop = '';
     pLeft = '';
  } else {
     $(this).addClass('rope-loop');
     pTop = $(this).offset().top + 37;
     pLeft = $(this).offset().left;
  }
  createElement();
});
$('.row-rope-2 button.pin').off('click').on('click', function (bottomRight) {
   if ($(this).hasClass('rope-loop')) {
      $(this).removeClass('rope-loop');
      pBottom = '';
      pRight = '';
   } else {
      $(this).addClass('rope-loop');
      pBottom = $(this).offset().top + 37;
      pRight = $(this).offset().left;
   }
       
   createElement();
});

function createElement() {
  let FpTop,FpLeft,FpBottom,FpRight;
  if (pTop !== '' && pLeft !== '' && pBottom !== '' && pRight !== '') {
     let line = document.createElement("span");
     line.setAttribute('class', 'rope-line');
     FpTop = pTop;
     FpLeft = pLeft;
     FpBottom = pBottom;
     FpRight = pRight;
     if (pLeft > pRight){
        FpLeft = pRight;
        FpRight = pLeft;
     }
     if (pTop > pBottom){
        FpTop = pBottom;
        FpBottom = pTop;
     }
    line.setAttribute('style', 'top:' + FpTop + 'px;left:' + FpLeft + 'px;bottom:calc(100% - ' + FpBottom + 'px);right:calc(100% - ' + FpRight + 'px);');
    $('body').append(line);
    pTop = '';
    pLeft = '';
    pBottom = '';
    pRight = '';
    removeElement();
  }
}

function removeElement() {
   $('.rope-line').off('click').on('click', function () {
      $(this).remove();
   });
}
span.rope-line {
   position: absolute;
   background-color: yellow;
   cursor: pointer;
   z-index: 9;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-12 row-rope-1">
   <button class="pin pin-up" style="margin-bottom:120px;">
      point 1
   </button>                      
</div>

<div class="col-12 row-rope-2">
    <button class="pin pin-up" style="margin-left: 50px;">
      point2
    </button>                             
</div>

<div class="col-12 row-rope-1">
   <button class="pin pin-up" style="margin-bottom:120px;margin-left: 150px;">
      point3
   </button>
</div>
                                                              
<div class="col-12 row-rope-2">
   <button class="pin pin-up" style="margin-top: 20px;">
      point4
   </button>
</div>

I would appreciate if you could help me with the easiest way :).
Thanks.

Upvotes: 1

Views: 1331

Answers (1)

Pavol Velky
Pavol Velky

Reputation: 810

You can use CSS transform and transform-origin. Calculate distance, angle and you can connect two points in 2D space.

let selectedPin = null;
$('.pin').on('click', function () {
    let pin = $(this);
    if (selectedPin === null) {  
        selectedPin = pin;
        return;
    }
  
    let selectedPinPos = {
        x: selectedPin.offset().top,
        y: selectedPin.offset().left
    }

    let pinPos = {
        x: pin.offset().top,
        y: pin.offset().left
    }

    let distance = calcDistance(selectedPinPos, pinPos);
    let angle = 90-calcAngle(selectedPinPos, pinPos);

    $('#rope').css({
        transform: 'rotate('+angle+'deg)',
        width: distance+'px',
        top: selectedPinPos.x,
        left: selectedPinPos.y
    });

    selectedPin = null;
});

function calcDistance(p1,p2) 
{
    var dx = p2.x-p1.x;
    var dy = p2.y-p1.y;
    return Math.sqrt(dx*dx + dy*dy);
}

function calcAngle(p1, p2) 
{
    return Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
}
span.rope-line {
   position: absolute;
   background-color: yellow;
   cursor: pointer;
   z-index: 9;
}

#rope {
  position: absolute;
  top: 20px;
  left: 20px;
  
  background: #f00;
  
  width: 0;
  height: 2px;
  
  transform: rotate(80deg);
  transform-origin: 0% 0%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-12 row-rope-1">
   <button class="pin pin-up" style="margin-bottom:120px;">
      point 1
   </button>                      
</div>

<div class="col-12 row-rope-2">
    <button class="pin pin-up" style="margin-left: 50px;">
      point2
    </button>                             
</div>

<div class="col-12 row-rope-1">
   <button class="pin pin-up" style="margin-bottom:120px;margin-left: 150px;">
      point3
   </button>
</div>
                                                              
<div class="col-12 row-rope-2">
   <button class="pin pin-up" style="margin-top: 20px;">
      point4
   </button>
</div>

<div id="rope"></div>

Fiddle: https://jsfiddle.net/dbz8of46/2/

Angle formula: https://gist.github.com/conorbuck/2606166

Distance formula: https://gist.github.com/aurbano/4693462

More info: https://www.w3schools.com/css/css3_2dtransforms.asp https://www.w3schools.com/cssref/css3_pr_transform-origin.asp

Upvotes: 1

Related Questions