I am trying to position a <div> above a users text selection that will act as a toolbar similar to Mediums.

enter image description here

While I have successfully gotten the <div> to be positioned next to the selection, I cannot seem to get it to correctly center relative to the selection:

    $(function() {
      // Setup the Event Listener
      $('.article').on('mouseup', function() {
        // Selection Related Variables
        let selection = window.getSelection(),
        getRange      = selection.getRangeAt(0),
        selectionRect = getRange.getBoundingClientRect();

        // Set the Toolbar Position
        $('.toolbar').css({
          top: selectionRect.top - 42 + 'px',
          left: selectionRect.left + 'px'
        });
      });
    });

I can determine the selection's center point by subtracting the selections left offset from the viewport by its width as such:

 selectionRect.left - selectionRect.width

However, I am not sure how to use that to set the position of my toolbar to be centered relative to the selection rectangle?

I tried subtracting the toolbars left offset from the width of the selection divided by 2 but that doesn't align to the center perfectly either.

JSFiddle

https://jsfiddle.net/e64jLd0o/

2 Answers

5
Dacre Denny On Best Solutions

One solution would be to add the following to your CSS:

.toolbar {
  transform: translateX(-50%);
}

and update your script to offset the left position of the toolbar element like so:

$('.toolbar').css({
  top: selectionRect.top - 42 + 'px',
  left: ( selectionRect.left + (selectionRect.width * 0.5)) + 'px'
});

Here is a working snippet:

$(function() {
  // Setup the Event Listener
  $('.article').on('mouseup', function() {
    // Selection Related Variables
    let selection = window.getSelection(),
    getRange      = selection.getRangeAt(0),
    selectionRect = getRange.getBoundingClientRect();
     

    // Set the Toolbar Position
    $('.toolbar').css({
      top: selectionRect.top - 42 + 'px',
      left: ( selectionRect.left + (selectionRect.width * 0.5)) + 'px'
    });
  });
});
.article {
  position: relative;
  height: 300px;
  padding: 20px;
}

.toolbar {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 169px;
  padding-top: 10px;
  padding-bottom: 10px;
  background: black;
  text-align: center;
  color: white;
  border-radius: 8px;
  
  transform: translateX(-50%);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<!-- Editor -->
<div class="article">
  <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Tenetur dignissimos facilis id repellat sint deserunt voluptates animi eaque tempore debitis, perferendis repudiandae voluptatem. Eligendi fuga deleniti saepe quod eum voluptas.</p>
</div>

<!-- Toolbar -->
<div class="toolbar">Toolbar</div>

3
Glycerine On

For a quick edit, I applied the changes required to position the div correctly:

https://jsfiddle.net/yaLvzswu/

I applied some additional positioning math on the left calculation:

$(function() {
  // Setup the Event Listener
  $('.article').on('mouseup', function() {
    // Selection Related Variables
    let selection = window.getSelection(),
    getRange      = selection.getRangeAt(0),
    selectionRect = getRange.getBoundingClientRect();
        console.log(selectionRect)
    // Set the Toolbar Position
    $('.toolbar').css({
      top: selectionRect.top - 42 + 'px',
      left: (selectionRect.left - ($('.toolbar').width()/2) + (selectionRect.width/2))+ 'px'
    });
  });
});

Your version applied the left of the toolbar to the left of the selected text. As we want to put the centre of your toolbar to the centre of the selection, the left is shuffled twice:

  • start left
  • move left by half the toolbar width

Now the toolbar centre is on the left of selection.

  • add half the selection width

The toolbar moves right a bit - centre of selected text.