Using leaflet 1.0.2, I have been following the tutorial Extending Leaflet: Handlers and Controls and I am building my own handler to draw a "bounding box" on the map.
So far this works very well, see the following example "pseudo" code:
L.BoundingBoxHandler = L.Handler.extend({
colour: '#0000FF',
rectangle: null,
addHooks: function () {
L.DomEvent.on(this._map._container, 'mousedown', this.start, this);
L.DomEvent.on(this._map._container, 'mousemove', this.mouseMove, this);
L.DomEvent.on(this._map._container, 'mouseup', this.mouseUp, this);
},
removeHooks: function () {
L.DomEvent.off(this._map._container, 'mousedown', this.start, this);
L.DomEvent.off(this._map._container, 'mousemove', this.mouseMove, this);
L.DomEvent.off(this._map._container, 'mouseup', this.mouseUp, this);
},
start: function (ev: MouseEvent) {
// get the lat long bounds of the mouse then draw a rectangle
this.rectangle = L.rectangle(latLngBounds, { color: this.colour,
weight: 2 }).addTo(this._map);
},
mouseMove: function (ev: MouseEvent) {
// code that gets the current location of mouse
// and calls setBounds on the rectangle...
},
mouseUp: function (ev: MouseEvent) {
// remove the bounding box
this.rectangle.remove();
}
});
I am adding the handler to the map by calling:
map.addHandler('boundy', L.BoundingBoxHandler);
In the code example, you can see that I have a variable called "colour" which determines the colour of the rectangle.
I would like to pass this colour in as an option when I create the handler, so that I can change the colour of the rectangle.
How do I pass in options when I create the handler in Leaflet JS?
How do I pass in options when I create the handler in Leaflet JS?
You don't. 😊
Look at how the default map handlers work: the use the map options to define their own behaviour.
For example, the code for the ScrollWheelZoom handler defines the following options in the map:
An implicit scrollWheelZoom option for enabling/disabling the handler when the map is instantiated.
wheelDebounceTime and wheelPxPerZoomLevel options for the behaviour of the handler.
It is perfectly OK for a handler to define new map options, as long as the names don't collide with the existing ones.
So if you've got a BoundingBox handler, you probably want to have an implicit boundingBox option and something like a boundingBoxStyle option, both as map options.
Related
I have a click event on a map feature that zooms into that feature when clicked by the user
Map starts like this:
When a user clicks on the map feature:
L.geoJson(geoJsonFeatureCollection, {
style,
onEachFeature
}).addTo(map)
function zoomToFeature (e) {
map.fitBounds(e.target.getBounds())
}
function onEachFeature (feature, layer) {
layer.on({
click: zoomToFeature
})
}
On a second click on the same map feature, after being already zoomed in, I'd like to forward the URL to another page (the info HTML page of that feature). But I can't distinguish both situations.
How can I know in map.fitBounds if the map bounds were already fitted, i.e., if the method actually did/zoomed/panned anything?
You can use the same calculation function from leaflet and check if it equals to the current map state:
function zoomToFeature (e) {
const bounds = e.target.getBounds();
const target = map._getBoundsCenterZoom(bounds);
if(target.zoom === map.getZoom() && map.getCenter().equals(target.center)){
// bounds already fitting
} else {
map.fitBounds(bounds);
}
}
Maybe you need to change the margin of equals. Default: .equals(target.center, 1.0E-9)
I have a layer with two polylines and polylineDecorators. I would like to highlight both polylines and polylineDecorators when I hover on any of these. Right now I'm able to highlight only one at the time when hovering on it.
Here is my code:
var layer_migration = L.layerGroup({
layerName: 'layer_migration',
pane: 'linesPane',
});
function onEachFeature_migration (feature, layer) {
var polyline = L.polyline(layer.getLatLngs(),{
color: "#8B0000",weight: 5,opacity: 0.4,dashArray: '8,8',
dashOffset: 0
}).addTo(layer_migration);
var PLdecorator1 = L.polylineDecorator(polyline, {
patterns: [{
offset: '104%',
repeat: 100,
symbol: L.Symbol.arrowHead({pixelSize: 16,
pathOptions: {color: "#8B0000",fillOpacity: 0.6,weight: 0
}
})
}]
}).addTo(layer_migration)
var myfeatures = L.featureGroup([polyline,PLdecorator1]).addTo(layer_migration);
myfeatures.on('mouseover', function(e) {
var layer = e.target;
layer.setStyle({color: '#8B0000',opacity: 1,fillOpacity:1
});
});
}
Any help super appreciated.
Thanks,
P
In your mouseover callback, I think that e.target will just refer to the individual layer (polyline or decorator) that triggered the event, not the collection of layers that make up the feature group. I've not tested it, but according to the docs, you ought to be able to get the effect you want by calling .setLayer() on the feature group itself:
myfeatures.on('mouseover', function(e) {
myfeatures.setStyle({color: '#8B0000',opacity: 1,fillOpacity:1});
});
Also, if the two polylines are created by two separate calls to onEachFeature_migration(), then they will end up as two separate feature groups. To get around this, you might need to assign an empty featureGroup to myfeatures outside the function, then add the new polylines to it inside the function using myfeatures.addLayer().
I start my application with expand Layer-Control:
L.control.layers(baseMaps, overlays, { collapsed:false } ).addTo(mymap);
I found no Mouse-Action to minimize the Layer-Control. I want to minimize the Layer-Control. But I don't know the handler. Could anybody give me a tip?
I had the same requirement for Leaflet. I needed to have the layer control expanded at first and then return to its normal hiding after someone realizes what it does.
I am using JQuery, but you could probably manipulate the DOM as well.
I have a function that instantiates the layer control object, and then I immediately reset the mouseenter and mouseleave events for the expanded control and the smaller toggle widget.
let layerControl = L.control.layers(basemap_items, { 'specialLayer': layer}, { collapsed: false }).addTo(map);
$('.leaflet-control-layers').on('mouseleave', () => {
layerControl.collapse();
});
$('.leaflet-control-layers-toggle').on('mouseenter', () => {
layerControl.expand();
});
I load some lat / lon info, then use it to build a polyline.
I then want to add a marker at each of the polyline vertices that will show when the polyline is clicked.
The vertices should disappear if a different (or the same) polyline is clicked.
The code below creates the polyline and the vertex markers.
But the vertex markers do not ever disappear.
I've tried to do this several ways with the same result. I've tried storing the vertex markers in an array and adding them directly to the map, then map.removeLayer'ing them. That doesn't work either. Nor does it work if I use an L.featureGroup instead of a layerGroup.
Clearly I've missed the point somewhere as to how markers can be removed. Could someone point me at the error in my methodology?
// trackMarkersVisible is a global L.layerGroup
// success is a callback from an ajax that fetches trackData, an array f lat/lon pairs
success: function (trackData) {
// build an array of latLng's
points = buildTrackPointSet(trackData, marker.deviceID);
var newTrack = L.polyline(
points, {
color: colors[colorIndex],
weight: 6,
clickable: true
}
);
$(newTrack).on("click", function () {
trackMarkersVisible.clearLayers();
$.each(points, function(idx, val) {
var tm = new L.Marker(val);
trackMarkersVisible.addLayer(tm);
});
map.addLayer(trackMarkersVisible);
});
}
Without a JSFiddle or Plunker it's hard to say because i'm not sure what behaviour your getting but using the clearLayers() method of L.LayerGroup should remove all layers from that group. I would check in the onclick handler if the group already has layers: group.getLayers().length === 0 If the group is empty, add the markers, if the group has layers use clearLayers. Example in code:
polyline.on('click', function (e) {
if (group.getLayers().length === 0) {
e.target._latlngs.forEach(function (latlng) {
group.addLayer(L.marker(latlng));
});
} else {
group.clearLayers();
}
});
This works for me, see the example on Plunker: http://plnkr.co/edit/7IPHrO?p=preview
FYI: an instance of L.Polyline is always clickable by default so you can leave out the clickable: true
I am trying to understand the JS in this popular tutorial.
The essence of the tutorial is this function which passes the parameter 'e' to the function. 'e''s target property is the self-referencing layer of the function.
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 5,
color: '#666',
dashArray: '',
fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera) {
layer.bringToFront();
}
}
How does JavaScript understand 'e'? When the callbacks to the function are made, no parameter is passed to the function as a variable in the event listener.
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
click: zoomToFeature
});
}
In http://leafletjs.com/examples/choropleth.html ...
First we’ll define an event listener for layer mouseover event
e is the mouseover event
So the sequence is like that
GeoJSON layer finds features and creates layers out of them
Each time a layer (e.g. a L.Polygon) is created, you are called back with onEachFeature
You can attach an event listener to the layer (e.g. mouseover)
Later on, when this layer receives a mouseover event, it will send the event (e) back to you
Note: if you need your geojson feature properties by the time your receive a mouseover event from your layer, just keep them in your layer object in onEachFeature callback
layer.properties = feature.properties;
Check out this JSFiddle where color is defined in the geojson properties