RGradientMarker

This component wraps a MapLibre Marker object. He manages its life cycle and is responsible for adding/removing it to the map. For this reason this component must be a descendant of RMap.

To use this component you will need to add an additional stylesheet.

import "maplibre-react-components/style.css";

Usage

import { RGradientMarker, RMap } from "maplibre-react-components";
 
const center: [number, number] = [-0.5, 47.5];
 
export default function App() {
  return (
    <RMap initialCenter={center} initialZoom={2}>
      <RGradientMarker longitude={-0.5} latitude={48} />
    </RMap>
  );
}
 

If you use a custom marker element don't forgot to memoize the component.

Reactivity

All his props are reactive, feel free to express your creativity !

import { RGradientMarker, RMap } from "maplibre-react-components";
import { useState } from "react";
import { Button } from "pentatrion-design/components/button";
import { hslToRgb } from "./util";
 
const center: [number, number] = [-0.5, 47.5];
 
export default function App() {
  const [counter, setCounter] = useState(0);
  const [colorRange, setColorRange] = useState(180);
  const [scale, setScale] = useState(1);
 
  const color = hslToRgb(colorRange / 360, 0.5, 0.5);
  return (
    <RMap initialCenter={center}>
      <RGradientMarker
        longitude={center[0]}
        latitude={center[1]}
        text={counter.toString()}
        color={color}
        scale={scale}
      />
      <div className="absolute bottom-4 left-4 flex flex-col gap-2 rounded-2xl bg-gray-0 p-4">
        <div>
          <Button
            onClick={() => setCounter((c) => c + 1)}
            fullWidth={true}
            className="justify-center"
          >
            increment counter {counter}
          </Button>
        </div>
        <div className="flex items-center justify-between gap-2">
          Color
          <input
            type="range"
            min={0}
            max={360}
            value={colorRange}
            onChange={(e) => {
              setColorRange(e.target.valueAsNumber);
            }}
          />
          <span className="w-16">{color}</span>
        </div>
        <div className="flex items-center justify-between gap-2">
          Scale
          <input
            type="range"
            min={0.5}
            max={2}
            step={0.1}
            value={scale}
            onChange={(e) => {
              setScale(e.target.valueAsNumber);
            }}
          />
          <span className="w-16">{scale}</span>
        </div>
      </div>
    </RMap>
  );
}
 

Draggable reactivity component

If your marker component is draggable, you need to register a handler for the dragend or drag event to update the state. See RMarker documentation for the detail of implementation.

Icon / Text content

RGradientMarker can contain icon or text content. If you use any font icon kit (fontello, fontawesome, etc...), just specify the className and it will be wrapped inside a <i className={icon} /> element.

Otherwise, you need to specify a factory function who generate your HTMLElement or SVGSVGElement.

RGradientMarker is a React wrapper of a GradientMarker class who extends Marker from MapLibre. When the marker is added to the map it is integrated into a DOM node which is not managed by React. This is why the generated element must be a DOM element and not a JSX.Element.

import { RGradientMarker, RMap } from "maplibre-react-components";
import { mountainIconFactory } from "./util";
 
const center: [number, number] = [-0.5, 47.5];
 
export default function App() {
  return (
    <RMap initialCenter={center} initialZoom={2}>
      <RGradientMarker longitude={-9.1} latitude={38} text="Lis" />
      <RGradientMarker longitude={-0.5} latitude={48} icon="fe-star" />
      <RGradientMarker
        longitude={6.4546}
        latitude={46.1067}
        icon={mountainIconFactory}
      />
    </RMap>
  );
}
 
// util.ts
export const mountainIconFactory = () => {
  const svgNamespace = "http://www.w3.org/2000/svg";
  const svg = document.createElementNS(svgNamespace, "svg");
 
  svg.setAttribute("xmlns", svgNamespace);
  svg.setAttribute("viewBox", "0 0 640 512");
  svg.setAttribute("fill", "currentColor");
 
  const path = document.createElementNS(svgNamespace, "path");
  path.setAttribute(
    "d",
    "M560 160A80 80 0 1 0 560 0a80 80 0 1 0 0 160zM55.9 512H381.1h75H578.9c33.8 0 61.1-27.4 61.1-61.1c0-11.2-3.1-22.2-8.9-31.8l-132-216.3C495 196.1 487.8 192 480 192s-15 4.1-19.1 10.7l-48.2 79L286.8 81c-6.6-10.6-18.3-17-30.8-17s-24.1 6.4-30.8 17L8.6 426.4C3 435.3 0 445.6 0 456.1C0 487 25 512 55.9 512z",
  );
 
  // Ajouter l'élément path à l'élément SVG
  svg.appendChild(path);
 
  return svg;
};

Reference

RGradientMarker extends RMarker, he therefore shares many of his options and has new ones. Check the MapLibre MarkerOptions reference page for details of MarkerInitialOptions and MarkerReactiveOptions.

However, for compatibility reasons, some options from MarkerOptions are not available : element, anchor, offset.

type RMarkerProps =
  {
    longitude: number;
    latitude: number;
  } &
 
 
 
  /**
   * Reactive marker options.
   * they have the same name as in MarkerOptions
   */
  GradientMarkerReactiveOptions &
 
 
 
 
  /**
   * Listenners for marker events
   * prefixed with "on" + first letter uppercase
   */
  GradientMarkerCallbacks;
 
type GradientMarkerReactiveOptions = {
  className?: string;
  clickTolerance?: number;
  rotation?: number;
  rotationAlignment?: Alignment;
  pitchAlignment?: Alignment;
  opacity?: string;
  opacityWhenCovered?: string;
  subpixelPositioning?: boolean; // v4.5.1+
  color?: string;
  draggable?: boolean;
  icon?: string | HTMLElement | SVGSVGElement | (() => HTMLElement | SVGSVGElement);
  interactive?: boolean;
  scale?: number;
  shape?: "pin" | "circle";
  text?: string;
};
type GradientMarkerCallbacks = {
  onDragStart?: (e: Event<Marker>) => void;
  onDrag?: (e: Event<Marker>) => void;
  onDragEnd?: (e: Event<Marker>) => void;
 
  // native DOM event
  onClick?: (e: MouseEvent) => void;
}