I am trying to do something I feel is very simple, yet seems that I am clearly misunderstanding a crucial piece of the mapbox addlayer feature.
The Goal
Create dynamically identified icons, based on a features data value (e.g. geojson feature data vale title: "walmart"). Essentially just adding dynamic store icons from the sprite image when those locations are queried via tilequery. picture representation here
The problem
I keep getting an error when trying to use the sprite values from the style. Error: util.js:349 Image "airport-11" could not be loaded. Please make sure you have added the image with map.addImage() or a "sprite" property in your style. You can provide missing images by listening for the "styleimagemissing" map event.
I see tons of resources talking about sprites, but none discuss how to exactly implement them in this fashion. I have even tried querying the sprite and then adding the values using dot notation to access sprite values. This gives an error of "undefined" and invalid value.
Example code:
map.addLayer({
id: "tilequery-points",
type: "symbol",
source: "tilequery", // Set the layer source
layout: {
"icon-image": [
"match",
["get", "title"],
["HEB"],
"H-E-B_logo",
["Pilot Flying j"],
sprite.Pilot_Travel_Centers_logo,
// "Pilot_Travel_Centers_logo",
["Dollar General"],
"Dollar_General_logo",
["Cumberland Farms Corp"],
"Cumberland_Farms_logo (1)",
["CEFCO"],
"CEFCO-convenience-stores-Logo_510px",
["BJs Wholesale Inc"],
The Question
How do I access the sprite values and not get an error?!!!
Thanks for the help! I Wouldn't ask if I didn't need it!
UPDATE
I have figured out that to use sprite images inside of any layer, the images will automatically be available if you have them in your Mapbox studio sprite image collection. The confusion was that previously, I was not able to use them from link. However, it should work automatically.
Hope it helps!
It's true the documentation about sprites is not super clear. I'll try to summarise (simplifying a bit).
A Mapbox GL style has one sprite. That's a PNG containing all the icons, plus a JSON file specifying what each icon is called (its icon ID), and where it located within the PNG. The sprite is specified by giving a URL as the sprite property: https://docs.mapbox.com/mapbox-gl-js/style-spec/sprite/
You can also add images to the sprite dynamically after the map loads, with map.loadImage and map.addImage, specifying the icon ID.
To display an icon, you use that same ID in a symbol layer: "icon-image": "myicon".
You can run into trouble when you try to combine your own icons with those in a Mapbox basemap (which are Maki icons with names like `airport-11').
To combine them, you can do one of these three things:
upload your icons to a style in Mapbox Studio
load your icons dynamically
generate a new sprite sheet offline, using something like mbsprite
I don't know what you meant about "dot notation", but no, that's not the right path.
Related
I have a web application that uses Dygraphs to create charts.
The application allows a user to create multiple Dygraph charts (each with their own Y-Axis) that will be stacked on top of each other.
Here's an example of what the multiple Dygraphs look like on a PC browser: Notice that the example displays three different Dygraphs each having their own Y-axis, but the X-axis is hidden for the top 2 charts and visible on the bottom chart.
I will allow the user to save the chart to disk as a PNG. - The way I currently save the multiple Dygraphs as one PNG is:
Create a target canvas that will be used to contain all the visible Dygraphs
Extract each canvas out of each Dygraph, then add each canvas to the target canvas **
Create a PNG via the .toDataURL() function on the target canvas
Here's an example of what the above screenshot looks like when saved as one PNG: (This is exactly what I want from the PNG)
The procedure works fine on browsers on a PC. But when I attempt to save the multiple Dygraphs into one PNG on a phone/tablet browser, the resultant PNG doesn't match the graph that is visible on the screen.
Example:
Here's what the multiple Dygraphs look like on an iPad (screenshot)
And here's what the resultant PNG looks like (Notice how the width and height of each chart does not match the actual iPad display).
I don't understand why the PNG is rendered correctly when I use a PC browser, but is not rendered correctly when I use a browser on a mobile device.
I'm not sure if this problem is due to limitations of the Canvas.toDataURL() function or if this is a Dygraphs problem or something else. I'm fishing for advice that may point me in the right direction and/or shed light on this particular problem.
**I should mention that I use Juan Manuel Caicedo Carvajal's Dygraph-Export extension
I'm guessing the Problem occurs, because the generated canvas isn't rendered fully to the responsive screen of an iPad.
You can try to export the original canvas (instead of generating a new one with the said library) yourself with toDataUrl https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL
Dygraphs generates 2 canvas, one for the legend and one for the actual graph and lays them ontop of each other. So make sure you choose the right one (not the _hidden_canvas). If the examples works you can draw the legend onto the graph canvas with canvas.drawImage(otherCanvas)
How to Copy Contents of One Canvas to Another Canvas Locally
Hope this helps. Keep me updated!
My workaround/hack for the problem stated in my OP was to make a change to the Dygraph source in the Dygraph.getContextPixelRatio function.
Notice in the code below that I set devicePixelRatio = 1
dygraph-combined.js
Dygraph.getContextPixelRatio = function (context) {
try {
//var devicePixelRatio = window.devicePixelRatio;
var devicePixelRatio = 1; // Hack!!!
var backingStoreRatio = context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1;
if (devicePixelRatio !== undefined) {
return devicePixelRatio / backingStoreRatio;
} else {
// At least devicePixelRatio must be defined for this ratio to make sense.
// We default backingStoreRatio to 1: this does not exist on some browsers
// (i.e. desktop Chrome).
return 1;
}
} catch (e) {
return 1;
}
};
In my case, this hack fixed my problem (stated in the OP) and didn't negatively affect any other parts of my application that uses Dygraphs. That said, if you find a better/correct way to fix the problem stated in the OP, please share.
I have a custom list renderer that has a logo for a business in it. It has a label Logo_URLImage that has the placeholder image. In my code I get the data and assign HashMaps to the list model, h.put("Logo_URLImage",imageURL); where imageURL is a string that has the absolute URL to the image.
On Android it seems to always work, but most of the testing has been on iOS devices. What happens is that images are updated as you'd expect the first time or two that you run it. A run later on will show blank images (flash the place holder image and then blank) and once that happens images will never come back.
Any thoughts on what might be causing this?
Check that you defined the LogoName map entry. Check that it is unique per image?
Check that it doesn't include special characters that might cause an issue.
I have a table view controller with a cell that contains an UIImageView. I also have a NSMutableArray that contains the url's. I want the url's to download the images and place them in the correct order. The NSMutableArray also contains some empty Strings and the cell that it corresponds too I want to have my placeholder image from my image assets.
How can I get it to work? I have also populated each cell with a title and summary but cannot workout how images work.
UPDATE
The code used for the image download. Note the photoLabels contains the array of images. Some of the photos are in the incorrect place once the first placeholder image occurs (It is one index late). Why is it doing that. Does anyone know why. I have println(photoLabels) and all the 50 strings are correct (with some just being "")
If anyone can help that would be great.
let imageURL: String = photoLabels.objectAtIndex(indexPath.row) as String
println(imageURL)
if imageURL == "" {
cell.imageContainer.image = UIImage(named: "placeholder")
} else {
cell.imageContainer.setImageWithURL(NSURL(string: imageURL))
}
return cell
Thanks
This seemingly innocent question actually entails a rat's nest of interesting details. These include:
Use lazy loading of the image, loading them just-in-time, rather than trying to download them up front;
Download the images asynchronously;
While downloading the images as needed, cache them (using NSCache, not NSMutableArray) so that if you scroll back to see some images recently downloaded that you don't have to download them again;
But, in response to memory pressure, make sure to empty the RAM-based cache (but still avail yourself of the persistent storage cache);
If user scrolls quickly down to the 100th row in the table example, make sure that the images for the visible cells don't get backlogged behind the requests for the previous 99 images (nb: you should test your app in suboptimal conditions, e.g. a poor 2G or 3G cellular environment, which can be simulated with the network link conditioner); and
You might want a placeholder image to show until the asynchronously retrieved image is downloaded (or retrieved from the cache).
The bottom line is that this takes a non-trivial amount of effort to do properly. As a result, I'd encourage you to use an existing solution, for example the UIImageView categories that are available from SDWebImage or AFNetworking. Both of these two frameworks offer a nice category for UIImageView that allows you to request the image to be downloaded asynchronously (it's sd_setImageWithURL in SDWebImage; it's setImageWithURL in AFNetworking).
Here is my adventure. On this page I would like to display our bicycle route.
I am using in drupal 7:
Openlayers 7.x-2.0-beta3
OpenLayers KML Layer 7.x-1.0-beta1 (I'm not sure if I need this module as well)
layer: openlayers_kml_example with the source a url to a file.
map : example_kml Example KML Map
The result is that the layer is displayed very very small on the big map. So if you zoom in to the airplane eventually you can see the track.
Map Projection set to 3857
Display Map Projection set to 4326 (the KML is made with Google earth. I think not important as there is no interaction only displaying.
LAYER SPECIFIC OPTIONS FOR KM extract styles and attributes ON.
If I put tracks on then I will miss the nice airplane icon.
I keep getting the same logs and of course no display on the page:
MESSAGE The layer cannot be reprojected to the map projection: EPSG:
MESSAGE Notice: Undefined variable: map in openlayers_layer_sanity_check() (line 399
MESSAGE Notice: Undefined property: stdClass::$name in openlayers_layer_sanity_check()
As it is not nice for people to think that I'm cycling constantly in water I would like to solve it :-)
Any suggestions?
John is correct in describing the issues but here is the solution :-)
Update drupal module openlayers to the latest version, currently 7.x-2.0-beta9.
Take care of the needed dependencies.
I reset all my layers and maps to the orginial and then adjusted the source of the kml layer to a file.
I am using the openlayers addressfield, geocode and geofield modules in Drupal7 to let the users create content with relevant geodata. But for some content there is no streetname available. So i would like to have a prezoomed maparea where the user can click in and flag the right position, instead of typing in the addressfield.
I tried to use the geofield with the "Openlayers Widget Map", but it's not exactly what i need.
Does anybody know how to use the modules for that?
Is there a tutorial for that?
Kind Regards
Michi
thx for answering!
Yes, in theory it works. I tried it befor with the geofield module.
And yes, i could see the map in the contenttype form while creating a node.
But i havn't found a way to prezoom the map into relevant places (or use the geolocate bevahior for that) or change the marker style for that geofield map. The only mapstyle i can choose in the contenttype field setting is the "geofield widget map". So i have no choice to use an individual prezoomed map with own marker styles.
Changing the "OpenLayers Default Map" in the openlayers settings makes no difference.
So maybe i've overlooked something to customize the geofield, but the module has no configuration link. So without some more configurations, the module is not practicable for users to flag a node with geofield.
Any other ideas or informations?
You can do this with the Geofield module: http://drupal.org/project/geofield
When you enable that module, you can add a Geofield field on your content type and set the widget to be an 'Openlayers Map'... the geofield field lets you input geographic information in a variety of ways, but just clicking on a map is one way. It probably uses the default zoom and center you have saved for your Openlayers map.
Try that out and let us know if it worked!!
Here are the options for entering in address information via Geofield: