Mateusz Rogulski
Mateusz Rogulski

Reputation: 7445

How to prevent loss hover in Raphael?

I'm developing some page when I use Raphael liblary to draw some items.

my App

So my problem is in that when I'm moving to some rect it growing up but when my mouse is on text which is positioning on my rect, it loss his hover. You can see it on my app example.

var paper = new Raphael(document.getElementById('holder'), 500, object.length * 100);
drawLine(paper, aType.length, bType.length, cType.length, cellSize, padding);

process = function(i,label)
{ 
    txt = paper.text(390,((i+1)* cellSize) - 10,label.devRepo)
        .attr({ stroke: "none", opacity: 0, "font-size": 20});
    var a = paper.rect(200, ((i+1)* cellSize) - 25, rectWidth, rectHeight)
        .hover(function()
        {  
            this.animate({ transform : "s2"}, 1000, "elastic");
            this.prev.animate({opacity: 1}, 500, "elastic");
            this.next.attr({"font-size" : 30});
        }, 
        function()
        {       
            this.animate({ transform : "s1" }, 1000, "elastic");
            this.prev.animate({opacity: 0}, 500);
            this.next.attr({"font-size" : 15});
        });
}

I have tried e.preventDefault(); on hover of this.next and some other solutions but it's doesn't work.

Any help would be appreciated.

Upvotes: 1

Views: 815

Answers (2)

amustill
amustill

Reputation: 5302

I wrote a small extension to Raphael - called hoverInBounds - that resolves this limitation.

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;
}

Upvotes: 0

Chris Wilson
Chris Wilson

Reputation: 6719

Most people will suggest you place a transparent rectangle over the box and the labels and attach the hover functions to that instead. (If memory serves, you have to make the opacity 0.01 instead of 0 to prevent the object from losing its attached events.) This works fine, but I don't love this solution; it feels hacky and clutters the page with unnecessary objects.

Instead, I recommend this: Remove the second function from the hover, making it functionally a mouseover function only. Before you draw any of the rectangles and labels, make a rectangular "mat" the size of the paper. Then, attach the function that minimizes the label as a mouseover on the mat. In other words, you're changing the trigger from mousing out of the box to mousing over the area outside of it.

I left a tiny bit of opacity and color on the mat to be sure it's working. You can just change the color to your background color.

  var mat = paper.rect(0, 0, paper.width, paper.height).attr({fill: "#F00", opacity: 0.1});

Now, you want to make a container for all the rectangles so you can loop through them to see which need to be minimized. I made an object called "rectangles" that contains the objects we're concerned with. Then:

  mat.mouseover(function () {
    for (var c = 0; c < rectangles.length; c += 1) {
      //some measure to tell if rectangle is presently expanded
      if (rectangles[c].next.attr("font-size")) {
        rectangles[c].animate({                  
              transform : "s1"
            }, 1000, "elastic");
        rectangles[c].prev.animate({opacity: 0}, 500);
        rectangles[c].next.attr({"font-size" : 15});                  
      }
    }
  });

Then I just removed the mouseout function from the individual rectangles.

jsBin

To be clear, this will have some downsides: If people run the mouse around really fast, they can expand several rectangles at the same time. This is remedied as soon as the mouse touches the mat. I think the functionality looks pretty nice. But the invisible mats is always an option.

Upvotes: 3

Related Questions