3

I'm working on a US map using Raphael.js, which you can view here: http://www.motionflashdesigns.com/usabbr/

I've started adding state abbreviations using set(), so that both the path of the state and its text abbreviation are in the same object.

I'm adding a mouseover event handler on the whole set object, but the child text also registers the mouse over event, which effectively causes a mouseout on the set, anyone know how to stop the event propagation on the set children?

In jquery I would either use mouseenter or event.stopPropagation, but neither of those seem supported in Raphael.

Here is the JS:

$(function () {

    var stateNames = new Array();
    var stateURLs = new Array();
    var stateModes = new Array();
    var stateColors = new Array();
    var stateOverColors = new Array();
    var stateClickedColors = new Array();
    var stateText = new Array();

    var offColor;
    var strokeColor;
    var mapWidth;
    var mapHeight;
    var useSideText;
    var textAreaWidth;
    var textAreaPadding;

    var mouseX = 0;
    var mouseY = 0;
    var current = null;

    // Detect if the browser is IE.
    var IE = $.browser.msie ? true : false;

    $.ajax({
        type: 'GET',
        url: 'xml/usaMapSettings.xml',
        dataType: $.browser.msie ? 'text' : 'xml',
        success: function (data) {

            var xml;
            if ($.browser.msie) {
                xml = new ActiveXObject('Microsoft.XMLDOM');
                xml.async = false;
                xml.loadXML(data);
            } else {
                xml = data;
            }

            var $xml = $(xml);

            offColor = '#' + $xml.find('mapSettings').attr('offColor');
            strokeColor = '#' + $xml.find('mapSettings').attr('strokeColor');
            mapWidth = $xml.find('mapSettings').attr('mapWidth');
            mapHeight = $xml.find('mapSettings').attr('mapHeight');
            useSideText = $xml.find('mapSettings').attr('useSideText');
            textAreaWidth = $xml.find('mapSettings').attr('textAreaWidth');
            textAreaPadding = $xml.find('mapSettings').attr('textAreaPadding');

            if (useSideText == 'true') {
                $("#text").css({
                    'width': (parseFloat(textAreaWidth) - parseFloat(textAreaPadding * 2)) + 'px',
                    'height': (parseFloat(mapHeight) - parseFloat(textAreaPadding * 2)) + 'px',
                    'display': 'inline',
                    'float': 'right',
                    'padding': textAreaPadding + 'px'
                });

                $('#text').html($xml.find('defaultSideText').text());
            }

            //Parse xml
            $xml.find('stateData').each(function (i) {

                var $node = $(this);

                stateText.push($node.text());
                stateNames.push($node.attr('stateName'));
                stateURLs.push($node.attr('url'));
                stateModes.push($node.attr('stateMode'));
                stateColors.push('#' + $node.attr('initialStateColor'));
                stateOverColors.push('#' + $node.attr('stateOverColor'));
                stateClickedColors.push('#' + $node.attr('stateSelectedColor'));
            });

            createMap();
        }
    });

    function createMap() {

        //start map
        var r = new ScaleRaphael('map', 930, 590),
            attributes = {
                fill: '#d9d9d9',
                cursor: 'pointer',
                stroke: strokeColor,
                'stroke-width': 1,
                'stroke-linejoin': 'round',
                'font-family':'Verdana', 
                'font-size':'19px', 
                'font-weight': 'bold'
            },
            arr = new Array();

            var usa = {};

            usa.alabama = r.set();
            usa.alaska = r.set();
            usa.arizona = r.set();
            usa.arkansas = r.set();
            usa.california = r.set();
            usa.colorado = r.set();
            usa.connecticut = r.set();
            usa.delaware = r.set();
            usa.dc = r.set();
            usa.florida = r.set();
            usa.georgia = r.set();
            usa.hawaii = r.set();
            usa.idaho = r.set();
            usa.illinois = r.set();
            usa.indiana = r.set();
            usa.iowa = r.set();
            usa.kansas = r.set();
            usa.kentucky = r.set();
            usa.louisiana = r.set();
            usa.maine = r.set();
            usa.maryland = r.set();
            usa.massachusetts = r.set();
            usa.michigan = r.set();
            usa.minnesota = r.set();
            usa.mississippi = r.set();
            usa.missouri = r.set();
            usa.montana = r.set();
            usa.nebraska = r.set();
            usa.nevada = r.set();
            usa.newHampshire = r.set();
            usa.newJersey = r.set();
            usa.newMexixo = r.set();
            usa.newYork = r.set();
            usa.northCarolina = r.set();
            usa.northDakota = r.set();
            usa.ohio = r.set();
            usa.oklahoma = r.set();
            usa.oregon = r.set();
            usa.pennsylvenia = r.set();
            usa.rhodeIsland = r.set();
            usa.southCarolina = r.set();
            usa.southDakota = r.set();
            usa.tennessee = r.set();
            usa.texas = r.set();
            usa.utah = r.set();
            usa.vermont = r.set();
            usa.virginia = r.set();
            usa.washington = r.set();
            usa.westVirginia = r.set();
            usa.wisconsin = r.set();
            usa.wyoming = r.set();

            var boxattrs = {'cursor': 'pointer', 'fill' : "#000"};
            var i = 0;

        for (var state in usamappaths) {
            //Create obj
            var obj = usa[state];
            obj.attr(attributes);

            if (stateModes[i] == 'OFF') {
                boxattrs = {'cursor': 'default', 'fill' : offColor};
            } else {
                boxattrs = {'cursor': 'pointer', 'fill' : stateColors[i], 'id' : i};
            }

            obj.push(r.path(usamappaths[state].path).attr(boxattrs));
            obj.push(r.text(usamappaths[state].textX, usamappaths[state].textY, usamappaths[state].text).attr(
                {"font-family":"Arial, sans-serif",
                 "font-weight":"bold",
                 "font-size":"14",
                 "font-color":"#000",
                 'cursor': 'pointer'}));

                obj[0].node.id = i;
                obj.mouseover(function (e) {
                    e.stopPropagation();

                    var id = $(this.node).attr('id');

                    if (stateModes[id] != 'OFF') {

                    //Animate if not already the current state
                        if (this != current) {
                            this.animate({
                                fill: stateOverColors[id]
                            }, 500);
                        }

                        //tooltip
                        $('#map').next('.point').remove();
                        $('#map').after($('<div />').addClass('point'));
                        $('.point').html(stateNames[id]).css({
                            left: mouseX - 50,
                            top: mouseY - 70
                        }).fadeIn();
                    }
                 });



        obj.mouseout(function (e) {

                var id = $(this.node).attr('id');

                if (stateModes[id] != 'OFF') {

                //Animate if not already the current state
                 if (this != current) {
                    this.animate({
                        fill: stateColors[id]
                    }, 500);
                }

                $('#map').next('.point').remove();

                }



         });

        obj.mouseup(function (e) {

                var id = $(this.node).attr('id');

                if (stateModes[id] != 'OFF') {
                    //Reset scrollbar
                    var t = $('#text')[0];
                    t.scrollLeft = 0;
                    t.scrollTop = 0;

                    //Animate previous state out
                    if (current) {
                        var curid = $(current.node).attr('id');
                        current.animate({
                            fill: stateColors[curid]
                        }, 500);
                    }

                    //Animate next
                    this.animate({
                        fill: stateClickedColors[id]
                    }, 500);

                    current = this;

                    if (useSideText == 'true') {
                        $('#text').html(stateText[id]);
                    } else {
                        //change "_self" to "_blank" if using in WP iframe
                        window.open(stateURLs[id], '_self');
                    }
                }
            });


         i++;
    }

    resizeMap(r);
    /*
    //Might use that for east coast states
    var t = r.text(120, 50, "WA").attr(
          {"font-family":"Arial, sans-serif",
           "font-weight":"bold",
           "font-size":"14",
           "font-color":"#000",
           "pointer-events":"none",
           'disabled': 'true'});

    var rect = r.rect(t.getBBox().x,t.getBBox().y,t.getBBox().width,t.getBBox().height).attr({'cursor': 'pointer'});
    */
}

// Set up for mouse capture
if (document.captureEvents && Event.MOUSEMOVE) {
    document.captureEvents(Event.MOUSEMOVE);
}

// Main function to retrieve mouse x-y pos.s

function getMouseXY(e) {

    var scrollTop = $(window).scrollTop();

    if (e && e.pageX) {
        mouseX = e.pageX;
        mouseY = e.pageY-scrollTop;
    } else {
        mouseX = event.clientX + document.body.scrollLeft;
        mouseY = event.clientY + document.body.scrollTop;
    }
    // catch possible negative values
    if (mouseX < 0) {
        mouseX = 0;
    }
    if (mouseY < 0) {
        mouseY = 0;
    }

    $('#map').next('.point').css({
        left: mouseX - 50,
        top: mouseY - 70
    })
}

// Set-up to use getMouseXY function onMouseMove
document.body.onmousemove = getMouseXY;


    function resizeMap(paper) {

        paper.changeSize(mapWidth, mapHeight, true, false);

        if (useSideText == 'true') {
            $(".mapWrapper").css({
                'width': (parseFloat(mapWidth, 10) + parseFloat(textAreaWidth, 10)) + 'px',
                'height': mapHeight + 'px'
            });
        } else {
            $(".mapWrapper").css({
                'width': mapWidth + 'px',
                'height': mapHeight + 'px'
            });
        }
    }
});
Be Brave Be Like Ukraine
  • 7,596
  • 3
  • 42
  • 66
