Search code examples
javascriptjqueryhtmlcsstooltip

JavaScript: how do I make a tooltip follow the cursor *and* flip on collision?


I'm fairly new to JavaScript, so I have a feeling this is an easily resolved problem; bear with me please.

For my website, I've incorporated a jQuery-based tooltip that follows the cursor. But since its a tool I found online to begin with, I'm having some troubleshooting issues. What I want is for the tooltip to follow the cursor until the tooltip collides with the edges of the page; when it does collide, I'd like for it to do something like collision: "flip". I pretty much understand why my attempts haven't been working. I only know how to make it only follow the cursor or only use .position(). I don't get how to incorporate both into a single script without messing up everything else.

Here's the script as it was given on the developer's site:

<script type="text/javascript">
$(document).ready(function() {
// Tooltip only Text
$('.masterTooltip').hover(function(){
    // Hover over code
    var title = $(this).attr('title');
    $(this).data('tipText', title).removeAttr('title');
    $('<p class="tooltip"></p>')
    .text(title)
    .appendTo('body')
    .fadeIn('slow');
}, function() {
    // Hover out code
    $(this).attr('title', $(this).data('tipText'));
    $('.tooltip').remove();
}).mousemove(function(e) {
    var mousex = e.pageX + 20; //Get X coordinates
    var mousey = e.pageY + 10; //Get Y coordinates
    $('.tooltip')
    .css({ top: mousey, left: mousex })
});
});
</script>

There was also a CSS component. As far as I can tell, this isn't involved in the problem, but in case that it is, voilà.

.tooltip {
display:none;
position:absolute;
border:1px solid #333;
background-color:#161616;
border-radius:5px;
padding:10px;
color: #fff;
font-size:12px;
width: 200px;
}

Sorry if this is a very dense question, but I've been trying to figure this out all day and I've all but given up at this point.

Again, what I want is for the tooltip to follow the cursor, as it currently does -- but not indefinitely. When following the cursor would cause the tooltip to collide with the window, creating a scrollbar, I want it instead to either appear on the other side of the cursor, or remain static as the cursor moves closer to an edge of the window. Anything, in any case, for the content within the tooltip to remain visible regardless of where the cursor goes.

Thank you!


Solution

  • Edit: Sorry I misread your question the first time. Here is the solution...

    The "trick" is to set the event object as the of property value of the object that is passed to position(). If the value of the "of" property is an object containing pageX/pageY, those values are used. This allows you to easily have something follow the mouse, a common use case.

    $(document).ready(function() {
        // Tooltip only Text
        $('.masterTooltip').hover(function() {
            // Hover over code
            var title = $(this).attr('title');
            $(this).data('tipText', title).removeAttr('title');
            $('<p class="tooltip"></p>')
                .text(title)
                .appendTo('body')
                .fadeIn('slow');
        }, function() {
            // Hover out code
            $(this).attr('title', $(this).data('tipText'));
            $('.tooltip').remove();
        }).mousemove(function(e) {
            var mouseXPadding = 20,
                mouseYPadding = 10;
                $('.tooltip').position({
                    my: "left+" + mouseXPadding + " top+" + mouseYPadding,
                    of: e,
                    // within: $('.masterTooltip') // optional to contain tooltip
                });
        });
    });
    

    Here is another, better imo, version which takes into account the fact that the user might accidentally move his/her mouse over the tooltip (a case which the above doesn't handle well):

    $(document).ready(function() {
        var padding = {
                x = 20,
                y = 10
            },
            $tip = $('<p class="tooltip"></p>');
    
        // Our helper function that moves tip to the mouse
        function moveTipToMouse(event) {
            $tip.position({
                my: "left+" + padding.x+ " top+" + padding.y,
                of: event,
            });
        }
    
        // Moves tooltip out of the way if the mouse accidentally goes over it
        $tip.mousemove(moveTipToMouse);
    
        // Tooltip only Text
        $('.masterTooltip').hover(function() {
            // Hover over code
            var title = $(this).attr('title');
            $(this).data('tipText', title).removeAttr('title');
            $tip.text(title);
            if (!$.contains(document, $tip[0])) {
                $tip.appendTo('body').fadeIn("slow");
            }
        }, function(event) {
            // Hover out code
            // if the mouse exists to the tooltip, no need to hide it
            if ($tip.is(':hover')) {
                return;
            }
            $('.tooltip').remove();
        }).mousemove(moveTipToMouse);
    });
    

    Here is the fiddle: https://jsfiddle.net/g6wmkzr2/