I'm trying to add real-time, web-socket event-based data to my map.
Everytime I get a point, I must add it/update it on map.
What's the best option?
A) Create a FeatureCollection and add a source and respective layer. When updating, change the FeatureCollection and call setData();
B) For every point, create a different source and layer. When updating, just change the respective source and call setData();
I really don't believe B) is the best option, I'm just not sure about the perfomance of option A) (or I'm thinking about the former the wrong way).
I'd say it somewhere between the two. For Mapbox Draw I use two layers, one for features that are being edited and one for features that aren't changing. In your case, you'd want to create a layer for every 100 features. This is because Mapbox GL has to recut the geojson into tiles every time you add a feature so limiting the number of features that have to be reviewed is wise. That said, lots of layers will be a problem too.
While I said 100 features above, you'll want to play around with this number a bunch. It will be about finding the right balance between number of layers and number of features in a source.
Related
I'm new to leafletjs. Been working on cesiumjs for a while and we are trying leaflet now. The main reason for the switch is to see if there's a huge performance difference.
In Cesium, I had a collection of primitive points that I plotted. What's the most efficient way of plotting 140K points in leafletjs? Using markers or creating individual little circles?
I am also thinking of using the clustering plugin (http://leafletjs.com/2012/08/20/guest-post-markerclusterer-0-1-released.html), so please share any thoughts on performance.
You have 2 common options:
Display your points in a Canvas-based layer, like using Circle Markers and force rendering them on a Canvas instead of SVG (see also Leaflet MaskCanvas plugin). Circle Markers, even on a canvas, still emit events, so you can detect "click" etc.
Use a clustering plugin, like Leaflet.markercluster plugin that you mention for exampe. It can handle your 140k points, depending on the client's computer performance (see https://github.com/Leaflet/Leaflet.markercluster#handling-lots-of-markers and demo http://leaflet.github.io/Leaflet.markercluster/example/marker-clustering-realworld.50000.html with 50k points, but note that the demo uses an old version of the plugin, whereas the current version is even faster).
Trying to display your 140k points without Canvas or clustering will crash your browser for sure.
If you want to render more than 100k markers, you can use Supercluster library, because Leaflet.markercluster loading of >100k markers could take more than 30 seconds.
I created a github repo to compare initial loading of Leaflet.markercluster and Supercluster.
So, basic gist is, I have my own tiles of not the real world I'd like to display with the Google Maps viewer. I've found examples of how to split an existing single image into tiles for use with it, but nothing that deals with setting up your own tiler.
I have map data such as this:
https://dl.dropboxusercontent.com/u/44766482/superimage/index.html
Which right now is just a bunch of 1600x1600 images in an html table. This naive method works, but I'd like to switch to the more robust google api for better zooming and smarter streaming of the image data.
I've been unable to find a good example of how to generate your own tiles for the zoom levels and bring it together with some html/js.
If you want some more information for the goal process;
I have a python script that can output any size tiles of the map, at any zoom level. I'd like to bundle those together into a google maps api website. But in my own efforts I have not found a good example or documentation of how to do that. For one, I can only find examples of how the zoom levels work for the real world map, but not for a custom one.
Edit:
Got most things working as I want them, but I'm still confused regarding the "center" that can be set, as it's in lat and lng, which don't apply. I'd also like to set boundaries as currently it tries to load .png files outside of the maps range.
My current progress:
https://dl.dropboxusercontent.com/u/44766482/googlemapspreview/index.html
I think what you are looking for is the google maps imageMapTypes:
https://developers.google.com/maps/documentation/javascript/maptypes#ImageMapTypes
Basically, each zoom level is the 4 lower zoom tiles combined. A Projection function can be skipped to get orthogonal mapping.
My question is about updating the data in leaflet.
Let's assume that we have geojson which we are changing into vector tiles using geojson-vt.js and displaying it on the leaflet map.
Similiary as there: geojson-vt example
Then i'm receiving an event / notifiaction that some linestring was changed, for example thise linestrings have a attribute color, which is using when displaying data, and this value has changed.
Then i want to update my map, but i dont want to recalculate, and redraw all tiles, but only this tiles where was change. How to do that?
It cannot be done. geojson-vt only allows for creating new geojson-vt instances, not updating them. Updating data in the internal structures is too complicated, and doesn't give any big advantages. This also means it's not possible to get a list of changed tiles, or even a list of tiles containing the updated geometry.
If this is really critical for your application, consider studying the code for geojson-vt for yourself, and proposing a solution.
If you have a set of static features and a set of possibly-changing features, consider making separate holders for them.
Ever noticed that when you go to maps.google.com and do a search (say, car wash), it renders a lot of results (represented by small circles) and a few prominent ones (seen as regular-size pins)?
Notice how quickly it does this?
From what I can tell from analyzing this in Firebug, much of this is generated on the server and sent to the client as a static image.
However, it's still dynamic. You can still zoom in and out, or click on a result and see a dynamic InfoWindow rendered.
Google have made the map quick and smooth using static images, while still making it flexible.
Is there a way to do this kind of 'pre-loading' with my own Google Map (implemented with the Google Maps API)?
The technology that maps.google.com uses is similar to that used in a GLayer. The server dynamically builds tiles and "hotspot" info. The GLayer tiles are also constructed dynamically (and possibly cached) even though the underlying data is fairly static. From the client side, the searched dots technology is identical to the Wikipedia or Panoramio GLayer. The only new trick is that the dot information is generated dynamically on Google's big fast servers.
The API does not (yet) provide any tools for creating custom GLayers. If you want to do the same sort of thing yourself, using your own database of locations, there are three steps that you need to code:
Create your own custom tileserver
which searches your database for
items in the tile area and uses a
graphics library like gd or
imagemagic to place dots on the
tile. Use those tiles to create a
GTileLayerOverlay on the client.
When the user clicks on the map,
send the location of that click to a
second server. That server should
check your database and return the
infowindow text for the dot at that
location, if any. Returning all the infowindow contents from all the dots imaged by the tileserver would be unacceptably slow, so you have to fetch them one by one, as needed.
Changing the cursor when the mouse
is over a dot is more tricky. What Google
do is return a list of hotspot
coordinates for all the dots on each
tile. Whenever the mouse moves, the
API determines which tile the
pointer is over and uses a quadtree
algorithm to see if the pointer is
over a hotspot, and change the
cursor if necessary. If you only
have a modest number of hotspots per
tile, then a linear search would
probably be acceptably fast. If you might have thousands of dots per tile, then you'll probably need to write your own quadtree algorithm. The Google quadtree code is not exposed, so you can't use it.
Here's a page where somebody has done all that. In this case the hotspots are calculated as circles, by comparing the distance from the centre point, even though the dots are square. On maps.google.com the hotspots are calculated as rectangles, by using GBounds.containsPoint(), even though the dots are round.
I'm doing something similar - but instead using a tile layer, I just send server-clustered markers to the browser whenever the view changes. If your data is static, you can pre-cluster your markers and it would be incredibly fast with tens of thousands of markers.
Our site can't use pre-clustering because the markers can be searched and filtered, but it's still pretty fast up to about 20,000 markers. Still working on it...
I want to implement my own clustering algorithm using this Virtual Earth javascript API: http://msdn.microsoft.com/en-us/library/cc966716.aspx
However, the VE engine calls my cluster function once for every shape in the layer. This makes it very slow!
It seems to me that VE should put all the shapes into a layer, then ask my function to cluster them. Not repeatedly call cluster!
Why does the VE engine do this? Is there another way to do client side clustering with this API?
More Information: I am loading the shapes from a GeoRSS feed.
The custom clustering algorithm method will only get called once for that VEShapeLayer.
Adam Byram,
There's not much difference in between using the VEMap.AddShape method and adding a VEShapeLayer to the map with all the Shapes inside. The AddShape method adds the Shape to the "default" ShapeLayer, which is the ShapeLayer with 0 (zero) index, and adding a VEShapeLayer adds a new layer in addition the the existing "default" layer.
It is probable that if you are using VEMap.AddShape to add the VEShape object to the map, that it is calling your clusting algorithm method everytime a VEShape is added to the Map. This would be correct behavior since it will need to re-calculate the clustering each time a shape is added.
To improve overall performance when adding all the shapes to the map, and to get VE to call your custom algorithm method only once when adding all the shapes; you can create a VEShapeLayer, add all the Shapes to it, then add that shape layer to the map. This will cause VE to only do the rendering of all the Shapes once (at time of loading them all) instead of each and every time you add a single VEShape.
It should only be calling your code once per VEShapeLayer - otherwise, clustering is pointless since you can't cluster a single shape. Are you using VEMap.AddShape instead of adding VEShape objects to a VEShapeLayer? If so, try creating a single VEShapeLayer, add it to the VEMap, and then add all VEShape objects to the shape layer instead of the map.