How to add custom Icons to LayerProps of `react-map-gl/maplibre`?

167 views Asked by At

I am failing to apply a custom Icon Marker to my LayerProps. I want to use an Icon from lucid-react for the unclusteredPointLayer. What I have tried so far: I have used type: "symbol" instead of circle but failed to get that working.

Here is the working code but without a custom marker:

import { Outlet, useLoaderData } from "@remix-run/react";
import {
  Layer,
  LayerProps,
  MapProvider,
    NavigationControl,
  Map as ReactMap,
  Source,
} from "react-map-gl/maplibre";

import "maplibre-gl/dist/maplibre-gl.css";
import Header from "~/components/map/header";
import {
  getAllPlaygrounds,
  getAllPlaygroundsAsGeoJSON,
} from "~/models/playground.server";

export async function loader() {
  const playgrounds = await getAllPlaygroundsAsGeoJSON();
  const plainPlaygrounds = await getAllPlaygrounds();

  return {
    playgrounds: playgrounds,
    plainPlaygrounds: plainPlaygrounds,
  };
}

export const clusterLayer: LayerProps = {
  id: "clusters",
  type: "circle",
  source: "playgrounds",
  filter: ["has", "point_count"],
  paint: {
    "circle-color": [
      "step",
      ["get", "point_count"],
      "#51bbd6",
      100,
      "#f1f075",
      750,
      "#f28cb1",
    ],
    "circle-radius": ["step", ["get", "point_count"], 20, 100, 30, 750, 40],
  },
};

export const clusterCountLayer: LayerProps = {
  id: "cluster-count",
  type: "symbol",
  source: "playgrounds",
  filter: ["has", "point_count"],
  layout: {
    "text-field": "{point_count_abbreviated}",
    "text-font": ["DIN Offc Pro Medium", "Arial Unicode MS Bold"],
    "text-size": 12,
  },
};

export const unclusteredPointLayer: LayerProps = {
  id: "unclustered-point",
  type: "circle",
  source: "playgrounds",
  filter: ["!", ["has", "point_count"]],
  paint: {
    "circle-color": "#11b4da",
    "circle-radius": 4,
    "circle-stroke-width": 1,
    "circle-stroke-color": "#fff",
  },
};

export default function Explore() {
  const data = useLoaderData<typeof loader>();

  return (
    <div className="">
      <MapProvider>
        <Header />
        <ReactMap
          id="map"
          initialViewState={{
            longitude: 7.67,
            latitude: 51.988,
            zoom: 11,
          }}
          style={{
            width: "100%",
            height: "100%",
            position: "fixed",
            top: 0,
            left: 0,
          }}
          mapStyle={
            "https://api.maptiler.com/maps/streets/style.json?key=" +
            ENV.MAPTILER_KEY
          }
          attributionControl={true}
        >
          <Source
            id="my-data"
            type="geojson"
            data={data.playgrounds}
            cluster={true}
            clusterMaxZoom={14}
            clusterRadius={50}
          >
            <Layer {...clusterLayer} />
            <Layer {...clusterCountLayer} />
            <Layer {...unclusteredPointLayer} />
          </Source>
          <NavigationControl position="bottom-right" showCompass={false} />
          <Outlet />
        </ReactMap>
      </MapProvider>
    </div>
  );
}

Anyone with some tips?

Thanks a lot!!

1

There are 1 answers

1
jSi On

Looking at the mapbox docs, using "symbol" as the type is the right track, see https://docs.mapbox.com/style-spec/reference/layers/#symbol for correct usage:

"symbol" docs

You can use "icon-image" to specify the custom image.

The react-map-gl docs, it describes Layer & LayerProps as a wrapper to mapbox layer API, so mapbox docs will be more helpful.