Saturday, 14 August 2021

d3.js hiding popups with opacity not working properly with pointer events

I am in dire need of help. I've spent over a week trying to figure out why I can't get this to work. I have a map in d3 with points overlaid. I want the user to be able to click the points and bring up a popup that will be scrollable. Then when user clicks off (anywhere on the body) I want the popup to disappear. The same is true for mouseover - show popup on mouseover, hide on mouseout.

Here’s the website : https://shmoss.github.io/Town_Sounds/#

My issue:

My code works absolutely fine on desktop, as well as my iphone 11. However, when testing on other iphones, if I open a popup, click off, and then re-click on another one, the popup is frozen. It doesn't scroll, i.e. it appears pointer events are disabled. Video at bottom.

Here's my code, tried to make as concise as possible:

//build d3 events (circles)
var events = mapG.selectAll("circle")
        .data(eventArray)
        .enter().append("circle")
        .style("class", 'events')
        .on("mouseover", function(d) { 

            //add popup - set opacity to make visible
            LeafletDiv.transition()        
                .duration(200)      
                .style("opacity", .9)
                .style("scrollTop", 0)


                var popInfo = '<br>' + d.Venue + '<br>' 

                LeafletDiv
                .html(popInfo)
                .style("top", "1.5vh")
                .style("text-align", 'left')

        }
       
    //on-click event
    .on("click", function(d) { 
        $('body').css({
            overflow: 'hidden'
        });

        //disable hover event listeners
        d3.selectAll(".events").on("mouseout", null);
        d3.selectAll(".events").on("mouseover", null);

        //add popup   
        var value2014 = currentMap.get(d.location);  

        LeafletDiv.transition()        
            .duration(200)      
            .style("opacity", .9);

                selections = d3.selectAll(".events").filter(function(d){

                return d.Date == this_date 

                })

                //populate html for popup
                var appendText = []
                selections.each(function(d){

                var popInfo = '<br>' + d.Venue + '<br>'                   
                appendText.push(popInfo+ '<br/>' + '<br/>')
              
                })
            //append html to popup                 
            LeafletDiv
                .html( appendText.join(""))
                .style("top", "1.5vh")
                .style("text-align", 'left')
                .style("pointer-events", 'auto')
          

        $('.county2014Tooltip').scrollTop(0);

        d3.event.stopPropagation();

        // if user clicks a SECOND time, anywhere, make popup disappear
        d3.select("body").on("click", function(d) { 
            console.log("clicking off popup")

                //hide popup
                var elements = d3.select(LeafletDiv)
                elements.scrollTop = 0
       
                LeafletDiv.transition()        
                    .duration(200)      
                    .style("opacity", 0)
                    .style("pointer-events", 'none') 
                    .attr("scrollTop", 0) 
                    //revert back to hover, unless user clicks again!
                    d3.selectAll(".events").on("mouseout", true);
                    d3.selectAll(".events").on("mouseover", true);
                    d3.selectAll(".events").on("mouseout", function(d) { 
                    //mousing out, hide popup!     
                    LeafletDiv.transition()        
                        .duration(200)      
                        .style("opacity", 0);        
                    })

                    // mouseover event listers added back in
                    d3.selectAll(".events").on("mouseover", function(d) { 
                    LeafletDiv.transition()        
                        .duration(200)      
                        .style("opacity", .9);

                    LeafletDiv .html('<br>' + d.Venue + '<br>'
                    )
                        .style("top", "1.5vh")
                        .style("text-align", 'left')

                })
                      
        })
    })

    //on mouseout, hide popup
    .on("mouseout", function(d) {       
        LeafletDiv.transition()        
            .duration(200)      
            .style("opacity", 0)
            .style("scrollTop", 0)  
    })

Videos documenting the behavior:

An iphone 11 (same exact code, but working as expected):

https://www.youtube.com/watch?v=_3MA4bJYiYM

Other iphone 11 (same exact code, not working:)

https://www.youtube.com/watch?v=OfbboDnIw1E

What I've tried:

For some reason, using transform scale(0) with a duration of 200 ms works. As an alternative to the current method of opacity, this work. But it looks unprofessional and I'm baffled why the above code doesn't work universally. Thanks in advance!



from d3.js hiding popups with opacity not working properly with pointer events

No comments:

Post a Comment