While working on a side project of mine, i encountered a decision: Free, opensource and privacy respecting raster tile maps using openstreetmap data, or a proprietary, closed source, privacy violating vector tile map provided by Mapbox, Maptiler or similar.

I chose the first option because i believe that privacy of the users of a webapp is important enough to sacrifice some features. However, i still wanted to have the features that vector tile maps provide, such as the ability to change the style of the map on the fly or the fact that the font size of the labels on the map is independent of the zoom level making acecssibility features possible. As I didn’t find the right solution for my problem (and no, I didn’t want to host my own vector tile server), the side project was put on hold.

Versatiles, the solution

A few months later, I stumbled upon a very nice talk from CCC Camp2023 (link). This talk was about a project called Versatiles, which is a vector tile map server that uses openstreetmap data. If you want to know more about Versatiles, I recommend watching the talk and checking out the website (https://versatiles.org).

Example Project

github repo: repo

The following example shows how easy it is to use Versatiles in a ReactJS project. The example is based on the Create React App template. If you just want to see the webapp in action, you can check it out here.

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';


const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

App.js

import React from 'react';
import { useEffect } from 'react';
import MapLibreGL from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';



function Map() {
  useEffect(() => {
    const map = new MapLibreGL.Map({
      container: 'map',
      style: 'https://tiles.versatiles.org/styles/colorful.json',
      center: [8.5428242, 47.3669311],
      zoom: 13
    });

    map.on('style.load', () => {
      new MapLibreGL.Marker()
        .setLngLat([8.5428242, 47.3669311])
        .addTo(map);
    });
  }, []);
  return <div id="map" style={{ width: '100%', height: '100vh' }} />;
}

function App() {
  return (
    <div className="App">
      <Map />
    </div>
  );
}

export default App;

Props to the Versatiles Team