20

I'm more of a C++ guy, but I am working on some web UI stuff at the moment. I can't seem to get a Bootstrap popover to show up on an SVG element.

Any ideas? The popover works on the normal div.

jsFiddle is here: http://jsfiddle.net/JjAht/

<!DOCTYPE html>
<html>
<head>
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.2.2/css/bootstrap.min.css" rel="stylesheet">
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.2.2/css/bootstrap-responsive.min.css" rel="stylesheet">

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.2.2/bootstrap.min.js"></script>
</head>
<body>
<div>
    <svg width="100" height="100">
        <circle r="45" cx="50" cy="50" style="fill: red"/>
    </svg>
</div>

<div class="well">
    <p>
    Hover here for a popover.
    </p>
</div>

<script type="text/javascript">

    $(document).ready(function() {
        var numCircles = $("circle").length;
        console.log("numCircles = " + numCircles);

        $("circle").popover({trigger:'hover', placement:'bottom', title:'Title!', content:'Content'});

        $("circle").css({"stroke":"blue"});

        $(".well").popover({trigger:'hover', placement:'bottom', title:'Title!', content:'Content'});
    } );
</script>
</body>
</html>
stealthyninja
  • 10,343
  • 11
  • 51
  • 59
Jon Stewart
  • 393
  • 1
  • 4
  • 11
  • 2
    This question may help you: http://stackoverflow.com/questions/3294553/jquery-selector-svg-incompatible However, I could not make their solution work on FF15. – augustomen Dec 19 '12 at 11:34
  • Ah, so the answer is that SVG has a similar but incompatible API and Bootstrap/jQuery can't deal with it. Lovely. Looks like I'll have to roll my own pop-up. [This example](http://markhansen.co.nz/stolen-vehicles-pt2/) uses the Bootstrap popover (I think), but I can't follow all the code. Thank you for the comment. – Jon Stewart Dec 19 '12 at 13:10

3 Answers3

25

From that example it looks like you need to modify Bootstrap to get this to work.

Under bootstrap-tooltip.js replace:

$tip
    .detach()
    .css({ top: 0, left: 0, display: 'block' })
    .insertAfter(this.$element)

pos = this.getPosition(inside)

with

if($('#'+this.$element[0].id,$('svg')).length > 0){
        $tip
          .remove()
          .css({ top: 0, left: 0, display: 'block' })
          .prependTo(document.body)

        pos = $.extend({}, this.$element.offset(), {
          width: this.$element[0].getBoundingClientRect().width
          , height: this.$element[0].getBoundingClientRect().height
        })
   } else {
         $tip
             .detach()
             .css({ top: 0, left: 0, display: 'block' })
             .insertAfter(this.$element)

         pos = this.getPosition(inside)
    }

There were basically two problems 1) bootstrap was inserting the div for the tooltip/popover into the SVG where the browser ignores it and 2) the position information needs to be calculated from the SVG

I've submitted this as a pull request on Github https://github.com/twitter/bootstrap/pull/6521

Update: It looks like bootstrap 2.3.0+ will support this via a new container property for tooltips/popovers. When working with SVG, set the container to body. See comments here https://github.com/twitter/bootstrap/pull/6521

An example:

svg.selectAll(".node").each(
    function(d,i){
        $(this).popover({title:"title", content:"content", container:"body"});
        // and/or $(this).tooltip({title:"tooltip - title", container:"body"});
    });
JulianRendell
  • 93
  • 1
  • 4
Kristofor Carle
  • 1,405
  • 12
  • 14
  • 2
    Thanks! I see you're in Alexandria; I'm in DC. I'd gladly buy you a happy hour beer sometime next week. You can email me at jon@lightboxtechnologies.com. – Jon Stewart Jan 16 '13 at 15:44
  • 1
    Thanks a lot for the tricks. Adding container options is working for me. Note: I'm using it to display popup on Openlayer ... – Stéphane Mar 05 '13 at 09:36
  • One other useful parameter is 'viewport'. This keeps the popover within the bounds of this element. I typically set this to the container SVG element – elachell Jul 20 '17 at 15:48
16

With the latest version of Bootstrap, adding a container option with an HTML element inside seems to be enough to make it work!

$("circle").each(function () {
    $(this).popover({
        title: "Hi!",
        content: "popover",
        container: $("#container")
    });
});
Mick F
  • 7,312
  • 6
  • 51
  • 98
  • I guess it would be better to change the container to `container: "body`.. BTW, good solution there.. – Bla... Apr 06 '15 at 14:18
-1

you haven't selected the svg to open a popover, that's why it won't open. Look here http://jsfiddle.net/JjAht/1/

    $("svg").popover({trigger:'hover', placement:'bottom', title:'Title!', content:'Content'});
Chanckjh
  • 2,587
  • 2
  • 22
  • 28
  • 1
    This opens a popover on the SVG as a whole, but, to be clear, what I'd ideally like is a popover on elements inside the svg. For example, if I had two circles, I'd like different popovers for each. – Jon Stewart Jan 08 '13 at 13:49
  • wouldn't it be better to make 2 svg then? – Chanckjh Jan 08 '13 at 16:28
  • 1
    I'll have a few thousand SVG elements, each representing a unique data point. I'd like the popover to present information about the unique data point. Putting each element into a separate SVG container doesn't seem feasible. [This site](http://markhansen.co.nz/stolen-vehicles-pt2/) is a good example of what I want do... fortunately, one can read the source for it. :-) – Jon Stewart Jan 09 '13 at 16:15