Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow external icon-image #822

Closed
jescalan opened this issue Nov 10, 2014 · 34 comments
Closed

Allow external icon-image #822

jescalan opened this issue Nov 10, 2014 · 34 comments

Comments

@jescalan
Copy link

Right now the only option for symbol.icon-image is a string in reference to a precompiled sprite sheet that's undocumented and very difficult for any normal user to be able to update. If the icon-image property would also take a URL to an image and render that, it would be fantastic. This would also mean great support for custom markers, which is a huge missing piece from mapbox gl right now. Bonus points if icon-image would accept svgs!

@peterqliu
Copy link
Contributor

@Jenius check out our style spec-- under sprite, you can put in the URL to your own custom-compiled sprite sheet. Just make sure you format the address it correctly (.json and .png will the appended automatically, as will @2x for retina screens). To apply the icon for your symbol, reference your symbol's name (as defined in your sprite.json) under icon-image.

Let me know if you have any questions on making either the images or accompanying JSONs.

@jescalan
Copy link
Author

Hey @peterqliu -- thanks for the response! So this solution would require pre-compiling out images into a sprite sheet. There are a few problems here:

  1. They have to be raster. Would love to just add a svg and have it be vector. This would work much better with the vector map anyway.
  2. It would not work at runtime. So for example if you hit an API and get back people's names, photos, and locations to plot on the map, you wouldn't be able to do this because you'd have to have run a build process beforehand to make those images available.
  3. The documentation for generating your own sprite sheet is severely lacking. Like, not actually present at all. What is a sprite.json? What goes in it? How should the folder of images be formatted? What tasks should be run to link them up? This is such an involved process that it really needs a guide of specific steps you can take to make it happen.

@jfirebaugh
Copy link
Contributor

@Jenius Great points. Sorry about the lack of docs. We're planning on some major changes to how icon sprites work, so the lack of documentation is somewhat a reflection of that. When things solidify we plan on having better docs and much better tooling support (e.g. an editor that will create the sprite for you automatically). We'll also keep the dynamic icon use case in mind.

@jescalan
Copy link
Author

Would be awesome. I'm working on an application right now that is banking on dynamic icon support, and will have to switch back to the non-gl version very sadly if that's not somewhat close on the roadmap, which I'm afraid it probably isn't.

Either way, would be happy to help out with this stuff if I can, and would appreciate any updates or rough timeframes on any of it!

@peterqliu
Copy link
Contributor

@Jenius shucks that we can't help with dynamic support yet, but if you decide to use static sprites in the future, here's a crash course (writing this partly for you, and partly as a jumpstart for future docs).

_Folder setup_

My folder when making maps looks like this:

screen shot 2014-11-11 at 6 14 00 pm

index.html is the page itself, style.json is my stylesheet. For sprites, I make a sprite.png with all my raster images compiled, and sprite.json tells the renderer where in the PNG to fetch each sprite (more on this below). I make a second version of each for retina screens, hence the @2x files.

To link up my stylesheet and sprite assets, I store the assets' filenames in the stylesheet's sprite property (since my assets here are just called sprite, it would read "sprite": "sprite" )

_Defining the sprites_

Let's take a typical sprite PNG image-- looks something like this:

If we check out the corresponding sprite.json, the first object is:

marker-24: { x: 0, y: 0, width: 24, height: 24, pixelRatio: 1, sdf: false }

This tells the renderer that a sprite called marker-24 is 24px wide, 24px high, and its upper-left hand corner is at x=0 y=0. Looking at the PNG, that's the very first sprite above, next to the giraffe. We make one of these objects for each sprite.

_Putting it together_

Let's say we're trying to use marker-24 in a map, on a retina screen.

  1. In style.json, we reference marker-24 in a paint property, like icon-image.

  2. In style.json, the renderer will grab the sprite assets' filename ( sprite ) and figure out the type of screen we're on (retina), to assemble the expected JSON filename ( sprite + @2x + .json ).

  3. Once it finds this file, it will look for a marker-24 object there, and fetch the x/y/width/height values therein.

  4. It will then seek the corresponding PNG file to the JSON ( [email protected] ), and there find the portion of the image as defined by the four values above. This is the portion that is applied to your map.

@jescalan
Copy link
Author

Awesome, thank you! Exactly what I was after. Looking forward to how the changes to sprites work out, this should get me through it for now 😀

@pnorman pnorman mentioned this issue Nov 18, 2014
@jfirebaugh
Copy link
Contributor

Remaining issues here are covered by #358.

@fallenartist
Copy link

Thanks for the explanation @peterqliu. Did anyone manage to use custom markers and would share a working example? For some reason I can't get them to show up linking to either Mapbox or custom style and sprites. See this question on SO. Thanks.

@ktruckenmiller
Copy link

+1 @fallenartist

@lukerollans
Copy link

Hello from 2016 all of the above 2014/15 comments :)

So, we're switching from Google Maps to Mapbox GL, and I've just come across this. The necessity of a sprite sheet is an absolute deal breaker for us. Has this been addressed at all? If not, we'll need to switch to Mapbox.js (leaflet)

@peterqliu
Copy link
Contributor

@lukerollans what's your use case? Mapbox Studio now makes the sprite sheet for you, though it still means you prepare it in the map style ahead of time.

@lukerollans
Copy link

@peterqliu we are a travel companion application, in which our subscribers add their businesses so travelers can find them easily. Within the app is a map page and a "featured image" is used as the map marker. So, they're completely user defined and quite variable.

@wagerfield
Copy link

What does sdf mean in sprite.json? You have it set to false and so do all the definitions in bright.json.

@aidanlister
Copy link

I can't seem to apply colours to the maki icon sprite sheet .. do I need to make my own for each set of colours I want?