LGLab
  • 31
  • 2

3 Answers3

0

You should use mouseenter and mouseleave events instead of mouseover and mouseout.

How to disable mouseout events triggered by child elements?

Community
  • 1
  • 1
Matt Esch
  • 22,661
  • 8
  • 53
  • 51
  • jQuery contains a solution and it's non-trivial. I don't advocate using jQuery to solve the problem but there is source to refer to at least and demonstrations of the behavior. No such solution exists in Raphael. I'd also mention that not all the solutions referred to are jQuery but they are generic. The problem is that child elements trigger mouseout events. That is the problem that needs solving and a generic solution is your only choice. – Matt Esch Jan 15 '13 at 10:55
0

Check out Jonathan Greene's raphael.set.hoverset.

djmccormick
  • 463
  • 4
  • 11
0

Im not sure what the problem exactly is here but if i understand correctly your trying to effect the area without effecting the text. The way i got around this was by pushing the two elements together

var North_Text = paper.set();
    North_Text.push(
    paper.text(80, 40, 'Dartford'),
    paper.circle(75, 32, 3)
);
North_Text.attr({
    id: 'North_Text',
}).data('id', 'North_Text');

var North_Kent = paper.set();
    var North = paper.circle(75, 32, 300);
    North.attr({id: 'West',parent: 'North_Kent'}).data('id', 'North');
North_Kent.attr({'id': 'North_Kent','name': 'North_Kent'});

North_Kent.push(North,North_Text);

and then used this function to effect the area independently of the text. Im pretty sure iv adapted this from something in the past and adjusted it to fit a variable function so i could place it in a for loop and effect multiple objects in an array.

// Variable function "theEndFunction"
var theEndFunction = function(areaGroups,area){
    areaGroups.mouseover(function(){
        area.attr({"fill":"#099f1d"});
        area.animate({ stroke: "#099f1d", 'stroke-width': 2, opacity: .75 }, 1000, 'elastic');

    if(Raphael.type != 'VML')
    areaGroups.toFront();
        });

    areaGroups.mouseout(function(){ 
        area.attr({"fill":"#39B54A"});
        area.stop().animate({ stroke: "#39B54A", 'stroke-width': 0, opacity: .75 }, 1000, 'elastic');
    }); 
}


theEndFunction(North_Kent,North);

I hope this helps in some way and if i get a chance later i'll try and throw up a fiddle

wellhairy
  • 23
  • 5