Bjorn Reppen
Bjorn Reppen

Reputation: 22769

Render mapbox vector tiles inside react-leaflet?

Is there a way to use vector tiles from react-leaflet?

I am aware of Leaflet.VectorGrid, but it is not written for react-leaflet?

Upvotes: 7

Views: 6653

Answers (4)

ianthetechie
ianthetechie

Reputation: 670

In case anyone finds this question and is wondering how to do this with MapLibre GL JS (FOSS fork of Mapbox GL JS) as the backend renderer, you can do this but it's not immediately obvious. The MapLibre equivalent plugin is actively maintained now while the Mapbox one is not.

Here is the component code (in TypeScript) for a MapLibre tile layer that you can use instead of TileLayer in your React Leaflet MapContainer:

import {
    type LayerProps,
    createElementObject,
    createTileLayerComponent,
    updateGridLayer,
    withPane,
} from '@react-leaflet/core'
import L from 'leaflet'
import '@maplibre/maplibre-gl-leaflet'

export interface MapLibreTileLayerProps extends L.LeafletMaplibreGLOptions, LayerProps {
    url: string,
    attribution: string,
}

export const MapLibreTileLayer = createTileLayerComponent<
    L.MaplibreGL,
    MapLibreTileLayerProps
>(
    function createTileLayer({ url, attribution, ...options }, context) {
        const layer = L.maplibreGL({style: url, attribution: attribution, noWrap: true}, withPane(options, context))
        return createElementObject(layer, context)
    },
    function updateTileLayer(layer, props, prevProps) {
        updateGridLayer(layer, props, prevProps)

        const { url, attribution } = props
        if (url != null && url !== prevProps.url) {
            layer.getMaplibreMap().setStyle(url)
        }

        if (attribution != null && attribution !== prevProps.attribution) {
            layer.options.attribution = attribution
        }
    },
)

Full sample code lives in this repo on GitHub: https://github.com/stadiamaps/react-leaflet-demo

Upvotes: 0

Murli Prajapati
Murli Prajapati

Reputation: 9713

For react-leaflet v2, export the MapBoxGLLayer component wrapped with HOC withLeaflet() to get it working.

Steps:

1.Install mapbox-gl-leaflet.

npm i mapbox-gl-leaflet 

2.Add mapbox-gl js and css to index.html

<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.51.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.51.0/mapbox-gl.css' rel='stylesheet' />  

3.Add this component.

import L from "leaflet";
import {} from "mapbox-gl-leaflet";
import PropTypes from "prop-types";
import { GridLayer, withLeaflet } from "react-leaflet";

class MapBoxGLLayer extends GridLayer {
  createLeafletElement(props) {
    return L.mapboxGL(props);
  }
}

/*
* Props are the options supported by Mapbox Map object
* Find options here:https://www.mapbox.com/mapbox-gl-js/api/#new-mapboxgl-map-options-
*/
MapBoxGLLayer.propTypes = {
  accessToken: PropTypes.string.isRequired,
  style: PropTypes.string
};

MapBoxGLLayer.defaultProps = {
  style: "mapbox://styles/mapbox/streets-v9"
};

export default withLeaflet(MapBoxGLLayer);   

4.Use the MapBoxGLLayer component.

class App extends Component {
  state = {
    center: [51.505, -0.091],
    zoom: 13
  };

  render() {
    return (
      <div>
        <Map center={this.state.center} zoom={this.state.zoom}>
          <MapBoxGLLayer
            accessToken={MAPBOX_ACCESS_TOKEN}
            style="mapbox://styles/mapbox/streets-v9"
          />
        </Map>
      </div>
    );
  }
}

Find the working code here (Add your own mapbox token): https://codesandbox.io/s/ooypokn26y

Upvotes: 6

lando
lando

Reputation: 440

There are some really nice vector tiles examples in this react-leaflet issue (mapbox-gl example reproduced below).

// @flow

import L from 'leaflet'
import {} from 'mapbox-gl-leaflet'
import {PropTypes} from 'react'
import { GridLayer } from 'react-leaflet'

export default class MapBoxGLLayer extends GridLayer {
  static propTypes = {
    opacity: PropTypes.number,
    accessToken: PropTypes.string.isRequired,
    style: PropTypes.string,
    zIndex: PropTypes.number,
  }

  createLeafletElement(props: Object): Object {
    return L.mapboxGL(props)
  }
}

and the usage of the above component:

<Map>
  <MapBoxGLLayer
    url={url}
    accessToken={MAPBOX_ACCESS_TOKEN}
    style='https://style.example.com/style.json'
  />
</Map>

NOTE: you may also need to npm install mapbox-gl and import that library and assign into to the global window.mapboxgl = mapboxgl to avoid issues with mapboxgl being undefined.

Upvotes: 3

Evan Siroky
Evan Siroky

Reputation: 9408

You can create a custom component by extending the MapLayer component. You can see an example of how this is done in react-leaflet 1.0 in a project I contributed to here.

Upvotes: 2

Related Questions