@lucaswoj
Copy link
Contributor

@aidanlister Maki does not support the symbol-color property because it is not an SDF icon set. You must make your own for each set of colors you want. You may find Maki Chef useful.

@wagerfield
Copy link

For anyone who wants to generate their own sprite sheets for Mapbox from SVG icons using gulp, I've created a gulp plugin that wraps Mapbox's spritezero package.

You can find the gulp-spritezero package here.

The only thing it doesn't do right now is generate SDF images—I haven't figured that bit out yet. So if anyone knows how to do this, please point me in the right direction or create a PR.

@lucaswoj
Copy link
Contributor

There hasn't been much communication about this yet but we are seriously considering dropping SDF support because it is undocumented and unused. See mapbox/mapbox-gl-style-spec#444 for more.

@ouya99
Copy link

ouya99 commented May 24, 2016

why not use svg? Whats your ideas for the future?

@ouya99
Copy link

ouya99 commented May 24, 2016

https://github.com/rev22/svgl ?

what is the purpose of generating sdf/png files when dealing with vector gfx?
Is there a method to use svg in opengl on your maps?

@koolkarni
Copy link

Why can i just add my Image url to layout

map.addLayer({
    "id": "uck1",
    "type": "symbol",
    "source": "uck1",
    "layout": {
        "icon-image": "http://x.x.x.x/an.png"
    }
});

@Scarysize
Copy link

@koolkarni Icons are supplied via a sprite sheet, not via a single file per (potential) feature.
@lucaswoj What is the current stance on SDF icons? We are considering to open source our sprite sheet generator. A simple cli tool to generate a (sdf) sprite sheet from a directory of SVG files.

@lucaswoj
Copy link
Contributor

No official stance on SDF icons or per-feature icons at the moment. I'm personally in favor of using an established standard + icon-colorize rather than our undocumented SDF standard.

@mgd722
Copy link

mgd722 commented May 17, 2017

To those of you arriving here from a very frustrating Google search, external/generated icons can be passed to icon-image if you use map.loadImage() and map.addImage() first.

Examples:
Add an icon to the map
Add a generated icon to the map

@santinogue
Copy link

@mgd722 there's a limitation of 500 icons per sprite right? And only one sprite per map can be loaded, map.loadImage() add the new image to the sprite, as far as I know, our situation is that we are using the symbol layer to implement custom markers and we are reaching the limit of 500 images with the images of the markers and the svgs used by our custom mapbox maps (our layers). Any ideas on how can we sort this issue, other alternatives?

@Scarysize
Copy link

@santinogue There is a complimentary map.removeImage method: https://www.mapbox.com/mapbox-gl-js/api/#map#removeimage

We are using this successfully to switch out icon which are not being displayed right now. If you want to display a lot more icon simultaneously you are going to run into problems.

@santinogue
Copy link

@Scarysize thanks for your answer, but removeImage wont help us. For example, we have copied the street layer from mapbox and made some modifications, we load the sprite containing the svgs for that map and other custom ones, so there are like 400 (or more) icons on that sprite, that leves 100 icons or less to use with the symbol layers (our custom markers), and we want to display them at the same time.

@Scarysize
Copy link

Okay, but be aware that the limit of icons is not fixed to 500. The limit is the maximum size of the internal sprite sheet, which is limited to 1024x1024px (2048x2048 on retina). So you might squeeze some more icons into your style by using smaller images.

@santinogue
Copy link

Ok, the 500 icons restriction is specified in the API documentation https://www.mapbox.com/api-documentation/#sprites, anyway, if the limit is 500 or 1000, if we keep adding styles or new icons, we will reach the limit eventually, is this something that want's to be supported?

@dagjomar
Copy link
Contributor

@santinogue @Scarysize Are you sure these are hard limits now? After the internal changes to the SpriteAtlas, I believe there might be only hardware or internal memory that would limit the amount of icons you could add using addImage().

@santinogue
Copy link

@dagjomar I'm not sure, but the documentation led me to think that. Maybe someone can clarify if this limits are still there, and the docs should be updated if not the case.

@jfirebaugh
Copy link
Contributor

The limits documented at https://www.mapbox.com/api-documentation/#sprites apply to the sprites web API (/styles/v1/{username}/{style_id}/sprite/...). There is no explicit limit to the number of images that can be added via the Mapbox GL JS addImage API -- only the effective (and device specific) limits imposed by available RAM and maximum WebGL texture size.

@shrutikar
Copy link

I used map.loadImage( ) and map.addImage( ). It works fine when the image is "http://.........". I have created my custom icons which lay on my server where my index.html is also there (in the same folder). But it seems to pick the icons mentioned as "http://......" but not the icons in my folder. It works fine on my local machine. Is there a way around to this?

@lucaswoj
Copy link
Contributor

@shrutikar It sounds like you're asking about loading icons over protocols other than http://, such as via the local file system (file://). Protocols other than http:// may work to some extent but cannot be relied upon. You'll save yourself some trouble if you always use the http:// protocol, including using a local http development server on your computer.

StackOverflow is a better place for questions like this in the future. We try to reserve GitHub issues for feature requests and bug reports.

@mvl22
Copy link
Contributor

mvl22 commented Jan 5, 2020

If the icon-image property would also take a URL to an image and render that, it would be fantastic.

map.addLayer({
"id": "uck1",
"type": "symbol",
"source": "uck1",
"layout": {
"icon-image": "http://x.x.x.x/an.png"
}
});

Out of interest, what is the technical reason for this not being possible? Is there some fundamental issue here, or is this just not a development priority?

It's possible to create images by creating a DOM element and attaching that to the map, though this is presumably rather inefficient.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests