react-leaflet-vectorgrid icon indicating copy to clipboard operation
react-leaflet-vectorgrid copied to clipboard

Use with react-leaflet 3.0

Open EGNKupava opened this issue 4 years ago • 24 comments

Hello there! I am trying to use react-leaflet-vectorgrid with react-leaflet 3.0. It doesn't work because in version 3.0 HOC 'withLeaflet' anymore doesn't exist. Who can help?

EGNKupava avatar Jan 20 '21 14:01 EGNKupava

+1

AndrejGajdos avatar Feb 08 '21 11:02 AndrejGajdos

I also have a need for this, anyone have any advice?

KoduIsGreat avatar Feb 25 '21 21:02 KoduIsGreat

https://codesandbox.io/s/gracious-fog-9d52v?file=/src/vector-grid.js

EGNKupava avatar Feb 27 '21 15:02 EGNKupava

@EGNKupava thank you, I will check it out.

AndrejGajdos avatar Feb 27 '21 18:02 AndrejGajdos

I start to port the original code to react-leaflet 3.0 and it work 90%, but for an unknown reason (I'm not familiar enough with React Hooks yet), the active state don't seem to work so the active state is not persistent (active is always null in clearHighlight()

If somebody want to correct that code, they're welcome!

import React, { useState } from 'react';
import { createTileLayerComponent, updateGridLayer } from '@react-leaflet/core';
import L from 'leaflet';
import isObject from 'lodash/isObject';
import isFunction from 'lodash/isFunction';
import isString from 'lodash/isString';
import isEmpty from 'lodash/isEmpty';
import clone from 'lodash/clone';
import cloneDeep from 'lodash/cloneDeep';
import extend from 'lodash/extend';
import merge from 'lodash/merge';
import has from 'lodash/has';
import find from 'lodash/find';
import 'leaflet.vectorgrid';

export const VectorGrid = createTileLayerComponent (
    function createTileLayer(props, context) {
        const [highlight, setHighlight] = useState(null);
        const [active, setActive] = useState(null);
        const {
            data,
            style,
            hoverStyle,
            activeStyle,
            onClick,
            onMouseover,
            onMouseout,
            onDblclick,
            onContextmenu,
            vectorTileLayerStyles,
            url,
            maxNativeZoom,
            subdomains,
            accessKey,
            accessToken,
            type = 'protobuf',
            interactive = true,
            idField = '',
            ...rest
        } = props;
        delete(rest.leaflet);

        const baseStyle = (properties, zoom) => {
            if (isFunction(style)) {
                return style(properties);
            } else if (isObject(style)) {
                return style;
            }
            return {
                weight: 0.5,
                opacity: 1,
                color: '#ccc',
                fillColor: '#390870',
                fillOpacity: 0.6,
                fill: true,
                stroke: true
            };
        };

        const _getFeatureId = (feature) => {
            const {
                idField
            } = props;
            if (isFunction(idField)) {
                return idField(feature);
            } else if (isString(idField)) {
                return feature.properties[idField];
            }
        }
        
        const setFeatureStyle = (id, style) => {
            vectorGrid.setFeatureStyle(id, style);
        }
    
        const resetFeatureStyle = (ids) => {
            ids.map((id) => {
                vectorGrid.resetFeatureStyle(id);
                return null;
            });
        }
    
        const clearHighlight = (featureId, _active) => {
            if (featureId && featureId !== _active) {
                resetFeatureStyle([featureId]);
            }
            if (highlight && highlight !== _active) {
                resetFeatureStyle(highlight);
            }
            setHighlight(null);
        }
    
        const clearActive = () => {
            if (active) {
                resetFeatureStyle(active);
            }
            setActive(null);
        }

        const getFeature = (featureId) => {
            const {
                data,
                idField
            } = props;
            if (isEmpty(data) || isEmpty(data.features)) return {};
            const feature = find(data.features, ({
                properties
            }) => properties[idField] === featureId);
            return cloneDeep(feature);
        }

        const _propagateEvent = (eventHandler, e) =>{
            if (!isFunction(eventHandler)) return; 
            const featureId = _getFeatureId(e.layer);
            const feature = getFeature(featureId);
            const event = cloneDeep(e);
            const mergedEvent = merge(event.target, {
                feature
            });
            eventHandler(event);
        }

        let vectorGrid;
        if (type === 'slicer') {
            vectorGrid = new L.vectorGrid.slicer(data, {
                interactive: interactive,
                getFeatureId: feature => _getFeatureId(feature),
                rendererFactory: L.svg.tile,
                vectorTileLayerStyles: vectorTileLayerStyles || {
                    sliced: (properties, zoom) => {
                        const bs = baseStyle(properties, zoom);
                        bs.fill = true;
                        bs.stroke = true;
                        return bs;
                    }
                },
                ...rest
            });
        } else {
            vectorGrid = new L.vectorGrid.protobuf(url, {
                interactive: interactive,
                key: accessKey,
                token: accessToken,
                vectorTileLayerStyles: vectorTileLayerStyles,
                getFeatureId: feature => _getFeatureId(feature),
                rendererFactory: L.canvas.tile,
                ...rest
            });
        }
        vectorGrid.on('mouseover', (e) => {
            const {
                properties
            } = e.layer;
            _propagateEvent(onMouseover, e);
            let st;
            const featureId = _getFeatureId(e.layer);
            if (isFunction(hoverStyle)) {
                st = hoverStyle(properties);
            } else if (isObject(hoverStyle)) {
                st = cloneDeep(hoverStyle);
            }
            if (!isEmpty(st) && featureId) {
                clearHighlight();
                setHighlight(featureId);
                const base = cloneDeep(baseStyle(properties));
                const hoverStyle = extend(base, st);
                setFeatureStyle(featureId, hoverStyle);
            }
        })
        .on('mouseout', (e) => {
            _propagateEvent(onMouseout, e);
            const featureId = _getFeatureId(e.layer);
            clearHighlight(featureId, active);
        })
        .on('click', (e) => {
            const {
                properties
            } = e.layer;
            const featureId = _getFeatureId(e.layer);
            _propagateEvent(onClick, e);
            let st;
            if (isFunction(activeStyle)) {
                st = activeStyle(properties);
            } else if (isObject(activeStyle)) {
                st = cloneDeep(activeStyle);
            }
            if (!isEmpty(st) && featureId) {
                clearActive();
                setActive(featureId);
                const base = cloneDeep(baseStyle(properties));
                const activeStyle = extend(base, st);
                setFeatureStyle(featureId, activeStyle);
            }
        })
        .on('dblclick', (e) => {
            _propagateEvent(onDblclick, e);
            clearActive();
        })
        .on('contextmenu', (e) => {
            _propagateEvent(onContextmenu, e);
            clearActive();
        });

        return {
            instance: vectorGrid,
            context
        }
    }, 
    function upgrade(layer, props, prevprops) {
        return updateGridLayer(layer, props, prevprops)
    }
)

export default VectorGrid;

FredChauviere avatar Sep 17 '21 14:09 FredChauviere

I'm fairly certain you need to use a ref, because leaflet maintains its own state. I would look into the useRef hook provided by react

KoduIsGreat avatar Sep 17 '21 14:09 KoduIsGreat

Oh my god, you are right. I really need to invest more time learning React Hooks : I learned React through Class Components and the switch to Function Component is really hard now...

Here's my corrected code that now seems to work 95% : (FYI, I did not port the Popup management code)

import { useRef } from 'react';
import { createTileLayerComponent, updateGridLayer } from '@react-leaflet/core';
import L from 'leaflet';
import isObject from 'lodash/isObject';
import isFunction from 'lodash/isFunction';
import isString from 'lodash/isString';
import isEmpty from 'lodash/isEmpty';
import clone from 'lodash/clone';
import cloneDeep from 'lodash/cloneDeep';
import extend from 'lodash/extend';
import merge from 'lodash/merge';
import has from 'lodash/has';
import find from 'lodash/find';
import 'leaflet.vectorgrid';


export const VectorGrid = createTileLayerComponent (
    function createTileLayer(props, context) {
        const highlight = useRef(null);
        const active = useRef(null);
        const {
            data,
            style,
            hoverStyle,
            activeStyle,
            onClick,
            onMouseover,
            onMouseout,
            onDblclick,
            onContextmenu,
            vectorTileLayerStyles,
            url,
            maxNativeZoom,
            subdomains,
            accessKey,
            accessToken,
            type = 'protobuf',
            interactive = true,
            idField = '',
            ...rest
        } = props;
        delete(rest.leaflet);

        const baseStyle = (properties, zoom) => {
            if (isFunction(style)) {
                return style(properties);
            } else if (isObject(style)) {
                return style;
            }
            return {
                weight: 0.5,
                opacity: 1,
                color: '#ccc',
                fillColor: '#390870',
                fillOpacity: 0.6,
                fill: true,
                stroke: true
            };
        };

        const _getFeatureId = (feature) => {
            const {
                idField
            } = props;
            if (isFunction(idField)) {
                return idField(feature);
            } else if (isString(idField)) {
                return feature.properties[idField];
            }
        }
        
        const setFeatureStyle = (id, style) => {
            vectorGrid.setFeatureStyle(id, style);
        }
    
        const resetFeatureStyle = (id) => {
            vectorGrid.resetFeatureStyle(id);
        }
    
        const clearHighlight = (properties) => {
            if (highlight.current) {
                if (highlight.current !== active.current) {
                    resetFeatureStyle(highlight.current);
                } else {
                    let st;
                    if (isFunction(activeStyle)) {
                        st = activeStyle(properties);
                    } else if (isObject(activeStyle)) {
                        st = cloneDeep(activeStyle);
                    }
                    if (!isEmpty(st)) {
                        const base = cloneDeep(baseStyle(properties));
                        const activeStyle = extend(base, st);
                        setFeatureStyle(active.current, activeStyle);
                    }
                }
            }
            highlight.current = null;
        }
    
        const clearActive = () => {
            if (active.current) {
                resetFeatureStyle(active.current);
            }
            active.current = null;
        }

        const getFeature = (featureId) => {
            const {
                data,
                idField
            } = props;
            if (isEmpty(data) || isEmpty(data.features)) return {};
            const feature = find(data.features, ({
                properties
            }) => properties[idField] === featureId);
            return cloneDeep(feature);
        }

        const _propagateEvent = (eventHandler, e) =>{
            if (!isFunction(eventHandler)) return; 
            const featureId = _getFeatureId(e.layer);
            const feature = getFeature(featureId);
            const event = cloneDeep(e);
            const mergedEvent = merge(event.target, {
                feature
            });
            eventHandler(event);
        }

        let vectorGrid;
        if (type === 'slicer') {
            vectorGrid = new L.vectorGrid.slicer(data, {
                interactive: interactive,
                getFeatureId: feature => _getFeatureId(feature),
                rendererFactory: L.svg.tile,
                vectorTileLayerStyles: vectorTileLayerStyles || {
                    sliced: (properties, zoom) => {
                        const bs = baseStyle(properties, zoom);
                        bs.fill = true;
                        bs.stroke = true;
                        return bs;
                    }
                },
                ...rest
            });
        } else {
            vectorGrid = new L.vectorGrid.protobuf(url, {
                interactive: interactive,
                key: accessKey,
                token: accessToken,
                vectorTileLayerStyles: vectorTileLayerStyles,
                getFeatureId: feature => _getFeatureId(feature),
                rendererFactory: L.canvas.tile,
                ...rest
            });
        }
        vectorGrid.on('mouseover', (e) => {
            const {
                properties
            } = e.layer;
            _propagateEvent(onMouseover, e);
            let st;
            const featureId = _getFeatureId(e.layer);
            if (isFunction(hoverStyle)) {
                st = hoverStyle(properties);
            } else if (isObject(hoverStyle)) {
                st = cloneDeep(hoverStyle);
            }
            if (!isEmpty(st) && featureId) {
                clearHighlight(properties);
                highlight.current = featureId;
                const base = cloneDeep(baseStyle(properties));
                const hoverStyle = extend(base, st);
                setFeatureStyle(featureId, hoverStyle);
            }
        })
        .on('mouseout', (e) => {
            const {
                properties
            } = e.layer;
            _propagateEvent(onMouseout, e);
            clearHighlight(properties);
        })
        .on('click', (e) => {
            const {
                properties
            } = e.layer;
            const featureId = _getFeatureId(e.layer);
            _propagateEvent(onClick, e);
            let st;
            if (isFunction(activeStyle)) {
                st = activeStyle(properties);
            } else if (isObject(activeStyle)) {
                st = cloneDeep(activeStyle);
            }
            if (!isEmpty(st) && featureId) {
                clearActive();
                active.current = featureId;
                const base = cloneDeep(baseStyle(properties));
                const activeStyle = extend(base, st);
                setFeatureStyle(featureId, activeStyle);
            }
        })
        .on('dblclick', (e) => {
            _propagateEvent(onDblclick, e);
            clearActive();
        })
        .on('contextmenu', (e) => {
            _propagateEvent(onContextmenu, e);
            clearActive();
        });

        return {
            instance: vectorGrid,
            context
        }
    }, 
    function upgrade(layer, props, prevprops) {
        return updateGridLayer(layer, props, prevprops)
    }
)

export default VectorGrid;

FredChauviere avatar Sep 17 '21 15:09 FredChauviere

I'm on a roll, I fixed the Tooltip and Popup code: (Thanks to @KoduIsGreat again)

import { useEffect, useRef } from 'react';
import { createTileLayerComponent, updateGridLayer } from '@react-leaflet/core';
import L from 'leaflet';
import isObject from 'lodash/isObject';
import isFunction from 'lodash/isFunction';
import isString from 'lodash/isString';
import isEmpty from 'lodash/isEmpty';
import clone from 'lodash/clone';
import cloneDeep from 'lodash/cloneDeep';
import extend from 'lodash/extend';
import merge from 'lodash/merge';
import has from 'lodash/has';
import find from 'lodash/find';
import leaflet.vectorgrid;

export const VectorGrid = createTileLayerComponent (
    function createTileLayer(props, context) {
        const highlight = useRef(null);
        const active = useRef(null);
        const {
            data,
            style,
            hoverStyle,
            activeStyle,
            onClick,
            onMouseover,
            onMouseout,
            onDblclick,
            onContextmenu,
            vectorTileLayerStyles,
            url,
            maxNativeZoom,
            subdomains,
            accessKey,
            accessToken,
            type = 'protobuf',
            interactive = true,
            idField = '',
            ...rest
        } = props;
        delete(rest.leaflet);

        useEffect(() => {
            const {
                tooltipClassName = '',
                tooltip = null,
                popup = null
            } = props;
            if (tooltip) {
                vectorGrid.bindTooltip((layer) => {
                    if (isFunction(tooltip)) {
                        return tooltip(layer);
                    } else if (isString(tooltip) && has(layer.properties, tooltip)) {
                        return String(layer.properties[tooltip]);
                    } else if (isString(tooltip)) {
                        return tooltip;
                    }
                    return '';
                }, {
                    sticky: true,
                    direction: 'auto',
                    className: tooltipClassName
                });
            }
            if (popup) {
                vectorGrid.bindPopup(popup);
            }     
        }, [props.tooltip, props.popup]);

        const baseStyle = (properties, zoom) => {
            if (isFunction(style)) {
                return style(properties);
            } else if (isObject(style)) {
                return style;
            }
            return {
                weight: 0.5,
                opacity: 1,
                color: '#ccc',
                fillColor: '#390870',
                fillOpacity: 0.6,
                fill: true,
                stroke: true
            };
        };

        const _getFeatureId = (feature) => {
            const {
                idField
            } = props;
            if (isFunction(idField)) {
                return idField(feature);
            } else if (isString(idField)) {
                return feature.properties[idField];
            }
        }
        
        const setFeatureStyle = (id, style) => {
            vectorGrid.setFeatureStyle(id, style);
        }
    
        const resetFeatureStyle = (id) => {
            vectorGrid.resetFeatureStyle(id);
        }
    
        const clearHighlight = (properties) => {
            if (highlight.current) {
                if (highlight.current !== active.current) {
                    resetFeatureStyle(highlight.current);
                } else {
                    let st;
                    if (isFunction(activeStyle)) {
                        st = activeStyle(properties);
                    } else if (isObject(activeStyle)) {
                        st = cloneDeep(activeStyle);
                    }
                    if (!isEmpty(st)) {
                        const base = cloneDeep(baseStyle(properties));
                        const activeStyle = extend(base, st);
                        setFeatureStyle(active.current, activeStyle);
                    }
                }
            }
            highlight.current = null;
        }
    
        const clearActive = () => {
            if (active.current) {
                resetFeatureStyle(active.current);
            }
            active.current = null;
        }

        const getFeature = (featureId) => {
            const {
                data,
                idField
            } = props;
            if (isEmpty(data) || isEmpty(data.features)) return {};
            const feature = find(data.features, ({
                properties
            }) => properties[idField] === featureId);
            return cloneDeep(feature);
        }

        const _propagateEvent = (eventHandler, e) =>{
            if (!isFunction(eventHandler)) return; 
            const featureId = _getFeatureId(e.layer);
            const feature = getFeature(featureId);
            const event = cloneDeep(e);
            const mergedEvent = merge(event.target, {
                feature
            });
            eventHandler(event);
        }

        let vectorGrid;
        if (type === 'slicer') {
            vectorGrid = new L.vectorGrid.slicer(data, {
                interactive: interactive,
                getFeatureId: feature => _getFeatureId(feature),
                rendererFactory: L.svg.tile,
                vectorTileLayerStyles: vectorTileLayerStyles || {
                    sliced: (properties, zoom) => {
                        const bs = baseStyle(properties, zoom);
                        bs.fill = true;
                        bs.stroke = true;
                        return bs;
                    }
                },
                ...rest
            });
        } else {
            vectorGrid = new L.vectorGrid.protobuf(url, {
                interactive: interactive,
                key: accessKey,
                token: accessToken,
                vectorTileLayerStyles: vectorTileLayerStyles,
                getFeatureId: feature => _getFeatureId(feature),
                rendererFactory: L.canvas.tile,
                ...rest
            });
        }
        vectorGrid.on('mouseover', (e) => {
            const {
                properties
            } = e.layer;
            _propagateEvent(onMouseover, e);
            let st;
            const featureId = _getFeatureId(e.layer);
            if (isFunction(hoverStyle)) {
                st = hoverStyle(properties);
            } else if (isObject(hoverStyle)) {
                st = cloneDeep(hoverStyle);
            }
            if (!isEmpty(st) && featureId) {
                clearHighlight(properties);
                highlight.current = featureId;
                const base = cloneDeep(baseStyle(properties));
                const hoverStyle = extend(base, st);
                setFeatureStyle(featureId, hoverStyle);
            }
        })
        .on('mouseout', (e) => {
            const {
                properties
            } = e.layer;
            _propagateEvent(onMouseout, e);
            clearHighlight(properties);
        })
        .on('click', (e) => {
            const {
                properties
            } = e.layer;
            const featureId = _getFeatureId(e.layer);
            _propagateEvent(onClick, e);
            let st;
            if (isFunction(activeStyle)) {
                st = activeStyle(properties);
            } else if (isObject(activeStyle)) {
                st = cloneDeep(activeStyle);
            }
            if (!isEmpty(st) && featureId) {
                clearActive();
                active.current = featureId;
                const base = cloneDeep(baseStyle(properties));
                const activeStyle = extend(base, st);
                setFeatureStyle(featureId, activeStyle);
            }
        })
        .on('dblclick', (e) => {
            _propagateEvent(onDblclick, e);
            clearActive();
        })
        .on('contextmenu', (e) => {
            _propagateEvent(onContextmenu, e);
            clearActive();
        });

        return {
            instance: vectorGrid,
            context
        }
    }, 
    function upgrade(layer, props, prevprops) {
        return updateGridLayer(layer, props, prevprops)
    }
)

export default VectorGrid;

FredChauviere avatar Sep 17 '21 16:09 FredChauviere

I am aware this isn't the most elegant solution, but I managed to do this simple react component as a wrapper of leaflet.js, and it works with react-leaflet-v3, so I hope this is helpful for some else out there:

import { useEffect } from "react"; import { useLeafletContext } from "@react-leaflet/core";

import L from "leaflet";

import "leaflet.vectorgrid";

export default function VectorGrid(props) { const { layerContainer, map } = useLeafletContext();

var url = "http://localhost:8082/river_network/{z}/{x}/{y}.pbf";

let options = { rendererFactory: L.canvas.tile, attribution: '© something', };

const vectorGrid = L.vectorGrid.protobuf(url, options);

const container = layerContainer || map;

useEffect(() => { container.addLayer(vectorGrid); return () => { container.removeLayer(vectorGrid); }; }, []);

return null; }

seospinale avatar Dec 16 '21 18:12 seospinale

I am aware this isn't the most elegant solution, but I managed to do this simple react component as a wrapper of leaflet.js, and it works with react-leaflet-v3, so I hope this is helpful for some else out there:

import { useEffect } from "react"; import { useLeafletContext } from "@react-leaflet/core";

import L from "leaflet";

import "leaflet.vectorgrid";

export default function VectorGrid(props) { const { layerContainer, map } = useLeafletContext();

var url = "http://localhost:8082/river_network/{z}/{x}/{y}.pbf";

let options = { rendererFactory: L.canvas.tile, attribution: '© something', };

const vectorGrid = L.vectorGrid.protobuf(url, options);

const container = layerContainer || map;

useEffect(() => { container.addLayer(vectorGrid); return () => { container.removeLayer(vectorGrid); }; }, []);

return null; }

You are a lifesaver, thank you! One minor thing, I needed to add this line to my index.html

<script src="https://unpkg.com/leaflet.vectorgrid@latest/dist/Leaflet.VectorGrid.bundled.js"></script>

tobiRss avatar Dec 17 '21 15:12 tobiRss

Do any of you know what else needs to be done for this to work with leaflet 1.8, react-leaflet 4.0 and react 18 ?

flacoman91 avatar May 20 '22 21:05 flacoman91

Do any of you know what else needs to be done for this to work with leaflet 1.8, react-leaflet 4.0 and react 18 ?

+1

jhoanborges avatar Jul 15 '22 16:07 jhoanborges

Do any of you know what else needs to be done for this to work with leaflet 1.8, react-leaflet 4.0 and react 18 ?

+1

CrazyKidJack avatar Sep 28 '22 21:09 CrazyKidJack

I created a sample project using create react app that has these working. I hope this helps. https://github.com/flacoman91/react-18-vector-grid-example

The most confusing part for me was understanding the new contexts and the functional component syntax.

You can probably hack around and follow the examples from leaflet vectorgrid here https://github.com/Leaflet/Leaflet.VectorGrid

flacoman91 avatar Sep 29 '22 02:09 flacoman91

I created a sample project using create react app that has these working. I hope this helps. https://github.com/flacoman91/react-18-vector-grid-example

The most confusing part for me was understanding the new contexts and the functional component syntax.

You can probably hack around and follow the examples from leaflet vectorgrid here https://github.com/Leaflet/Leaflet.VectorGrid

Thank you so much for this! I have a couple of questions if you don't mind:

  1. Why do you have react-leaflet-vectorgrid in your package.json if you included your own rewritten version?
  2. Looking at your VectorGris.js, am I correct to conclude that you have not implemented the entire react-leaflet-vectorgrid wrapper, only the part for loading pre-created tiles from a tile server (protobuf)
  3. I see in other people's previous comments that they had to do some extra work to make things like popups and tooltips work... does your code support those things? Or no would I need to make those work myself?

CrazyKidJack avatar Sep 29 '22 22:09 CrazyKidJack

@CrazyKidJack You're correct.

You need to include react-leaflet-vectorgrid to get the protobuf part working.

Yes, you have do do a little bit more work to get the other stuff working, but it's really not that hard once you've seen the code working. I can add some more examples so you can see how it works.

flacoman91 avatar Sep 29 '22 23:09 flacoman91

@CrazyKidJack You're correct.

You need to include react-leaflet-vectorgrid to get the protobuf part working.

Yes, you have do do a little bit more work to get the other stuff working, but it's really not that hard once you've seen the code working. I can add some more examples so you can see how it works.

Thanks for the speedy reply :) You're right that I can probably figure it out from this. Been look at it about 45minutes and the connections between your version and the original are starting to be come clear.

But more examples always more better if you don't mind providing them :D I'm sure they would help me progress faster

Thanks in advance for your awesomeness

CrazyKidJack avatar Sep 29 '22 23:09 CrazyKidJack

You need to include react-leaflet-vectorgrid to get the protobuf part working.

Is there an easy way for you to explain why? Again, I bet I could figure it out (starting to look at that now)... but if you know and can explain it without it being a burden that would be appreciated.

CrazyKidJack avatar Sep 29 '22 23:09 CrazyKidJack

You need to include react-leaflet-vectorgrid to get the protobuf part working.

Is there an easy way for you to explain why? Again, I bet I could figure it out (starting to look at that now)... but if you know and can explain it without it being a burden that would be appreciated.

I'm not sure. I remember it not working correctly if I tried to remove the dependency and removing import 'leaflet.vectorgrid'; also causes it to fail.

I think Leaflet has some stuff that are in global scope. I'm not an expert by any means, but I remember spending a good amount of time trying to get things going.

I've updated the example code with the react-leaflet plugins for markers, and circles.

You actually can write your own wrappers around any of the plugins that you see in https://leafletjs.com/plugins.html#markers--renderers

There's way more you can do with interactivity if you add the markers into another component and use some state management like redux to dynamically add/hide/show things. With the vectorgrid, you can tie mouseover/click events into the shapes to do anything you want.

Typically I console.log everywhere to figure out what is going on.

flacoman91 avatar Sep 30 '22 00:09 flacoman91

I'm not sure. I remember it not working correctly if I tried to remove the dependency and removing import 'leaflet.vectorgrid'; also causes it to fail.

Hey so my friend and I looked at it and I think your problem was just that your actual dependency is leaflet.vectorgrid but you didn't include that library directly in your package.json.

The reason that putting react-leaflet-vectorgrid in your package.json fixed it, is because react-leaflet-vectorgrid itself includes leaflet.vectorgrid for you.

So tldr: if you just change your package.json from:

"dependencies": {
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "leaflet": "^1.9.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-leaflet": "^4.1.0",
    "react-leaflet-vectorgrid": "^2.2.1", // CHANGE THIS LINE
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },

to

"dependencies": {
  "@testing-library/jest-dom": "^5.16.5",
  "@testing-library/react": "^13.4.0",
  "@testing-library/user-event": "^13.5.0",
  "leaflet": "^1.9.1",
  "react": "^18.2.0",
  "react-dom": "^18.2.0",
  "react-leaflet": "^4.1.0",
  "leaflet.vectorgrid": "^1.3.0", // CHANGE THIS LINE
  "react-scripts": "5.0.1",
  "web-vitals": "^2.1.4"
},

without making any other changes, it should work fine :).

