11

I'm using MapBox GL JS to create a map with a custom marker:

var marker = new mapboxgl.Marker(container)
    .setLngLat([
        datacenters[country][city].coordinates.lng,
        datacenters[country][city].coordinates.lat
    ])
    .addTo(map);

However, I seem to have some kind of offset problem with the marker. The thing is: when zoomed out a bit, the bottom of the marker is not really pointing to the exact location:

Marker when zoomed out a bit

When I'm zooming in a bit further it reaches its destination and it's pointing to the exact spot.

Marker when zoomed in

I really love MapBox GL, but this particular problem is bugging me and I'd love to know how to solve it. When this is fixed my implementation is far more superior to the original mapping software I was using.

Dani
  • 2,448
  • 8
  • 27
  • 44
  • Out of interest, @egidius, are you planning on clustering these markers, and if you've done it, could you let me know how? – Huw Davies Aug 17 '16 at 16:15

4 Answers4

16

From Mapbox GL JS 0.22.0 you're able to set an offset option to the marker. https://www.mapbox.com/mapbox-gl-js/api/#Marker

For example to offset the marker so that it's anchor is the middle bottom (for your pin marker) you would use:

var marker = new mapboxgl.Marker(container, {
        offset: [-width / 2, -height]
    })
    .setLngLat([
        datacenters[country][city].coordinates.lng,
        datacenters[country][city].coordinates.lat
    ])
    .addTo(map);
AndrewHarvey
  • 2,867
  • 11
  • 21
  • Cool! I was using v0.21.0, so I guess my hack is still legit given my circumstances. Thank you so much. I'll just have to wait for v 0.22.0 to be released. – Dani Aug 11 '16 at 06:50
  • @Egidius It's now released https://github.com/mapbox/mapbox-gl-js/blob/master/CHANGELOG.md – AndrewHarvey Aug 11 '16 at 23:23
  • 1
    Awesome!! Never have had to wait this short amount of time for a release – Dani Aug 12 '16 at 06:47
  • I take it the 'width' and 'height' are the width and height in px of the marker you're using? @AndrewHarvey Still struggling to get this to work! Even with the correct offset it remains inaccurate on zooming in and out... – Huw Davies Aug 17 '16 at 16:11
  • 1
    Finally got it.... it turns out my width needed to be negative width / 2 and the height to be height * 2... – Huw Davies Aug 17 '16 at 16:14
  • @HuwDavies The API description says "The offset in pixels as a PointLike object to apply relative to the element's top left corner. Negatives indicate left and up." Based on that I would have thought it would be [-width/2, -height]? – AndrewHarvey Aug 18 '16 at 03:28
  • @AndrewHarvey strangely enough the height isn't negative. It's double. I guess people will have to experiment with their markers ;) – Huw Davies Aug 18 '16 at 08:20
  • Mine works when I do negative width/2 and negative height – satnam Sep 29 '16 at 20:57
  • 1
    In the current version, the offset is relative to the _center_ of the marker, not the top left: https://docs.mapbox.com/mapbox-gl-js/api/#pointlike – Ben Hull May 27 '19 at 09:44
9

New solution for mapbox-gl.js v1.0.0 - Marker objects now have an anchor option to set the position to align to the marker's Lat/Lng: https://docs.mapbox.com/mapbox-gl-js/api/#marker

var marker = new mapboxgl.Marker(container, {anchor: 'bottom');

This should cover most cases and is more reliable than a pixel offset in my experience.

Ben Hull
  • 7,524
  • 3
  • 36
  • 56
2

I've found an solution to my problem. It might be somewhat hacky, but it solves the positioning problem of the marker: I'm using a Popup fill it with a font awesome map marker icon and remove it's "tooltip styled" borders:

Javascript:

map.on('load', function() {
    var container = document.createElement('div');
    var icon = document.createElement('i');
    icon.dataset.city = city;

    icon.addEventListener('click', function(e) {
        var city = e.target.dataset.city;
        var country = e.target.dataset.country
        flyTo(datacenters[country][city].coordinates);
    });

    icon.classList.add('fa', 'fa-map-marker', 'fa-2x');
    container.appendChild(icon);

    var popup = new mapboxgl.Popup({
            closeButton: false,
            closeOnClick: false
        })
        .setLngLat([
            datacenters[country][city].coordinates.lng,
            datacenters[country][city].coordinates.lat
        ])
        .setDOMContent(container)
        .addTo(map);
});

CSS:

.map div.mapboxgl-popup-content {
    background: none;
    padding: 0;
}

.map .mapboxgl-popup-tip {
    display: none;
}

I just hope someone comes up with a real solution, because this feels kinda dirty to me. But hey: it does the job just fine!

Dani
  • 2,448
  • 8
  • 27
  • 44
1

Mapbox Marker now has an element option see this link Mapbox Marker. So instead of appending the icon HTML to the Div element you can simply add into the options when creating a marker. I found this also gets rid of the offset problem. So using the code above you can do this....

var icon = document.createElement('i');
icon.classList.add('fas', 'fa-map-marker-alt');
icon.style.color = 'blue';
new mapboxgl.Marker(container, {anchor: 'center', offset: [0, 0], element: icon})

Also the CSS for the marker can be updated to allow a pointer

.mapboxgl-marker {
    border: none;
    cursor: pointer;
}
michael
  • 21
  • 1