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";
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.
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>
);
}
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.
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;
};
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;
};
import { Event } from "maplibre-react-components";
type GradientMarkerCallbacks = {
onDragStart?: (e: Event<Marker>) => void;
onDrag?: (e: Event<Marker>) => void;
onDragEnd?: (e: Event<Marker>) => void;
// native DOM event
onClick?: (e: MouseEvent) => void;
}