Displaying raster data on map in leaflet - javascript

I have a trouble with displaying raster data on leaflet maps.
There is an float NxM array and RGB scale. I want to add new layer with the colorful tiles. I tried just to draw rectangles, but it's incredibly slow displaying. I noticed method L.GridLayer.extend(), but I didn't find any examples of what I want (just simple grid with text of coords on each tile).
Can somebody give an example where the raster data displayed by this or any other method?

If you look at the list of Leaflet plugins, you'll see quite a few that do per-pixel raster manipulation, including:
L.TileLayer.BPG: extends tilelayer, loading a tile means rendering a <canvas> and dumping its contents into the <img>
L.TileLayer.PixelFilter: loads an image and replaces individual pixels
Leaflet-fractal: Displays the mandelbrot set, calculating each pixel of a <canvas>
L.TileLayer.GL: Manipulate images with WebGL. Very useful and fast for heavy computations (fractal sets are several orders of magnitude faster) or manipulating existing images. Do have a look at the hypsometric tint demo; it will be useful if your NxM array is in any kind of graphical format (as the "terrain-rgb" tiles).

Related

Hide mapbox layer shapes that are too small

I have some geoJSON polygons that I render via layers on top of my map. Depending on the shape itself and the zoom level, sometimes the rendered shapes are too small and it doesn't make sense to even show them.
Is there a way to hide shapes that have rendered area less than some number?
So, as Babis.amas suggested, first I calculate the area of the feature with help of turf.area. It gives the value in square meters. Then I convert this value to pixels using the function mentioned here. And then it really depends on the shape type I'm dealing with. If the shape considered to be too small to be rendered, I just don't add it to the layer data feature collection.

Mapbox GL JS line animation

I am working with ~150,000 polylines that span North America. Across all the lines I'd like to draw/animate from the start to the end of each line. I started down the road of adding vertices to an array and updating a Mapbox source like this example. This was not feasible given the size of the entire dataset. In geojson form it's about 800mb and manipulating this in the browser seemed unreasonable.
As an alternate approach, I've broken each polyline into equally sized segments of 10km in length. I added an attribute on each segment which represents its percent distance from the start. I created an interval below that triggers a setFilter event, filtering segments based in the percent from start.
currentLinPos=0;
lineInterval=setInterval(function(){
currentLinPos+=.01;
if(currentLinPos>0.9999){
currentLinPos=0
}
map.setFilter('lines',['<','linePrc',currentLinPos])
}, 250);
Even when working with a small subset of the data, performance choppy and lags. I expected a better result from Mapbox GL but perhaps I need to rethink my data structure or approach entirely. Or would using something like DECK.GL be far superior here?

Texture cache overflow for WebGL HTML5 game

