Home > other >  Simplifying a GeoJson FeatureCollection using mapshaper causes issues
Simplifying a GeoJson FeatureCollection using mapshaper causes issues

Time:04-01

More specifically, it causes the same code to render an outline on the map, and only recognizes the last path element when using pointer events. I simplified a continents.json file on mapshaper using their website and replaced the file in my public/data folder. Currently I'm fetching the data in one component and passing it down to another.

const WorldMapAtlas = () => {
    const [continents, continents] = useState<null | FeatureCollection>(null)

    useEffect(() => {
        fetch('data/continents_simple.json')
            .then(response => response.json())
            .then((worldData) => {
                let continents: FeatureCollection = (worldData as FeatureCollection)
                setContinents(continents)
            })
            .catch(error => console.log(error))        
    }, [])

    return (
        <>
            {continents &&
                 <div className="w-3/4" >
                     <TestMap projectionType={geoNaturalEarth1} GeoJson={continents} size={[928, 454]} translate={[464, 227]} />
                 </div>
            }
        </>
    )
}

I then try to render it with the TestMap Component

interface props {
    projectionType: () => GeoProjection;
    GeoJson: FeatureCollection | null;
    size: [number, number];
    translate: [number, number];
}

const TestMap = (props: props) => {
    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

When I use the unsimplifed json file it works fine. Each country is highlighted, but the strokewidth redraw takes a while. When all I do is change the fetch in WorldMapAtlas to the simplified json, an outline appears (which does not seems to be specific to one path, only disappears when all paths elements are deleted (dev tools)), and only the last feature in the json gets highlighted no matter where the cursor is.

The red dot is where my cursor is.

I've spent a lot of time on this, and I appreciate any help I could get! Thank you

Working Component

Non-Working Component

CodePudding user response:

After trying out a lot of different simplify options I feel silly. All you have to do is add the gj2008 option to the output command.

gj2008            [GeoJSON] use original GeoJSON spec (not RFC 7946)

This fixed all the problems! Although I have no idea why, I'm not sure how to check the original GeoJSON spec, and I'm not sure what the differences are. Hope this helps anyone who ran into the same problem!

  • Related