target several overlapping features in leaflet simultaneously - leaflet

I am new to leaflet, but am trying to implement a use case that I've been unable to find any examples or questions about here. Thank you in advance for helping with this question:
A live demo is here, and here's the code of interest in the GitHub repository.
As you mouseover the various geoJSON features, I use onEachFeature to change styling to 'highlight' that featured area on the map, and to display its name in the upper right info box:
function onEachFeature (feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight
});
layer.bindPopup(feature.properties.f2,customOptions);
}
var geojson;
geojson = L.geoJson(myData,{
style: style,
onEachFeature: onEachFeature,
}).addTo(map);
The problem arises where features overlap. When mousing over the overlapping regions only one is targeted. Instead, I would like all features overlapping at the cursor's position to be 'highlighted'; and to be able to list all the names in the info box.
I'm guessing that the solution is more like that I should retrieve the latlng on all mousemove events, determine if the latlng is in the boundary of any geoJSON objects, and if so, iterate through those highlighting and getting the names for all. I'm not sure if there is a plugin that can handle this more elegantly for me.
Is there anyway to target multiple overlapping geoJSON layers simultaneously in Leaflet?

You described an easy way, and I recommend you use it. I propose just one optimization for you.
Don't catch all mousemove events. You need a mouseover on each feature, and then check if there are other features overlapped by it.
function onEachFeature (feature, layer){
layer.on('mouseover',function(e){
var point = e.latlng;
map.eachLayer(function(layer){
var bounds = layer.getBounds();
if(bounds.contains(point))
highlite(layer);
})
})
}
Another way is to use the L.Canvas renderer and extend it so that it fires mouseover or other handlers for each layer under the pointer.

Related

Is there a solution like leaflet-knn in ArcGIS (js-api) for finding the nearest point in a geoJSON multi-point feature to a given point?

This is how i get the closest point on a geoJSON line to a given point using leaflet-knn:
Given a point, find the nearest points to it. If the index contains multi-point features, like lines, polygons, and so on, it returns points in those features and can return more than one point in each feature.
const line= L.geoJSON(this.lineFromGeoJson, {
onEachFeature: (feature, layer) => {
layer.bindPopup(
'insignificant feature stuff here',
{maxHeight: this.screenHeight, maxWidth: this.screenWidth, autoPan: true});
}
}).addTo(this.map);
const nearest = leafletKnn(line).nearest(L.latLng(this.lat, this.longt), 1);
Is there anything similar in #arcgis/core?
I'm already using the geodesicUtils.geodesicLengths from arcgis to get the length of this geoJSON line and i figured perhaps there was a solution for this in arcgis that i have not found?
I think you could use geometryEngine.nearestVertices method (ArcGIS JS API - esriGeometry).
Now, this method actually takes a geometry as parameter instead of a layer, so you will probably will need to "create" the geometry using the layer or better a subset of the layer.
You can get a subset of the layer (set of features) with a distance query on the layer using ArcGIS JS API - Query.

Leaflet or mapbox icon rotation like computeheading

I have a map in leafletJS and when the icon moves along, I have the angle and I am using the Leaflet.RotatedMarker plugin to rotate the icon to face where its heading.
Does leaflet js have a plugin that can enable me to not supply the angle myself ...
L.marker([48.8631169, 2.3708919], {
rotationAngle: 45
}).addTo(map);
...and instead use a function like gogle maps' computeheading() ?
Edit:
Does mapbox have a function like computeHeading
https://github.com/bbecquet/Leaflet.RotatedMarker
js:
var boat_marker = L.marker([set_lat, set_long], {
pid: guid(),
// rotationAngle: 45,
icon: boatIcon,
draggable: true,
}).addTo(mymap);
function rotated_point() {
boat_marker.setRotationAngle(90);
}
No.
Leaflet has only a minimal set of geodesy-related functions. Functions to calculate headings, azymuths, geodesic distances or great circles are not needed for basic Leaflet functionality, and are not included.
A popular approach to this kind of problems is to rely on the javascript bindings of geographiclib for geodesy-related calculations (such as heading/azymuth), in the same way turf.js helps with geoprocessing of vector data.
Note that geographiclib is not a Leaflet plugin, but rather a generic set of geodesic functions. You will need to use a bit of care to get the latitude and longitude components of L.LatLngs, and fetch only the azymuth (and drop the distance) from the solution to the geodesic problem.

How to move geojson polygon in leaflet?

Say I have a geojson box I've added to leaflet. How can I allow the user to "click and drag the box" to a new location, which in turn updates all the coordinates automatically? I know how to edit the boundary/points that make up the shape using leaflet editing, but am not sure how to actually move the shape.
There is a Leaflet.Draw.Drag plugin for Leaflet Draw that allows you to move polygons when you enter edit mode. It does seem to be a bit finicky about the version, though. At least in a few quick experiments, I was only able to get it to work using Leaflet Draw version 0.2.3. If you have an existing L.GeoJson layer, you can simply specify that as the featureGroup in the edit options of the draw control:
var drawControl = new L.Control.Draw({
edit: {
featureGroup: yourGeoJsonLayer,
edit: {
selectedPathOptions: {
maintainColor: true,
moveMarkers: true
}
}
}
});
In the selectedPathOptions, the maintainColor option just keeps the existing style of the layer while you're editing, and the moveMarkers option places a little square marker in the middle of the polygon as a reminder that you can drag the whole thing rather than just edit the vertices.
Here is an example fiddle:
http://fiddle.jshell.net/nathansnider/qk5bsgn8/

Zoom in on maker group in leaflet mapbox?

I have a layerGroup in my map which has a lot of markers and another layerGroup which has a lot of circles. I need to zoom in on these layer groups but I cannot find the exact API method to do so.
I have tried:
var myLayerGroup = L.layerGroup().addTo(map);
myLayerGroup.fitBounds(); // tried this
myLayerGroup.setBounds(); // and this too
I am not sure which method in the API will work for me. How to zoom in on a layer of markers?
Switch from using layerGroup to featureGroup, theb you can use getBounds() on a feature group to retrieve its bounds, then use map.fitBounds(result) to zoom to that view.

Leaflet Map Clustering + Marker Rotation

Has anyone ever tried to use Leaflet Clustering Plugin + Marker Rotation Plugin? I tried to work with both but they work partially.
In a first view, I can see some clusters and some isolated (and rotated) markers. Every time I zoom in into some Cluster the rotated markers disappear. Does anyone have any idea why this happens?
to simply rotate a marker, use :This Leaflet Plugin
include this in your html :
<script src="../leaflet-plugin/Marker.Rotate.js"></script>
wen create a marker :
var marker = new L.Marker(map.getCenter(), {iconAngle: 90});
a complete example
Found a solution provided by Dave Leaver..it works perfectly.
"You can hack it to work with L.MarkerClusterGroup (so it is no worse than it is already) by changing the start of the update function in the rotate plugin to bail if there is no _icon:
update: function() {
if (!this._icon) {
return;
}
The problem is that the rotate plugin is overwriting the transform and fighting with leaflet on it.
I recommend instead using a DivIcon with a child element that has the rotation, that way leaflet can happily update the transform to move the marker independent of the rotation.
As a totally broken example:
var m = new L.Marker(getRandomLatLng(map), { icon: L.divIcon({html:'<img src="http://cdn.leafletjs.com/leaflet-0.5.1/images/marker-icon.png" style="-webkit-transform: rotate(39deg); -moz-transform:rotate(39deg);" />'})});"