MapSnippets logoMapSnippets logo

Custom Marker Icons with OpenLayers

OpenLayers

Style point features with custom icons using ol.style.Icon with SVG or PNG sources.

progress_activityLoading map...
var svgPin = function(color) {
  return 'data:image/svg+xml,' + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="30" height="40" viewBox="0 0 30 40"><path d="M15 0C6.7 0 0 6.7 0 15c0 11.3 15 25 15 25s15-13.7 15-25C30 6.7 23.3 0 15 0z" fill="' + color + '"/><circle cx="15" cy="14" r="6" fill="#fff"/></svg>');
};
var features = [
  new ol.Feature({ geometry: new ol.geom.Point(ol.proj.fromLonLat([-0.1276, 51.5074])), name: 'Big Ben', color: '#e63946' }),
  new ol.Feature({ geometry: new ol.geom.Point(ol.proj.fromLonLat([-0.1015, 51.5014])), name: 'London Eye', color: '#2196F3' }),
  new ol.Feature({ geometry: new ol.geom.Point(ol.proj.fromLonLat([-0.0763, 51.5081])), name: 'Tower of London', color: '#4CAF50' })
];
var vectorLayer = new ol.layer.Vector({
  source: new ol.source.Vector({ features: features }),
  style: function(feature) {
    return new ol.style.Style({
      image: new ol.style.Icon({
        src: svgPin(feature.get('color')),
        anchor: [0.5, 1],
        scale: 1
      })
    });
  }
});
var map = new ol.Map({
  target: 'map',
  layers: [
    new ol.layer.Tile({ source: new ol.source.XYZ({ url: 'https://api.maptiler.com/maps/streets-v4/256/{z}/{x}/{y}.png?key=YOUR_MAPTILER_KEY', attributions: '&copy; <a href="https://www.maptiler.com/copyright/">MapTiler</a>' }) }),
    vectorLayer
  ],
  view: new ol.View({ center: ol.proj.fromLonLat([-0.1, 51.505]), zoom: 14 })
});

How it works

OpenLayers renders markers as point features in a vector layer. Each feature gets a custom style using ol.style.Icon, which accepts an src URL: including data URIs for inline SVGs. A style function reads per-feature properties (like color) to return different icons for each marker.

The anchor option controls which part of the icon sits on the feature’s coordinates. The value [0.5, 1] means horizontally centered and anchored at the bottom: correct for a pin shape. For circle icons, use [0.5, 0.5] to center the icon on the point.

Key APIs

API Description Docs
ol.style.Icon Image-based point style openlayers.org
ol.style.Style Composite style object openlayers.org
ol.Feature Geographic feature with properties openlayers.org

FAQ

Can I use a PNG file instead of an SVG data URI?

Yes. Set src to the PNG file URL: src: '/images/pin.png'. Adjust size and anchor to match the image dimensions.

How do I add text labels below each icon?

Use ol.style.Text alongside ol.style.Icon in the same ol.style.Style. Set offsetY to position the label below the icon.

Does the style function run for every render frame?

Yes. For best performance with many features, cache style objects instead of creating new instances on each call.

Common mistakes

  • Forgetting ol.proj.fromLonLat(): Point coordinates must be in EPSG:3857 for the default map projection
  • Setting anchor wrong: the default [0.5, 0.5] centers the icon, which shifts pin shapes upward from the actual location
  • Not encoding the SVG for data URI: special characters like # in colors must be URL-encoded
auto_awesome

Build maps using OpenLayers with AI

Generate code like this custom marker icons with openlayers example using the OpenLayers skill in your IDE.