mariusandra / pigeon-maps

ReactJS Maps without external dependencies
https://pigeon-maps.js.org/
MIT License
3.45k stars 143 forks source link

[Feature] Handle geojson file as provider in <Map /> #210

Open OhMaley opened 4 months ago

OhMaley commented 4 months ago

Hello,

For an application I need to handle both online and offline mode. When in offline mode I wish to render the map using data stored in a json file that follows the Geojson format:

offlineMap.json:

{
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "geometry": {
                "type": "Polygon",
                "coordinates": [
                    [
                        [
                            -61.686668,
                            17.024441000000138
                        ],
                        [
                            -61.88722200000001,
                            17.033054000000106
                        ],
                        [
                            -61.794448999999986,
                            17.163330000000087
                        ],
                        [
                            -61.686668,
                            17.024441000000138
                        ]
                    ]
                ]
            },
        },
        {...}
    ]
}

I was looking at a way to render only the necessary tiles, may be using the tileComponent prop of <Map /> combined with the geojson-vt library.

I manage to extract the coordinates of the tile I want to render from the tile argument of the tileComponent function and then get my Tile object using the geojson library. But now I am unsure how use this object to return a dom element from the tileComponent function.

Here what I have done so far (only the necessary code in included):

render() {
    const geojsonTiles = geojsonvt(offlineGeojsonData); // offlineGeojsonData is imported from offlineMap.json
    const customTileComponent = ({ tile, tileLoaded }) => {
            const coords = tile.key.split('-');
            const x = parseInt(coords[0]);
            const y = parseInt(coords[1]);
            const z = parseInt(coords[2]);
            const tileIndex = geojsonTiles.getTile(z, x, y);
            return (
                <GeoJson data={tileIndex} /> // <-- This is where I struggle
            );
        }
    render (
        <Map defaultCenter={[50.879, 4.6997]} defaultZoom={11} height={600} tileComponent={customTileComponent} />
    );
}

Is there a way to achieve this using this library without the need to code low rendering layer like <svg> or <g> elements?

Or does anyone already faced this issue?

Any insight is welcome 😃

baldulin commented 4 months ago

Isn't the GeoJson component exactly what you are searching for?

OhMaley commented 4 months ago

Yes and I finally figured out how to make things work. The only issue that I have it that I am not able to integrate the geojon-vt functionality in this implementation.

So far I have done that:

mainComponent.jsx, in the render method

<CustomPigeonMap defaultCenter={[50.879, 4.6997]} defaultZoom={5} height={600} isOffline={offline} provider={this.cutomProvider}>
    <GeoJson data={offlineGeojsonData} />
</CustomPigeonMap>

CustomPigeonMap.jsx:

class CustomPigeonMap extends Map {
    constructor(props) {
        super(props);
        this.onlineRenderTilesFunc = this.renderTiles;
        this.offlineRenderTilesFunc = () => { };
        if (props.isOffline) {
            this.renderTiles = this.offlineRenderTilesFunc;
        } else {
            this.renderTiles = this.onlineRenderTilesFunc;
        }
    }

    componentDidUpdate(prevProps) {
        if (prevProps.isOffline !== this.props.isOffline) {
            if (this.props.isOffline) {
                this.renderTiles = this.offlineRenderTilesFunc;
            } else {
                this.renderTiles = this.onlineRenderTilesFunc;
            }
        }

    }
}

I will play a bit more to see if I find a way to use the geojon-vt in this implementation.

Thanks for the help !