A collection of fine SVG map markers that can easily be colored, resized, or overlayed with any DOM node including icon libraries, like Lucide, FontAwesome, Bootstrap, or Material.
✨ DEMO
Check out the demo
⚠️ WARNING
This plugin is compatible with Leaflet v2, for Leaflet v1 compatibility view the v1 branch
npm i leaflet-extra-markers
<script type="importmap">
{
"imports": {
"leaflet": "https://unpkg.com/leaflet@2.0.0-alpha.1/dist/leaflet.js",
"leaflet-extra-marker": "https://unpkg.com/leaflet-extra-markers@latest/index.js"
}
}
</script>
import { Marker } from "leaflet";
import { Icon, PinCirclePanel } from "leaflet-extra-markers";
const marker = new Marker(map.getCenter(), {
icon: new Icon({
accentColor: "firebrick",
color: "indianred",
content: "42",
contentColor: "white",
scale: 1,
svg: PinCirclePanel,
}),
});
For more examples view the Demo.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@2.0.0-alpha.1/dist/leaflet.css"
/>
</head>
<body>
<div id="map" style="width:100%;height:400px;">
<script type="importmap">
{
"imports": {
"leaflet": "https://unpkg.com/leaflet@2.0.0-alpha.1/dist/leaflet.js",
"leaflet-extra-marker": "https://unpkg.com/leaflet-extra-markers@latest/index.js"
}
}
</script>
<script type="module">
import { Map, Marker } from "leaflet";
import { Icon, PinCirclePanel } from "leaflet-extra-markers";
const map = new Map("map").setView([0, 0], 3);
const marker = new Marker(map.getCenter(), {
icon: new Icon({
accentColor: "firebrick",
color: "indianred",
content: "42",
contentColor: "white",
scale: 1,
svg: PinCirclePanel,
}),
}).addTo(map);
</script>
</body>
</html>
class IconThe Icon class extends Leaflet’s Icon class.
import { Marker } from "leaflet";
import { Icon, PinCirclePanel } from "leaflet-extra-markers";
const marker = new Marker([32.82,-117.43], {
icon: new Icon({
accentColor: "firebrick",
color: "indianred",
content: "42",
contentColor: "white",
size: 25,
svg: PinCirclePanel,
}),
});
class Icon extends IconBase<ExtraOptions> {
constructor(options?: ExtraOptions);
createIcon(): HTMLElement;
createShadow(): HTMLElement;
}
interface ExtraOptionsThese are the options you can pass into the new Icon() contructor. Note that this interface extends Leaflet’s IconOption, while these base options are supported as escape hatches, they should not be used in most circumstances.
svg: SvgNode | undefinedThe marker (Marker.icon in leaflet) svg node.
Default: "#000"
accentColor: string | undefinedThe accent color is applied to the icon variant and also the dot on the empty state.
Default: "#fff"
color: string | undefinedThe marker color. Will be set on the root.style.color property.
The SVG path for the base marker shape has a fill set to currentColor` to inherit this color.
Note: This setting could be overwritten by rootStyle.color.
Note: If svgFillImageSrc is defined, this setting will still be set but effectively ignored.
Default: "#000".
content: Content | ((opts: ExtraOptions) => Content) | undefinedThe content node to append to the contentWrapper.
This will be ignored if `contentHtml is set.
Default:
createElement(["div", {
style: {
display: "block",
height: "0.8em",
width: "0.8em",
backgroundColor: accentColor,
borderRadius: "100%",
},
}]);
contentHtml: string | undefinedDangerously sets innerHTML of the contentWrapper.
If set this will override the content property.
WARNING: Possible XSS vector; sanitize user inputs if using this.
Example: <i class="fa fa-coffee" />
contentColor: string | undefinedThe content (wrapper) color. Will be set on the `contentWrapper.style.color property.
Note: This setting could be overwritten by contentWrapperStyle.color.
Default: "#fff"
origin: "bottom" | "center" | undefinedSets the icon anchor.
bottom x center, y bottomcenter x center, y centerscale: number | undefinedThe scale of the SVG marker; height will be scaled proportionately. The markers are designed on a base 30px wide grid. Min: 0.1
Default: 1
shadow: "cast" | "drop" | "ellipse" | "none" | undefinedThe shadow variant.
Default: "cast"
svgFillImageSrc: string | undefinedThe url of an image to use as a fill for the marker. Image will be clipped by marker base shape. Consider retina devices when sizing images.
contentWrapperClass: string | undefinedThe CSS class names added to the contentWrapper element.
contentWrapperStyle: Partial<CSSStyleDeclaration> | undefinedThe styles to set on contentWrapper element.
Default: {}
rootClass: string | undefinedThe CSS class names added to the root element.
rootStyle: Partial<CSSStyleDeclaration> | undefinedThe styles to set on root element.
Default: {}
shadowClass: string | undefinedThe CSS class names added to the shadow element.
shadowStyle: Partial<CSSStyleDeclaration> | undefinedThe styles to set on shadow element.
Default: {}
svgClass: string | undefinedThe CSS class names added to the svg element.
svgStyle: Partial<CSSStyleDeclaration> | undefinedThe styles to set on svg element.
Default: {}
function createElement(params: ElementParams): HTMLElementCreates HTML element recursively from a data structure. Efficently uses document fragements and support style objects and class arrays – skipping falsy values.
const svg = createElement([
"i",
{
"data-foo": "bar"
style: {
filter: "drop-shadow(2px 2px 2px rgba(0, 0, 0, 0.32))",
},
class: [
"fa",
isCafe && "fa-coffee",
],
},
[
// Optionally pass in children with same structure.
]
])
function createSvgElement(params: ElementParams): SVGElementCreates SVG element recursively from a data structure. Efficently uses document fragements and support style objects and class arrays – skipping falsy values.
const svg = createSvgElement([
"svg",
{
width: "30px",
height: "30px",
style: {
filter: "drop-shadow(2px 2px 2px rgba(0, 0, 0, 0.32))",
},
class: [
"extra-marker-icon",
],
},
["circle", { cx: "10", cy: "10", r: "5", fill: "currentColor" }],
])
Original marker design file (Figma) is located at ./assets/markers.fig.
The markers are divided into 4 families:
pin - taller map markers; like a pushpin; origin at bottom centertack - short map markers; like a thumbtack; origin at bottom centerchip - shorter map markers; like a poker chip; origin at bottom centerpoint - simple point markers; origin at center centerEach icon family has many shapes:
circlediamondpentagonsquarestarteardrop (only for pin family)triangleEach shape has many optional variants:
border-1 is a relative 1px borderborder-2 is a relative 2px borderpanel is a relative 2px border th a solid fill on the marker tail/pointer.The variants are designed to completely cover the base shape so you can have fun with opacity, filter, or mix-blend-mode.
The SVG Icons are designed on a base 30px wide grid. The height varies per icon family.
The SVG shadows are inlined as data URIs to increase performance. It is possible to a custom shadow by passing in a shadowUrl options.
The following script was used to efficently encode the shadow SVGs into data URIs.
npx mini-svg-data-uri ./assets/shadow-ellipse.svg
Below is the HTML structure of the Marker Icon.
<div> <!-- leaflet-marker-plane -->
<div> <!-- `root` -->
<!-- `svg` -->
<div> <!-- `contentWrapper` -->
<!-- `content` or `contentHtml` -->
</div>
</div>
</div>
<div> <!-- leaflet-marker-plane -->
<img /> <!-- `shadow` -->
</div>
Version 2 is a complete rewrite to support svg only icons with no image or css file dependencies.
Icon options/properties per the mapping below:
extraClasses –> rootClass.icon –> content or contentHtml.createElement util here.
- iconColor –> contentColor.
- iconRotate - removed; instead add the appropriate class or style to the element passed into content.
- innerHtml - removed.
- number –> content.
- prefix - removed. Instead add it to your HTML string for contentHtml or on the element if using content
- shape - removed; instead import the desired marker. import { PinCircleBorder } from "leaflet-extra-markers";
- svg –> not supported as boolean; now this takes an SvgNode type (import desired marker and pass by reference)
- svgBorderColor - removed; this never worked but its intended effect can now be accomplished by setting accentColor.
- svgOpacity - removed; this never worked but its intended effect can now be accomplished by setting svgStyle.opacity.
- markerColor –> color; note that named colors have been removed. The legacy color mapping is below;
const colors: {
"red": "#a23337",
"orange": "#ef9227",
"orange-dark": "#d73e29",
"yellow": "#f5bb39",
"cyan": "#32a9dd",
"blue": "#1b75bb",
"blue-dark": "#276273",
"purple": "#440444",
"violet": "#90278d",
"pink": "#c057a0",
"green-light": "#70b044",
"green": "#009549",
"green-dark": "#006838",
"white": "#ffffff",
"black": "#231f20",
};