javascriptcssbootstrap-4bootstrap-popoverpopper.js

Placing Bootstrap popover next to cursor position (inside of clicked element)


I have a bootstrap popover that I cannot seem to get to show up inside the element I am calling it on, next to my mouse. I have searched far and wide through the popper.js documentation and have tried using the 'offset' modifier, as well as adjusting just about every other parameter I could think of, in different configurations, but it seems no matter what I do the popover stubbornly wants to be positioned towards one of its four string directions and won't show up inside the element I am calling it on, next to my current cursor position.

Here's an example to give you an idea of what I have tried. Again, I am trying to have the popover popup positioned next to where my mouse click occurs, within a large div.

$(".a_large_div").click(function(e) {
    var relX = e.pageX - parentOffset.left;
    var relY = e.pageY - parentOffset.top;
    var height = $('.popover').height();
    $(this).popover({
        placement: 'top',
        offset:'-'+(relX + 1000)+'px,-'+(relY)+'px',
        title: 'My Popover', 
        html:true,
        trigger: 'manual',
        modifiers: {
            flip: { enabled: false },
            inner: { order: 700, enabled: true },
            applyStyle: { order: 900, enabled: true, fn: (data, options) => 
                { 
                     data.styles.left = "1000px";
                     console.log(data, options);
                     return data;
                }   
            },
            offset: { order: 0, enabled: true, offset: '-'+(relX + 1000)+'px,-'+(relY)+'px'  },
            },   
            boundary: this,
            content: function() {return $("#my_popover_content").html();},
            delay: 100
    }).on('show.bs.popover', function() {
        // execute some code
    }).on('shown.bs.popover', function() {
        // execute some code
    }).on('inserted.bs.popover', function() {
        Object.assign($('.popover')[0].style,{left:""+relX+"px !important",top:""+relY+"px !important"});
    }).on('hidden.bs.popover', function() {
        // execute some code
    }).on('hide.bs.popover', function() {
        // execute some code
});

$(this).popover('toggle'); 

$('.popover').css('left', (relX) + 'px');
$('.popover').css('top', (relY) + 'px');

I have tried all these different positioning methods but to no avail, it seems the 'placement' modifier overrides all of them and Im not sure at what point during the popper.js update process I would be able to override it's positioning. Thanks in advance for all your help.


Solution

  • Looking back on this question, I can see that this was a classic case of ‘doing too much’, where I just have way too much going on such that isolating a specific functionality in order to build and test was challenging.

    Figured I’d circle back and answer this since I have since figured out that this is a relatively straightforward problem.

    Popover can be given position absolute and can be positioned on click by assigning 'left' and 'top' css values offered by the x and y coordinates of the click event object’s metadata.

    var data=[
      {"x":10,"y":10,"height":100},
      {"x":120,"y":10,"height":120},
      {"x":230,"y":10,"height":150},
      {"x":340,"y":10,"height":180},
      {"x":450,"y":10,"height":200}
    ];
    
    
    var bar = d3.select("#barchart").append("svg")
    .attr("width",1000)
    .attr("height",250)
    .selectAll("rect")
    .data(data)
    .enter()
    .append("rect")
    .attr("x",function(d){return d.x }) 
    .attr("y",function(d){return 250 - d.height})
    .attr("width",90)
    .attr("height",0)
    .on('click', function() {
      var left = d3.mouse(this)[0];
      var top = d3.mouse(this)[1];
      var theHeight = $('.popover').height();
      $('.popover').show();
      $('.popover').css('left',(left+10)+'px');
      $('.popover').css('top', (top-(theHeight/2)-10)+'px');
      })
    .style("fill","blue")
    .transition()
    .duration(4000)
    .attr("height",function(d){return(d.height)});
    .popover {
        position:absolute;
        display:none;
        background:#fff;
        border: 1px solid #999;
        padding:10px;
        width:auto;
        box-shadow:0 0 10px rgba(0, 0, 0, .5);
    }
    .popover:after, .popover:before {
        right: 100%;
        border: solid transparent;
        content:" ";
        height: 0;
        width: 0;
        position: absolute;
        pointer-events: none;
    }
    .popover:after {
        border-color: rgba(255, 255, 255, 0);
        border-right-color: #ffffff;
        border-width: 10px;
        top: 50%;
        margin-top: -10px;
    }
    .popover:before {
        border-color: rgba(201, 201, 201, 0);
        border-right-color: #c9c9c9;
        border-width: 11px;
        top: 50%;
        margin-top: -11px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
    <div id="barchart"></div>
    <div class="popover">
      <p>hello world</p>
    </div>

    https://codepen.io/modularmoon/pen/gOLooeb