I wanted to know if there was a way to print all the LatLng points of the vertices of a polygon that is dynamically set by a user via a "List< LatLng > X = []". As of now, I can only get the first point of a specific polygon to print. I don't think I need to post the code bc any way to achieve printing all points works fine. Thoughts?
Related
I am using QGIS and I imported the Google maps sattelite map. Then I drew a line and measured the distance using the Measure Tool, but the distance is inaccurate (it says about 1200 m, but I know it should be 780 m). Also, when I look at the coordinates of a point on the map (shown in Figure 1: coordinates of the point with a star on it), it is different from the coordinates I find when looking up the coordinates online (https://www.gps-coordinates.net/) (shown in Figure 2: coordinates of the same point as in Figure 1), so there is probably something wrong there.
I imported the Google maps sattelite map via: browser panel --> XYZ tiles -> Sattelite -> New Connection -> URL = http://mt0.google.com/vt/lyrs=s&hl=en&x={x}&y={y}&z={z}.
I drew the line in a 'lines layer'.
I already changed the CRS to ETRS89/UTM zone 32N (I am looking at a place in eastern Germany) both in the general project properties and in the layer which includes the line I drew. I also checked whether the unit of distance was right, and it is indeed meters. Lastly, I changed the coordinates from X and Y to degrees/minutes/seconds. Nothing worked and the result stays about 1200 m.
I hope you can help, thanks in advance!
I just figured out how to fix the problem. It turns out the map I was using did not use the right coordinates (I still don't know why). I now added another map (QuickMapServices) and this one does use the right coordinates. The Measuring Tool also gives the right distance now.
I have a map for my Pen and Paper RPG and I want to show it via Leaflet.
I put the Png-File throw a Tile- Making Script and was able to generate this map.
I want to do the following things but don't know how:
Place the equator on the actual equator of the map
Putting bounds on the map, but only for the north-south-axis
The scale calculates with the dimensions of the real earth and i want to give it the dimensions of my world
I want my markers and polygons to repeat every 360°
I would appreciate any help,
Civer
To get the equator you could use a polyline like
var latlngs = [
[0, -180],
[0, 180]
];
var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);
Not really sure what you mean by "putting bounds on the map". Are you saying you want to limit the user's ability to pan to areas outside of the map? Or are you talking about some sort of visual bounding line?
To do stuff with with different scales I'd suggest you look into how leaflet's Coordinate Reference System works (CRS). Take a look at this page: https://leafletjs.com/examples/crs-simple/crs-simple.html
It looks like you commented out some CRS stuff in your demo.
Background:
I am working on a web based mapping application for hiking. So the map based on leaflet offers routes on hiking trails that are labeled. As any hiking trail can be part of multiple routes, routes - respectively the corresponding polylines representing the routes - can overlap.
Problem:
Each route has its tooltip (triggered by mouseover, {sticky:true}) showing its label which works as expected for non-overlapping polylines but as soon as two or more routes overlap only the polyline "on top" gets its tooltip opened. This behaviour is not bad per se but as all routes are equally important I would like to show all labels of the routes at the pointer's location (or something like a maximum of 5 labels + x more). I weren't able to find any issue related to this topic.
What I tried:
- Create a feature group for all routes, bind the tooltip to the group, hoping that the tooltip function provides an array of all polylines crossing the pointer's position. As it turned out, I only get information of the polyline on top
- I tried the same with a mousemove event on the map, no success
- Comparing pointer's layerPoint coordinates with all routes' _rings & _parts layPoint arrays to find matching layerPoints, but the success rate is only about 5% as these layerPoints only cover actual points of the polyline but not the connection between two points. Additionally, there is a margin around each polyline that triggers the tolltip before the pointer even touches the polyline (too improve touch action, I guess)
- A solution to the margin problem is to add positive and negative margins to each polyline point before comparing it to the pointer coordinates which improves the outcome but doesn't solve the main problem.
Sidenote:
- All routes are drawn into a single canvas
Long story short, I need external help to accomplish the goal. Maybe some of you have an idea or can provide a solution. Any input is appreciated.
** UPDATE: **
A working but pretty inefficient solution is as follows
Approach:
Calculate the shortest distance from the pointer to all routes in viewport. If distance from the pointer to a route is under a certain threshold, add them to the array of route labels that should be displayed.
Steps:
1.) bind a blank tooltip to the a feature group containing all routes
2.) bind mousemove event to the feature group with the follwing function
var routesFeatureGroup = L.featureGroup(routesGroup)
.bindTooltip('', {sticky: true})
.on('mousemove', function(e){
var routeLabels = [e.layer.options.label]; // add triggering route's label by default
var mouseCoordAbs = el.$map.project(e.latlng);
$.each(vars.objectsInViewport.routes, function(i, v){
if (e.layer.options.id != el.$routes[i].options.id && el.$routes[i]._pxBounds.contains(e.layerPoint)){
var nearestLatlngOnPolyline = getNearestPolylinePoint(e.latlng, el.$routes[i]);
var polyPointCoordAbs = el.$map.project(nearestLatlngOnPolyline);
var distToMouseX = polyPointCoordAbs.x - mouseCoordAbs.x;
var distToMouseY = polyPointCoordAbs.y - mouseCoordAbs.y;
var distToMouse = Math.sqrt(distToMouseX*distToMouseX + distToMouseY*distToMouseY);
if (distToMouse < 15) {
routeLabels.push(el.$routes[i].options.label);
}
}
})
var routesFeatureGroup.setTooltipContent(routeLabels.join('<br>'));
})
Explanation:
I already gather all objects (routes and markers) in the current viewport for another part of the app. All routes currently visible are stored in vars.objectsInViewport.routes (respectively their ids), so I dont have to go through all routes. The layer that triggered the mousemove event is added by default. I then check for each of the routes currently visible if:
- their id is different to the layer that trigger the mousemove event (as this label is added by default)
- if their bounds (in cartesian coordinates: "_pxBounds") contain the cartesian layerPoint of the mousemove event (for a rough approch to exclude routes that don't intersect)
If these conditions are met for a route, calculate the closest latlng point from the pointer to the route. I do this with a custom function, which is a bit to long to post it in this context. (I will if someone asks for it)
The mouse position and the latlng point on the polyline / route are then converted to absolute coordinates using the map-project method
http://leafletjs.com/reference.html#map-project
At last, the distance between these to points is calculated using pythagoras. It is pixel based, so that the zoom level isn't a factor. If the distance is below a certain threshold (15px) they are close enough to the pointer to be considered as being hovered (with the default margins around a polyline), so the label of the route is added to the label array.
Finally the tooltip for the feature group is filled with all labels.
Results are pretty promising even though the operation is pretty expensive. I added a timeout of 50ms to reduce the function call a bit:
var tooltipTimeout;
var routesFeatureGroup = L.featureGroup(routesGroup)
.bindTooltip('', {sticky: true})
.on('mousemove', function(e){
clearTimeout(tooltipTimeout);
tooltipTimeout = setTimeout(function(){
// collect labels
// ...
},50);
.on('mouseout', function(){
clearTimeout(tooltipTimeout);
})
I can give you an idea of how to do this, but I am not 100% sure that it will do the job. There is a plugin for Leaflet (Mapbox) that can tell you if a point is within a Polygon and it returns all the Polygons that contain that point.
If this plugin doesn't work for polylines you can create a polygon from a polyline by just going back from the last point to the first and closing the line (I am not sure if this suits you solution). For example if you have a polyline of connected points of [0, 1, 2, .... n-1, n] you then go back with connecting [n with n-1, n-1 with n-2, ... 1 with 0]. This way you will have the same shape of the polyline but it will be a polygon. This isn't the most optimized solution, it is a quick fix that uses a known and available plugin.
Once you get all the tooltips, you can open all of them at once for each polygon/polyline. Or maybe open some helper tooltip where the user can select which one he wants to open.
I hope this helps! If you figure out a better solution (or find a plugin that does the job) please post it here.
I have a historical city map that I want to display using Leaflet.
I like to set the coordinates of this image to reflect the real world, e.g so I can click on the image and get the real coordinates.
I guess I can just make it an overlay to a real map, but there must be a better solution just define at what coordinates of the corners of the image.
For this image, the approx real world coordinates is NW: 60.34343, 18.43360, SE: 60.33761, 18.44819
My code, so far, is here:
http://stage1876.xn--regrund-80a.se/example3.html
Any ideas how to proceed? It feels like it there should be an easy way to do this?
Any help would be so appreciated!
EDIT: The implementation (so far) with tiles are optional. I could go for a one image-map as well.
Is it possible to dim or hide the "rest of the world" except one country on a standard leaflet.js map? Mabye overlay out with some kind of "inverted polygon" with the contours of the country? Any code examples or links would be appreciated.
Expanding #tmcw's answer ...
The secret is to draw a polygon using the property described in http://leafletjs.com/reference.html#polygon
You can also create a polygon with holes by passing an array of arrays
of latlngs, with the first latlngs array representing the exterior
ring while the remaining represent the holes inside.
The first polygon will be a rectangle as big as the map itself, the hole will be the country you want to highlight.
L.polygon( [outerBoundsLatLngs, latLngs] );
Here is a working example: http://jsfiddle.net/FranceImage/1yaqtx9u/
See the leaflet-maskcanvas and L.Mask plugins