I am new to leafletjs. I am working on a map that renders just the united states map with few layers options such as roads and major roads ecc.. I have a base layer that uses WMS protocol to get the first layer's tiles with the following code:
L.tileLayer.wms(......)
Then I have another layer that comes from a different server which does not use WMS protocol. This server accepts parameters like bbox, height, width, lat, lng and few others. I can query this server for one tile at a time, so i need to provide multiple ajax calls to get multiple tiles to cover my current view and also update all layers when the map is moved.
The problem I have is how to make both layers work together? and how to get the Bounding Box of each tile the leafletJS way? and how to continue to update all tiles on "moveend" event as the user moves the map?
Using version 0.7.3 of leafletJS!
Thanks for your help
There is undocumented function in L.TileLayer class:
L.TileLayer.getTileUrl(tilePoint)
This function is called for each tile on a screen. It receives hash with x, y and z keys (tile number) and returns image URL for the tile. You can rewrite this function in your L.TileLayer instance:
var layer = L.tileLayer(url);
layer.getTileUrl = function(tilePoint) {
return 'http://example.com/' + tilePoint.z + '/' + tilePoint.y + '/' + tilePoint.x + '.png';
}
So, you don't need to track map movements, appearing and disappearing of tiles, etc.
Related
I have a geography column in database. This column holds the original polygon. Next to it I have another column that holds the simplified version of this polygon. The simplification has been done with geography.Reduce()(I use tolerance of 100) function that operates with Douglas-Peucker algorithm. When the client asks for this area I fetch it from database and do a quick convert into GeoJSON and serve it to my client.
If I query the original polygon it will take good 20 seconds before it is successfully retreived but it works. In the end only problem is the speed and that is why I introdouced the second column that holds the simplified polygon. Fetching this polygon from database happens in an instant but a curious thing happens on the client side.
As you can see multiple markers are shown on my map. None of them are clickable expect the top most(slightly south-west from Melbourne) but this one is actually a marker that I have added. Where do the other ones come from?
Another thing I noticed is the more I reduce simplicity the less of these fanthom markers shows. So if I serve the original polygon as GeoJSON all is fine. As soon as I start simplifying I get these fantom markers.
When I query for this simplified polygon I use geography::STAsText() function. After that I use NetTopologySuite to read this as WKT and create a NetSuiteTopology Geometry object. With this object I create a Feature and use GeoJsonWriter to create the actual GeoJSON.
var query = new SqlQuery("Location")
.Select("LocationServicingAreaSimplified.STAsText()")
.Where("LocationID", SqlOp.Equals, "#LocationID");
// This object query will be convertet to
// SELECT LocationServicingAreaSimplified.STAsText() FROM Location WHERE LocationID = ?
query.Parameters.Add("#LocationID", LocationID);
var simplifiedPolygon = await query.ExecuteScalarAsync<string>();
var wktReader = new WKTReader() { DefaultSRID = 4326 };
var geoJsonWriter = new GeoJsonWriter();
var feature = new Feature
{
Geometry = wktReader.Read(simplifiedPolygon)
};
return geoJsonWriter.Write(feature);
After an extensive research I have concluded that the proces of simplification will produce points when some polygons are oversimplified. google maps will represent the points as markers therefore, the greater the simplification the more points are produced the more markers are present.
I have found an article where it is described how to get rid of these points but haven't yet tested it.
Hope this helps some spatial noob(like me).
I have a question in React implementation for zoom/pan function for a scatter plot.
I wonder what approach would be good and want to hear opinions of React & data visualization expert.
I am specifically interested in implementing zoom/pan function of a scatter plot that is dynamically changing data range to visualize.
(Approach 1) Given a data range (controlled by mouse wheel event), first, filter the data, and render circles () for the filtered data. In this case, each circle will be generated with new key such that
const circles = [];
filteredData.forEach( (d, index) => {
circleProps = { /*..compute circle props... (e.g. position within a SVG) */ }
circles.push(
<circle key={`circle-${index}`} {...circleProps} />
);
});
Thus, every time the data range changes, it will create new set of circles located within the range.
(Approach 2) Similar to Approach 1 but no filtering on the data. Instead, use clip path to visualize only the circles within the range. In this case, it will update entire circles according to re-calculated positions but it will only create the circles one time at the beginning.
What would better approach? Or, any other options to handle large-scale data? Also, please correct me if anything is wrong.
Thanks.
My Codename One app features a MapContainer. I need to show points of interest (POIs) on it which coordinates reside on the server. There can be hundreds (maybe thousands in the future) of such POIs on the server. That's why I would like to only download from the server the POIs that can be shown on the map. Consequently I need to get the map boundaries to pass them to the server.
I read this for Android and this other SO question for iOS and the key seems to get the map Projection and the map bounding box. However the getProjection() method or the getBoundingBox() seem not to be exposed.
A solution could be to mix the coordinates from getCameraLocation() which is the map center and getZoom() to infer those boundaries. But it may vary depending on the device (see the shown area can be larger).
How can get the map boundaries in Codename one ?
Any help appreciated,
Cheers,
The problem is in the javadocs for getCoordAtPosition(). This will be corrected. getCoordAtPosition() expects absolute coordinates, not relative.
E.g
Coord NE = currentMap.getCoordAtPosition(currentMap.getWidth(), 0);
Coord SW = currentMap.getCoordAtPosition(0, currentMap.getHeight());
Should be
Coord NE = currentMap.getCoordAtPosition(currentMap.getAbsoluteX() + currentMap.getWidth(), currentMap.getAbsoluteY());
Coord SW = currentMap.getCoordAtPosition(currentMap.getAbsoluteX(), currentMap.getAbsoluteY() + currentMap.getHeight());
I tried this out on the coordinates that you provided and it returns valid results.
EDIT March 21, 2017 : It turns out that some of the platforms expected relative coordinates, and others expected absolute coordinates. I have had to standardize it, and I have chosen to use relative coordinates across all platforms to be consistent with the Javadocs. So your first attempt:
Coord NE = currentMap.getCoordAtPosition(currentMap.getWidth(), 0);
Coord SW = currentMap.getCoordAtPosition(0, currentMap.getHeight());
Will now work in the latest version of the library.
I have also added another method : getBoundingBox() that will get the bounding box for you without worrying about relative/absolute coordinates.
This is probably something that can be exposed easily by forking the project and providing a pull request. We're currently working on updating the map component so this is a good time to make changes and add features.
I have trouble getting Map behave properly when calling ZoomToResolution and PanTo
I need to be able to Zoom into specific coordinate and center map.
The only way I got it working is by removing animations:
this.MapControl.ZoomDuration = new TimeSpan(0);
this.MapControl.PanDuration = new TimeSpan(0);
Otherwise if I make call like this:
control.MapControl.ZoomToResolution(ZoomLevel);
control.MapControl.PanTo(MapPoint());
It does one or another (i.e. pan or zoom, but not both). If (after animation) I call this code second time (map already zoomed or panned to needed position/level) - it does second part.
Tried this:
control.MapControl.ZoomToResolution(ZoomLevel, MapPoint());
Same issue, internally it calls above commands
So, my only workaround right now is to set Zoom/Pan duration to 0. And it makes for bad UX when using mouse.
I also tried something like this:
this.MapControl.ZoomDuration = new TimeSpan(0);
this.MapControl.PanDuration = new TimeSpan(0);
control.MapControl.ZoomToResolution(ZoomLevel);
control.MapControl.PanTo(MapPoint());
this.MapControl.ZoomDuration = new TimeSpan(750);
this.MapControl.PanDuration = new TimeSpan(750);
Which seems to be working, but then mouse interaction becomes "crazy". Mouse scroll will make map jump and zoom to random places.
Is there known solution?
The problem is the second operation replaces the previous one. You would have to wait for one to complete before starting the next one. But that probably doesn't give the effect you want.
Instead zoom to an extent, and you'll get the desired behavior. If you don't have the extent but only center and resolution, you can create one using the following:
var zoomToExtent = new Envelope(point.X - resolution * MapControl.ActualWidth/2, point.Y, point.X + resolution * MapControl.ActualWidth/2, point.Y);
Btw it's a little confusing in your code that you call your resolution "ZoomLevel". I assume this is a map resolution, and not a level number right? The esri map control doesn't deal with service-specific levels, but is agnostic to the data's levels and uses a more generic "units per pixels" resolution value.
My map (Mapbox) takes up the whole background of the site so the center is in the middle of the site. But the focus of the map for the user is on the right side because I have content overlapping the map on the left side. When leaflet grabs the location, it's from the center of the map, but it would be more convenient if I could set it to grab the location from the center of the right third of the site, so that way the user won't be centering the map on targets bordering content on the left half of the site.
Is there a way I could set the center or location focus of the leaflet API for the map?
Here's how I have it set up currently,
mapOptions: {
maxZoom: 18,
zoomControl: false,
worldCopyJump: true
},
createMap: function() {
Map.map = L.map('map', Map.mapOptions);
Map.layer = L.mapbox.tileLayer(Map.mapID, {
unloadInvisibleTiles: true,
}).addTo(Map.map);
Map.map.locate({setView: true});
Map.map.addControl(L.mapbox.geocoderControl(Map.mapID));
new L.Control.Zoom({ position: 'topright' }).addTo(Map.map);
},
You can use a combo of panBy() and getSize() to offset the map the width of your overlay.
Here's a snippet that should get you a started:
// Calculate the offset
var offset = map.getSize().x*0.15;
// Then move the map
map.panBy(new L.Point(-offset, 0), {animate: false});
In my example, my overlay is 33% of the width of the map. So I grab the size of the map area, then multiple by 0.15 (this was based on some experimenting to see what the best offset amount was) and use panBy() to offset the map center.
Here's a full example.
If you have multiple markers and want to center the map in their bounds and at the same time you have overlapping container, you can use the fitBounds options (paddingTopLeft, paddingBottomRight, padding).
http://leafletjs.com/reference.html#map-paddingtopleft
First you will need to know the lat and long of the point on the map you want to center on. Then it is simple, just call Map.map.setView passing in your coordinates and zoom level.
Api reference: http://leafletjs.com/reference.html#map-set-methods
If you don't know your coordinates then you can find it by trial and error, just create a marker and add it to the map.
Found this solution by ghybs over on GIS which helped me solve this problem:
Leaflet-active-area
This plugin allows you to use a smaller portion of the map as an active area. All positioning methods (setView, fitBounds, setZoom) will be applied on this portion instead of the all map.