4

I'm attempting to completely recreate or reorganize the functionality of the LayersControl component in its own separate panel using react-leaflet.

I have several filtered into their own and it works fine, but I'd like to customize the look and location of the Control element.

I've hosted the current version of my Leaflet app on github pages here. You can see the control on the right, which is the basic Leaflet control, but I'd like to the Icon on the left (the layers icon) to accomplish the same thing instead with custom react components.

Just wondering if anyone can point me in the right direction to beginning to accomplish this!

This is my current render for my react-leaflet map:

render() {

      const types = [...new Set(data.map(loc => loc.type))];

      const group = types.map(type =>
        data.filter(loc => loc.type === type)
        .map(({id, lat, lng, name}) =>
          <LayersControl.Overlay name={startCase(toLower(type))}>
            <LayerGroup>
            <Marker key={id} position={[lat, lng]} icon=
              {locationIcon}>
              <Tooltip permanent direction="bottom" opacity={.6}>
                  {name}
              </Tooltip>
          </Marker>
            </LayerGroup>
          </LayersControl.Overlay>
          ));

      return (
        <>
        <ControlPanel />
        <Map
        zoomControl={false}
        center={this.state.center}
        zoom={this.state.zoom}
        maxBounds={this.state.maxBounds}
        maxZoom={10}
        >
          <LayersControl>
            <TileLayer
              url='https://cartocdn-gusc.global.ssl.fastly.net//ramirocartodb/api/v1/map/named/tpl_756aec63_3adb_48b6_9d14_331c6cbc47cf/all/{z}/{x}/{y}.png'
            />
            <ZoomControl position="topright" />
           {group}
          </LayersControl>
        </Map>
        </>
      );
    }
3
  • If you use react-leaflet you need to extend one of its abstract classes provided by React-Leaflet, in your particular case MapControl to implement your custom control behavior. What do you want to achieve in your custom Control? Commented Jan 19, 2019 at 11:17
  • Just toggle different Layers that contain Markers specific to that group. Basically just change the look of the already existing layercontrol Commented Jan 19, 2019 at 16:32
  • Could you be a little more specific? What would you like to change regarding the style?f.i the background color of the layercontrol, the radio buttons... Commented Jan 21, 2019 at 13:43

3 Answers 3

4

So theres still a few bugs in this but i've managed get most of the way (self taught react) using material UI as an example, can be seen in this sandbox link:

https://codesandbox.io/embed/competent-edison-wt5pl?fontsize=14

The general bassis is that we extend MapControl which means we have to define createLeafletElement, this has to return a generic leaflet (not react) control from the original javascript leaflet package. Essentially making a div with the domutil provided by leaflet and then portaling our react components through that div with react portals.

Again with another class extension we extend some of the classes provided by react-leaflet for layers, i pulled it out and just made a generic layer that you could define a group for, that way you could render any layer (polygon, baselayer etc) and specify the group to tell it where to go in the layer control i.e no need for specific components or overlays. As we are extending the class we need implement and pass down the methods we want to use, like addLayer, remove layer etc. During these implementations i've just added them to state to track what layers are active and such.

Not sure if there are better practices throughout everything i've implemented but this is definitely a start, hopefully in the right direction.

Bugs - The first layer in each group won't turn on correctly without the 2nd item ticked, something to do with state i think but didn't have the time to track it down

Sign up to request clarification or add additional context in comments.

Comments

1

Thanks Dylan and Peter for this nice React Leaflet custom control approach. I assumed there was still a bug in the toggleLayer function. It's checked multiple checkboxes and the layers won't change properly. So I restructered a little bit and now it should work fine.

toggleLayer = layerInput => {
    const { name, group } = layerInput;
    let layers = { ...this.state.layers };

    layers[group] = layers[group].map(l => {
        l.checked = false;
        this.removeLayer(l.layer);
        if (l.name === name) {
            l.checked = !l.checked;
            this.props.leaflet.map.addLayer(l.layer);
        } 
        return l;
    });

    this.setState({
        layers
    });
};

Comments

0

Just to elaborate on the bug that is mentioned in Dylans answer...

If you have more then one ControlledLayerItem, none items are added to the map until the very last item is checked. To fix this, the toggleLayer method in ControlLayer2.js has to be slightly modified:

toggleLayer = layerInput => {
 const { layer, name, checked, group } = layerInput;

 let layers = { ...this.state.layers };
 layers[group] = layers[group].map(l => {
  if (l.name === name) {
    l.checked = !l.checked;

    l.checked
        ? this.props.leaflet.map.addLayer(layer)
        : this.removeLayer(layer);
  }
  return l;
 });

 this.setState({
  layers
 });
};

Thanks Dylan for the code, it was really helpfull.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.