Mapbox-gl-js: Load Multiple Images for addImage()

Created on 22 May 2017  路  17Comments  路  Source: mapbox/mapbox-gl-js

I need to add multiple images to my map using addImage(). The example here shows how to load and add a single image to your map.

I was wondering if there's a recommended way to load and add multiple images to the map?

Any help is appreciated. Thanks in advance!

Most helpful comment

        Promise.all(
            images.map(img => new Promise((resolve, reject) => {
                map.loadImage(img.url, function (error, res) {
                    map.addImage(img.id, res)
                    resolve();
                })
            }))
        )
        .then(DoStuffWithLoadedImages)

All 17 comments

Hi @realph, thanks for using Mapbox GL. The recommended way is to call addImage() multiple times, once for each of the images you want to add. For example, you can add a loop to the example code to do this. Hope that helps!

馃憤

@realph Did you ever get this working? Would love to see what you ended up with :)

as of this comment, addImage is asynchronous, and takes a callback. So adding 5 images would require you to bury your code 5 levels deep in callbacks. Is there a way to do with with Promises?

@foundryspatial-duncan it looks like loadImage() is the method with the callback not addImage(). From what I can see you don't have to wait for the callback of one request before kicking off additional so you can just amend the example with a loop like:

For each image url {
  map.loadImage(url, function(error, image) {
    map.addImage('foo', image)
  }
}

Oops, that's my mistake. I was thinking of loadImage, where you'd want to make sure all of your images were loaded and added before trying to use them on the map... In that case you'd need to get creative with promises 馃憤

i have almost the same problem but i think the code of @twelch can't work since this way you will give all the images the same id "foo". The problem of using a for loop is that you can handle when the callback will be called and so you can't decide a different id for each image you want to add to the map.

Does anyone has a solution for this?

@andrealemanno just use array of objects to iterate. Previously create it:

const images =[
  {imageUrl: 'path/to/image_1.png', id: 'image_1'},
  {imageUrl: 'path/to/image_2.png', id: 'image_2'},
  ...
]

images.forEach(img => {
    map.loadImage(img.url, function(error, res) {
      map.addImage(img.id, res)
    })
})

@qrobin

images.forEach(img => {
    map.loadImage(img.url, function(error, res) {
        map.addImage(img.id, res)
    })
})

Missing ) from loadImage(

Tested with relative path /images/image.png and absolute path https://... both brings me this error

Uncaught TypeError: Cannot read property 'width' of undefined
at o.addImage (map.js:1104)
at (index):75
at ajax.js:157
at XMLHttpRequest.M.r.onload (ajax.js:120)

Oops, that's my mistake. I was thinking of loadImage, where you'd want to make sure all of your images were loaded and added before trying to use them on the map... In that case you'd need to get creative with promises 馃憤

Has anyone come up with a workable solution?

I understand all the looping stuff above, but it seems to me that the loadImage/addImage pairs have to be run before the data is then loaded on the map.

(I do find it incredible that a modern mapping library makes it so incredibly difficult simply to create markers loaded over a URL dynamically, e.g. using values in GeoJSON.)

Has anyone come up with a workable solution?

Seems that this is the only workable approach:
https://docs.mapbox.com/mapbox-gl-js/example/custom-marker-icons/

        Promise.all(
            images.map(img => new Promise((resolve, reject) => {
                map.loadImage(img.url, function (error, res) {
                    map.addImage(img.id, res)
                    resolve();
                })
            }))
        )
        .then(DoStuffWithLoadedImages)

Can I load a sprites sheet image,then set it to the 'icon-image'? the problem is, I do not know how to make it works like background-url/background-position in CSS. I can not find the solutions in style-spec

Has anyone come up with a workable solution?

@snorkleboy , thanks for the example but I couldn't get it to work on my instance. Could you drop a codepen.io example as I'm confident yours is the right approach for loading multiple external Images before loading the Layers.

var hostpital = ['IMSS', 'ISSSTE', 'PEMEX', 'SEDESA', 'SEMAR', 'SSA'];

hostpital.forEach(myFunction);

function myFunction(value, index, array) {
    map_hospitales.loadImage(
        'directory_or_url_image' + value + '.png',
        function(error, image) {
            if (error) throw error;
            map_hospitales.addImage(value, image);
        }
    );
}

"properties": {
    "title": 'TITLE',
    "hospital": 'IMSS'



md5-2840156000ce51af8f36db77c16c032a







md5-6278b0bcfa28c4d2e680c2768a7101f1



@snorkleboy's answer works. But beware: you cannot use SVG's 馃槈

@snorkleboy yes, you can use SVGs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bgentry picture bgentry  路  3Comments

aendrew picture aendrew  路  3Comments

PBrockmann picture PBrockmann  路  3Comments

BernhardRode picture BernhardRode  路  3Comments

stevage picture stevage  路  3Comments