Tool tip in html

Viewed 455

I have a div that needs to be identified using a line and box(which will contain a message) like in the below mockup image.2 and 3(Line and a rectangular box) are fixed to each other and draggable and 1(Line) can be stretched to any direction. I have created the box but I am not able to figure out how can I attach a line to it. Here is what I have tried.

JSFIDDLE

js

const $b1 = $("#box1");
const $b2 = $("#box2");
const $line = $("#line");

const coordinates = function() {
debugger;
  const x1 = $b1.offset().left;
  const y1 = $b1.offset().top + $b1.height()/2;
  const x2 = $b2.offset().left + $b1.width()/2;
  const y2 = $b2.offset().top + $b1.height()/2;

  moveLine(x1, y1, x2, y2);  
}

coordinates();

function moveLine(x1, y1, x2, y2) {
    var length = Math.sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
    var angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
    var transform = 'rotate(' + angle + 'deg)';

    offsetX = (x1 > x2) ? x2 : x1;
    offsetY = (y1 > y2) ? y2 : y1;
    
    $line.css({
        'position': 'absolute',
        '-webkit-transform': transform,
        '-moz-transform': transform,
        'transform': transform
      })
      .width(length)
      .offset({
        left: offsetX,
        top: offsetY
      });
}

$('#box1').draggable({
  drag: coordinates
});

Html

<div class="box" id="box1">10%</div>
<p id="box2">www.google.com</p>

<div class="line" id="line"></div>

css

.box {
  border: 1px solid black;
  background-color: #ffffff;
  width: 100px;
  height: 40px;
  position: absolute;
}

#line1 {
  top: 100px;
  left: 50px;
  /*transform: rotate(222deg);
    -webkit-transform: rotate(222deg);
    -ms-transform: rotate(222deg);*/
}

.line {
  width: 1px;
  height: 1px;
  background-color: black;
  position: absolute;
  z-index: -1; /* put line behind the boxes */
}


#box1 {
  top: 150px;
  left: 150px;
}

#box2 {
  top: 200px;
  left: 200px;
  position:relative;
}

enter image description here

4 Answers

I used SVG to define the line.

I am sorry it is not in jQuery.

// Thanks to: https://developer.mozilla.org/en-US/docs/Web/API/Document/drag_event
// Thanks to: https://stackoverflow.com/a/6239882/2182349

// This is demo code - obviously it could be refined

let tooltip = document.getElementById("tooltip");

document.addEventListener("dragstart", function(event) {
  // store a ref. on the tooltip elem
  tooltip = event.target;
  // make it half transparent
  event.target.style.opacity = .5;
  let style = window.getComputedStyle(event.target, null);
  event.dataTransfer.setData("text/plain",
    (parseInt(style.getPropertyValue("left"), 10) - event.clientX) + ',' + (parseInt(style.getPropertyValue("top"), 10) - event.clientY));
}, false);

document.addEventListener("dragend", function(event) {
  // reset the transparency
  event.target.style.opacity = "";
}, false);

/* events fired on the drop targets */
document.addEventListener("dragover", function(event) {
  // prevent default to allow drop
  event.preventDefault();
}, false);

document.addEventListener("drop", function(event) {
  // prevent default action (open as link for some elements)
  event.preventDefault();
  let offset = event.dataTransfer.getData("text/plain").split(',');
  tooltip.style.left = (event.clientX + parseInt(offset[0], 10)) + 'px';
  tooltip.style.top = (event.clientY + parseInt(offset[1], 10)) + 'px';
  drawLine(tooltip);
}, false);

let clientRect = document.getElementById("anchor").getBoundingClientRect();
let line = document.getElementById("line");
let points = line.points;
let first = points.getItem(0);
first.x = clientRect.x + clientRect.width / 2;
first.y = clientRect.y + clientRect.height / 2;

drawLine(tooltip);