I am creating an HTML5 web adventure game and making tilemaps with Tiled.
Even with Texture Packer, I seem to be exceeding max cache of texture units as I'm getting error
Texture cache overflow: 16 texture units available
WebGL Stats shows the limit is 16 for ~70% of devices. My browser, as shown here, supports 16 texture units:
In game, I opened Chrome console to check WebGL specs:
WebGL2RenderingContext.MAX_TEXTURE_IMAGE_UNITS = 34930
WebGL2RenderingContext.MAX_VERTEX_TEXTURE_IMAGE_UNITS = 35660
WebGL2RenderingContext.MAX_COMBINED_TEXTURE_IMAGE_UNITS = 35661
This is a bit confusing as this article shows output should be more in the 0-10 range, not 30,000 range:
maxTextureUnits = 8
maxVertexShaderTextureUnits = 4
maxFragmentShaderTextureUnits = 8
My question(s):
How can I determine which images in my packed texture atlas are causing the issues? I.e., how can I check the total textures?
Is it possible to force a higher cache limit?
The way to check those values is
const maxFragmentShaderTextureUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
const maxVertexShaderTextureUnits = gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS);
const maxTextureUnits = gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS);
Further, those values have to do with how many textures you can access in a single shader not how many textures you can have in total.
They also have nothing to do with a "cache"
In your case you probably want to combine your textures into a single texture atlas (one texture that contains all your tiles).
Here's some code that does that.
It loads a tiled json file, then loads all the referenced images, it then creates a 2D canvas and copies the tiles from each image into the canvas, remapping the tiles in the maps to match. When it's finished it uses the canvas as the source of the tile texture. Normally I'd do this offline but it was nice to just be able to hit "reload" to see a new map that I left it at runtime.
In that same library is a shader that draws tilemaps including flipped and rotated tiles. In other words, to draw a tiled map it's one draw call per layer and only 2 textures are used. One texture holds the tile images (the texture created above). Another texture holds a layer of a tiled map. The shader reads the tiled map texture and uses that to draw the correct tile from the tile image texture. You can see an explanation of this technique in this article
BTW: The library with the tiled loader also has a shader that can selectively adjust the hue of a sprite. The library was used with a few games, for example this game
How can I determine which images in my packed texture atlas are causing the issues? I.e., how can I check the total textures?
You manage the textures, not WebGL, so if you want to know how many you're using add some code to count them.
Is it possible to force a higher cache limit?
No, but like I said above this has nothing to do with any cache.
My guess is you're using some library or your own code is generating a shader and that you're adding more and more textures to it and the shader generator therefore generating a shader that uses too many textures. The question is why are you using so many textures in the same draw. No 2D game I know of uses more then 2 to 6 textures at in one draw call. The game might use 10000 textures but to draw a single sprite or a layer of tilemap it only needs 1 or 2 textures.
To put it another way. A typical game would do
for each layer of tilemap
bind texture atlas for layer (assming it's different than other layers)
draw layer
for each sprite
bind texture for sprite
draw sprite
In the example above, even if you had 10000 textures only 1 texture is ever in use at a time so you're hitting no limits.

Drawing un-antialiased polygons on HTML5 canvas

I'm trying to create a polygon that has un-antialiased, unfeathered, unsoftened, etc. edges/sides. My goal is to have a polygon that has visible pixelated edges like an old-school game would. I found that images do not use antialiasing with proper settings, but I'd like to use lineTo and paths to create the polygon (because I need to be able to change the colors etc).
Using scaling (setting the canvas size one fourth of the actual size and scaling the canvas up with CSS styling), translating the shape by 0.5 pixels and setting the image-rendering property to pixelated results in this:
https://jsfiddle.net/6gbo7x3g/4/
Even though the result is better than without the tricks, you can still see antialiasing. The browser support isn't great either, as pixelated image rendering isn't supported in Safari. Here is a screenshot from Chrome of the canvas above:
image of antialiased polygon
How can I create a polygon (that has diagonal edges) un-antialiased? There will be multiple similar polygons, so drawing every pixel by hand would be too resource-intensive.
Questions like How can I keep the edge pixels of lines from being semi-transparent?, stackoverflow.com/a/45749684/1693593 and stackoverflow.com/a/18551803/1693593 aren't duplicates, because they only apply to scenarios where pixel-by-pixel rendering is applicable (in this scenario it is too resource-intensive). I asked this question, because other questions date almost four years back, and surely the web standards have changed since then.

Performant GL Triangles Mapbox GL JS

I am working on trying to create a basic, grid-based, but performant weather-arrow visualization system.
EDIT 2:
Up-to-date version here: ( Mapbox Tracker ) of the system using the workflow which is described below
Usage Instructions:
- Click on Wind icon (on the left)
- Wait for triangles to occupy screen
- Pan time-slider (at the bottom)
As you will observe (especially on larger resolutions or when panning time slider quickly) there is quite a performance hit when drawing the triangles.
I would greatly appreciate any advice on where to start with either using something in the current API which would help, or any ideas on how to tap into the current graphics pipeline with some type of custom buffer where I would only need to rotate, scale, change color of triangles already populated in screen space.
I feel as though my specific use-case would greatly benefit from something like this, I really just don't know how to approach it.
I have a naive implementation running using this workflow:
Create a geojson FeatureCollection source
Create a fill layer
Using Data Driven property: fill-color
Data function:
Get map bounds
Project sw & ne into screen points (map.project(LatLng))
Divide height and width into portions
Loop through width and height portions
Lookup data
Access data rotation property
Create vertices based on center point + size
Rotate vertices
Create Point objects for vertices
Unproject Point Object and wrap map.unproject(Point).wrap()
Create Feature Object, assign Data driven Color
Assign unprojected LatLng as Coordinates to Polygon geometry
Add to Feature Array for Collection
Call setData on layer
So while this works, I'm looking for advice for a more performance friendly approach.
What I'm thinking here is whether I can somehow create a custom layer, one where I only need to draw to screen co-ordinates to represent the data relative to its LatLng point. So that I can draw colored, scaled, rotated triangles in screen space, and then have them update to relevant data from the new relative LatLng position.
E.g. Update some type of Mesh on screen instead of having to: unproject, then update feature collection source using map.getSource('arrows').setData(d), requestAnimationFrame(function) etc.
I've done similar in three.js in other projects but I would much rather use something that is more mapbox native. Does this sound feasible? Am I going to see a decent performance boost if so?
I've not dealt with raw gl calls before etc so I might need a pointer or two in the right direction if its going to need to get as low level as that.
EDIT:
Previous Implementation using gmaps / three.js : volvooceanrace
(wait for button on left to go from grey to black) click on top button which shows a 'wind' label when hovered over, slide red time bar underneath to change data.
Added screenshot of current working implementation
Mapbox GL Arrows
Not sure what was available in 2016, but a reasonable approach these days might be to use symbol layers, and the icon-rotate data-driven property to rotate each icon based on the property of its data point.

Categories