Hovering over a set of elements in Raphaeljs

I have a set that only contains a rectangle.

var hoverTrigger = this.paper.set();
var outline = this.paper.rect();
outline.attr({
...
hoverTrigger.push(outline)
this.sprite.push(hoverTrigger);

Upon hover, the rectangle is supposed to expand, and some links are added to it, and upon mouse off, the links disappear and the rectangle becomes small again.

hoverTrigger.hover(function () {
  var link = this.paper.text();
  hoverTrigger.push(link);
  outline.animate({
  ...
}, function() {
  link.remove();
  outline.animate({
  ...
});

However, it seems like the hover function is being applied to each item in the set individually, and not the whole set, because when you go to mouse over a link, the hover off function fires and the link disappears. Sometimes the box gets hover on and hover off events in quick succession and spazzes.

Is there a way to apply a hover to a set of things, so that mousing between two things in the set doesn't trigger hover off?

Answers:

Answer

Having faced this limitation myself recently, I decided to write a small extension to Raphael called hoverInBounds that resolves it.

Simply, once the mouse enters the element we keep track of when it actually moves outside its bounds - executing the hover out function then, not before.

Demo: http://jsfiddle.net/amustill/Bh276/1

Raphael.el.hoverInBounds = function(inFunc, outFunc) {
    var inBounds = false;

    // Mouseover function. Only execute if `inBounds` is false.
    this.mouseover(function() {
        if (!inBounds) {
            inBounds = true;
            inFunc.call(this);
        }
    });

    // Mouseout function
    this.mouseout(function(e) {
        var x = e.offsetX || e.clientX,
            y = e.offsetY || e.clientY;

        // Return `false` if we're still inside the element's bounds
        if (this.isPointInside(x, y)) return false;

        inBounds = false;
        outFunc.call(this);
    });

    return this;
}

Place the above block of code before you create your Raphael paper object.

Answer

I hit on this problem before. I found 2 solutions.

Create a rectangle over other elements with opacity set to 0

var paper = new Raphael( 0, 0, 100, 100 );
var rect = paper.rect( 0, 0, 100, 100 ).attr({ opacity: 0 });
rect.hover( func_in, func_out );

This only works for elements that have 1 overall action like click.

The other option is to cancel the hover function when hovering over a set of elements

var funcOutTimer;

set.hover( function( ) {
    if( funcOutTimer ) { // Hovered into this element in less than 100 milliseconds => cancel
        window.clearTimeout( funcOutTimer);
    } else {
    // do stuff
    }
},
function( ) {
    funcOutTimer = setTimeout( function( ) {
        // do stuff
    }, 100 ); // wait for 100 milliseconds before executing hover out function
});

Basically the hover in function is only executed when first entering a set of elements for the first time and the hover out function will only execute once when finally the element you have hovered into is not part of that set.

Answer

I found that this works with the following

myCircleElement.hover (
    function(e) { myTextElement.animate({opacity:1}, 800); },
    function(e) {
        var x = e.layerX || e.x,
        y = e.layerY || e.y;
        // Return `false` if we're still inside the element's bounds                                        
        if (this.isPointInside(x, y)) return false;
        // otherwise do something here.. eg below
        myTextElement.animate({opacity:0}, 800); //
    }
);
Answer

The method Bruno details have this minor issue:

If you create a rectangle over the other elements, if the other elements are text then those texts can't be selected in the web page. But it works.

By the way the attribute "opacity": 0 is not enough, I had to add the "fill": "white" attribute in my case.

You need to bring the object to the front like this: obj.toFront(); obj is a raphael shape like "rect", etc.

I tested it on a mouseover and mouseout event and it works.

Check my fiddle here: link to fiddle

function withArray(x,y){
    var rect = paper.rect(x, y, 100, 60).attr({
        fill: "green"
    });
    rect.text = paper.text(x+(100/2), y + 30, 'rect w/array').attr({
        'font-size': 12,
        "fill": "white"
    });
    var rectover = paper.rect(x,y,100,60).attr({
        fill: "white",
        opacity: 0
    });
    var myArray = paper.set();
    myArray.push(rect, rect.text, rectover);
    myArray.mouseover(function() {
    var anim = Raphael.animation({
    transform: ['S', 1.5, 1.5, (rect.attr("x")), (rect.attr("y"))]
        }, 100, "backOut", function() {
    });
    myArray.animate(anim);
    }).mouseout(function() {
        var anim = Raphael.animation({
            transform: [""]
        }, 50, "backOut", function() {
   });
   myArray.stop().animate(anim);
});
}

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.