Home > other >  onClick isn't working with svg or svg path with ReactJs
onClick isn't working with svg or svg path with ReactJs

Time:03-29

I've looked everywhere trying to figure this out. I have a basic svg element with a single path element inside. Nothing I can do will get the onClick function to fire. It will fire if pass the handleClick to the div, but I need to be able to fire an onClick event on specific paths.

const handleClick = () => {
    alert('clicked')
}

return (
        <div className="bg-blue-400">
            <svg viewBox={`0 0 ${props.size[0]} ${props.size[1]}`} onClick={() => handleClick()}>
                <g>
                    <path
                        d={outline}
                        stroke="black"
                        fill="aliceblue"
                        strokeWidth={0.5}
                        strokeDasharray="10,10"
                        onClick={() => alert('path was clicked')}
                    />
                 </g>
             </svg>
         </div>
)

Any help is greatly appreciated!

CodePudding user response:

I fleshed out your code and defined outline from an example online and it works fine. When I click the heart shape this draws, the 'path was clicked' alert displays, when I click OK on that to close it, the 'clicked' alert appears to have been behind it, so I guess that was triggered first?

import React from 'react';


const Comp = (props) => {
    const handleClick = () => {
        alert('clicked')
    }
    const outline = `M 10,30
       A 20,20 0,0,1 50,30
       A 20,20 0,0,1 90,30
       Q 90,60 50,90
       Q 10,60 10,30 z`;
       
    return (
            <div className="bg-blue-400">
                <svg viewBox={`0 0 ${props.size[0]} ${props.size[1]}`} onClick={() => handleClick()}>
                    <g>
                        <path
                            d={outline}
                            stroke="black"
                            fill="aliceblue"
                            strokeWidth={0.5}
                            strokeDasharray="10,10"
                            onClick={() => alert('path was clicked')}
                        />
                     </g>
                 </svg>
             </div>
    )}

export const App = () => {
    return(<div>
        <Comp size={[400, 400]}/>
    </div>)
}

export default App;

Defined a css file with

.bg-blue-400  {
     background-color: blue;
}

The only thing I can imagine is causing your problem is maybe how outlineis defined, or the size props?

CodePudding user response:

So far nothing I've done seems to worked. I then trying to use a different method where I use d3 and useRef to display the svg and add the pointer events, and that seems to have worked so far.

    const svgRef = useRef(null)
    const [height, width] = props.size;

    useEffect(() => {
        //accesses the reference element
        const svg = d3.select(svgRef.current)
 
        //declares the geoJson, projection, and path(pathGenerator)
        const geoJson = props.GeoJson
        const projection = props.projectionType()
            .fitSize(props.size, geoGraticule10())
            .translate(props.translate)      
        const path = d3.geoPath().projection(projection)

        //uses d3 to inject the data into the svg element
        const features = svg.selectAll(".country")
            .data(geoJson ? geoJson.features : [])
            .enter().append("path")

            //basic styling attributes
            .attr("d", path)
            .attr("fill", "none")
            .attr("stroke", "aliceblue")
            .attr("stroke-width", "0.5px")

            //allows pointer events anywhere inside the path even when fill=none
            .attr("pointer-events", "visibleFill")
            .attr("visibility", "visible")

            //sets the path element id to the continent name
            .attr("id", (d) => {
                 return `${d.properties.continent}`
            })

            //selects the current continent and highlights it by increasing the stroke width
            .on("mouseover", (d,i) => {
                svg.select(`#${i.properties.continent}`).attr("stroke-width", "2px")
            })

            //deselects
            .on("mouseleave", (d,i) => {
                svg.select(`#${i.properties.continent}`).attr("stroke-width", "0.5px")
            })

            //adds the .country attribute to allow for later updates on the svg element
            .attr("class", "country")
    }, [geoJson]);

    return (
        <div className="bg-blue-400">
            <svg ref={svgRef} viewBox={`0 0 ${props.size[0]} ${props.size[1]}`} />
        </div>
    )
}

export default TestMap

This is working with a different json file but works the same with the original path

  • Related