CrazyKidJack avatar Sep 30 '22 00:09 CrazyKidJack

@CrazyKidJack awesome!

Thanks for pointing that out. Hooray for open source. I updated the example to demonstrate some of the vectorgrid events.

flacoman91 avatar Sep 30 '22 01:09 flacoman91

@CrazyKidJack awesome!

Thanks for pointing that out. Hooray for open source. I updated the example to demonstrate some of the vectorgrid events.

Nono, thank you for continuing to update that example! It's really helping me :)

CrazyKidJack avatar Sep 30 '22 14:09 CrazyKidJack

@flacoman91 Could you help me understand a couple of things in this code block: image

I just don't understand what the "style" and "type" options are for. I don't understand what they control or where they are consumed. I looked through the Leaflet.VectorGrid documentation and source code as well as the Leaflet documentation and some of the source code and I just don't understand.

I do understand that rendererFactory, interactive, and vectorTyleLayerStyles come from the Leaflet.VectorGrid API/documentation: image

I do understand that the "apiKey" comes form the url template: image

But I don't understand what those other two options are for, how they are used, what consumes them, and where the documentation for them is. I thought maybe this was something you added yourself but I didn't see any thing obvious that was using them.

Any help would be appreciated :)

CrazyKidJack avatar Oct 08 '22 23:10 CrazyKidJack

@CrazyKidJack what service are you using to serve up your tiles?

I just copy pasted the example from https://github.com/Leaflet/Leaflet.VectorGrid#dependencies

I think type:protobuf is how the data is read.
If you're using geojson, the type should be slicer

https://github.com/mapbox/vector-tile-spec

The source of your data will determine the protocol that can be used. For work, we use mapbox and vector tiles.

Style is how you want the specific features to look.

the demo here: view-source:https://leaflet.github.io/Leaflet.VectorGrid/demo-vectortiles.html

looks like it's broken, but thats how you can provide a different style for each feature that comes back from the tiles.

Feel free to comment/ open a ticket on the the demo repo I created. I should update it with more advanced examples. I need to find a public demo url/key to mapbox or some other provider. That's a big issue with demonstrating all of these features.

flacoman91 avatar Oct 11 '22 16:10 flacoman91