function drawLine(endElement) {
  let clientRect = endElement.getBoundingClientRect();
  let line = document.getElementById("line");
  let points = line.points;
  let last = points.getItem(2);
  last.x = clientRect.x + clientRect.width / 2;
  last.y = clientRect.y + clientRect.height / 2;
  let length = Math.sqrt(Math.pow(first.x - last.x, 2) + Math.pow(first.y - last.y, 2));
  let middle = points.getItem(1);
  if (first.x > last.x) length = -length;
  middle.x = first.x + length / 2;
  middle.y = (first.y > last.y) ? last.y : first.y;
}
body {
  margin: 0;
  padding: 0;
}

.box {
  position: relative;
  background: #fff;
  display: inline-block;
  border: 1px solid #000;
  width: auto;
  padding: 3px;
  text-align: center;
}

#anchor {
  top: 150px;
  left: 100px;
}

#tooltip {
  top: 10px;
  left: 400px;
}

svg {
  position: absolute;
  top: 0;
  left: 0;
  z-index: -100;
  width: 100%;
  height: 100%;
}
<svg height="200" width="500">
        <polyline id="line" points="0,0 0,0 0,0" style="fill:none;stroke:black;" />
        </svg>
<div id="tooltip" class="box" draggable="true">
  Tool tip
</div>
<div id="anchor" class="box">www.google.com</div>

If the segment 2 shouldn't be responsive you can just use a :before element and adjust the offset left of the segment 1:

const $b1 = $("#box1");
const $b2 = $("#box2");
const $line = $("#line");

const coordinates = function() {
  const x1 = $b1.offset().left;
  const y1 = $b1.offset().top + $b1.height() / 2;
  const x2 = $b2.offset().left + $b1.width() / 2;
  const y2 = $b2.offset().top + $b1.height() / 2;

  moveLine(x1, y1, x2, y2);
}

coordinates();

function moveLine(x1, y1, x2, y2) {
  var length = Math.sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
  var angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
  var transform = 'rotate(' + angle + 'deg)';

  offsetX = (x1 > x2) ? x2 : x1;
  offsetY = (y1 > y2) ? y2 : y1;

  $line.css({
      'position': 'absolute',
      '-webkit-transform': transform,
      '-moz-transform': transform,
      'transform': transform
    })
    .width(length)
    .offset({
      left: offsetX - 20, // remove segment 2's width
      top: offsetY
    });
}

$('#box1').draggable({
  drag: coordinates
});
.box {
  border: 1px solid black;
  background-color: #ffffff;
  width: 100px;
  height: 40px;
  right: 0;
  position: absolute;
}

.box:before {
  position: absolute;
  transform: translate(-100%, -50%);
  top: 50%;
  content: '';
  width: 20px;
  height: 1px;
  background: black;
}

#line1 {
  top: 100px;
  left: 50px;
  /*transform: rotate(222deg);
    -webkit-transform: rotate(222deg);
    -ms-transform: rotate(222deg);*/
}

.line {
  width: 1px;
  height: 1px;
  background-color: black;
  position: absolute;
  z-index: -1;
  /* put line behind the boxes */
}

#box1 {
  top: 150px;
  left: 150px;
}

#box2 {
  top: 200px;
  left: 200px;
  position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>


<div class="box" id="box1">10%</div>
<p id="box2">www.google.com</p>

<div class="line" id="line"></div>

I would suggest you use a png image for the line part, or an svg. It would be much easier.

Short answer, because the code has already been given by others above.

Here's some CSS. For the tool tip container use class="tooltip" and for the <span> of the tool tip text use class="tooltiptext".

.tooltip{position:relative;display:inline-block;
border-bottom: 1px dotted black; /* if you want dots under the hoverable text */
}
.tooltip .tooltiptext{visibility:hidden;width:120px;
background: #555; /* or whatever color you want the tool tip background to be */
color: #fff; /* or whatever color you want the tool tip text to be */
text-align:center;padding:5px 0;border-radius:6px;position:absolute;
z-index:1;bottom:125%;left:50%;margin-left:-60px;opacity:0;transition:opacity 0.3s;}
.tooltip .tooltiptext::after{content:"";
position:absolute;top:100%;left:50%;margin-left:-5px;border-width:5px;
border-style:solid;border-color:#555 transparent transparent transparent;}
.tooltip:hover .tooltiptext{visibility:visible;opacity:1;}
Related