Can't get featureLayer.setStyle to remove highlight on mouseout (mapbox/leaflet) - javascript

So, I'm building a map of water taking permits in Toronto. Work in progress available here: http://pennybeames.net/maps/PermitsTO.html
I'm using L.mapbox.featureLayer to add my markers:
var permitsLayer = L.mapbox.featureLayer(permits, {
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, permitsStyle(feature));}
}).addTo(map);
I've got the custom info control from the Leaflet choropleth example working (http://leafletjs.com/examples/choropleth.html).
I change the style and update the info in the custom control as follows:
featureLayer.eachLayer(function (layer) {
layer.on('mousemove', function (e) {
// highlight feature
layer.setStyle({
weight: 2,
opacity: 1,
fillOpacity: 0.9
});
//update properties in DomUtil
info.update(layer.feature.properties);
});
});
All is working smoothly until we get to mouseout. The info control updates fine (either switching to the properties of the new target or reverting to its empty state), but the style won't change. The highlight stays on.
featureLayer.eachLayer(function (layer) {
layer.on('mouseout', function (e) {
//reset style
featureLayer.setStyle(permitsStyle);
//empty properties in DomUtil
info.update();
});
});
I don't get any errors, but I also don't see any change. I've tried
featureLayer.resetStyle(e.target)
but then all I get is Uncaught TypeError: featureLayer.resetStyle is not a function.
There is probably a really simple question, but it's eluding me. Insight, hivemind?

Don't bind to your events inside the eachLayer loop, just do featureLayer.on('myevent',function(e) {e.layer.setStyle(MY_NEW_STYLE)})

Related

How can I change divIcon className on click?

I have a leaflet map with several markers on it. On click on a marker this one should get highlighted. I use divIcons and want to change the whole icon or the className of it, both would work for me. At the moment i'm just changing the class of the created div in the html tree to highlight it. This works great, but i ue a marker clusterer. Therefore the divs get created and dumped on and on again and my highlight class dissapears at each clustering.
Markers:
var markerIcon = L.divIcon({
className: 'marker--default',
html: "15",
iconAnchor: [20, 20]
});
var markerIconActive = L.divIcon({
className: 'marker--state--active',
html: "15",
iconAnchor: [20, 20]
});
Integration of Marker:
var markers = L.markerClusterGroup({});
markers.addLayer(L.marker([50.919523, 6.940621], {icon: markerIcon})).on('click', onClick);
map.addLayer(markers);
Clickevent:
function onClick(e) {
e.target.setIcon(markerIconActive);
}
Note:
It doesn't work. I get the error "e.target.setIcon is not a function". After reading the documentary it seems that there is no setIcon method for divIcons. As said it would be working for me too if just the className get changed, but i don't know how to change this one.
Documentation:
https://leafletjs.com/reference-1.4.0.html#divicon
Instead of trying to access the functions / properties via e.target.<function> use e.<function> or this.<function>:
function onClick(e) {
e.setIcon(markerIconActive);
}
alternatively, you can access it through e.layer:
function onClick(e) {
let marker = e.layer;
marker.setIcon(markerIconActive);
}
Reading Material
Is there a way to click on any map marker and retrieve the marker's lat/lng (or array index)?
If you want to change the class of your div, the native function is classList. You can use it along-side with stopPropagation to prevent the first bug you pointed out. like so
function onClick(e) {
e.stopPropagation();
e.target.classList.toggle('newclass');
}
You also can use replace method instead of toggle if you want a "switch"
function onClick(e) {
e.stopPropagation();
e.target.classList.replace('oldclass','newclass');
}
Don't forget to pass the event buble through the onClick function when you call it $.on('click', onClick(e))
markers.addLayer(L.marker([50.919523, 6.940621], {icon: markerIcon})).on('click', onClick(e));

Leaflet clicking on features

So, I'm trying to map bus routes using leaflet w/geojson for the coordinates. I'm having a difficult time with one aspect where, on a click, the bus line is boldened, and, ideally, the last clicked on feature returns to the default style.
What I have so far
function $onEachFeature(feature, layer) {
layer.on({
click: function(e) {
//calls up the feature clicked on
var $layer = e.target;
var highlightStyle = {
opacity: 1,
weight: 5
};
$layer.bringToFront();
$layer.setStyle(highlightStyle);
}
});
}
//imagine all the leaflet map tile code here
//this is where the features get added in and the $oneachfeature function
var busFeature = L.geoJson(busRoutes, {
style: defaultBusRouteColor,
onEachFeature : $onEachFeature
});
busFeature.addTo(map);
Above, what I have now successfully changes the style of the feature to what's in highlightStyle. However, when another feature is clicked, the style remains. How do I remove the previously clicked on feature's style so that only one feature at a time has the style highlightStyle?
Things I've already tried: using addClass/removeClass to jQuery methods, layer.resetStyle() with leaflet, and a bunch of other things that still didn't work. Note: this would ideally be used in a mobile version, as the desktop version uses a hover function that emphasizes the features, with no problem. this:
function $oneachfeature(feature, layer){
layer.on({
mouseover: function (e){makes feature bold}
});
layer.on({
mouseout: function (e){makes feature normal again}
});
}
Any suggestions?
Store a reference to the highlighted layer so you can later call resetStyle on it:
// Variable to store selected
var selected
// Create new geojson layer
new L.GeoJSON(collection, {
// Set default style
'style': function () {
return {
'color': 'yellow',
}
}
}).on('click', function (e) {
// Check for selected
if (selected) {
// Reset selected to default style
e.target.resetStyle(selected)
}
// Assign new selected
selected = e.layer
// Bring selected to front
selected.bringToFront()
// Style selected
selected.setStyle({
'color': 'red'
})
}).addTo(map)
Example: http://embed.plnkr.co/RnQO1s/preview
Reference: http://leafletjs.com/reference.html#geojson-resetstyle
using resetStyle() would seem to be an easier solution...simply reset the style of the layer before applying the new style to the feature. This requires only a sinlge line of code adding to your original function:
function $onEachFeature(feature, layer) {
layer.on({
click: function(e) {
//calls up the feature clicked on
var $layer = e.target;
var highlightStyle = {
opacity: 1,
weight: 5
};
busFeature.resetStyle();
$layer.bringToFront();
$layer.setStyle(highlightStyle);
}
});
}
Remove previous Highlight before adding the next:
.removeLayer() works to remove the previously set geoJSON selection using .addTo()
theMap = yourMap.Map
geoJson = yourMap.geoJSON();
onclick() {
const highlightedFeature = {
'color': '#12FF38',
'fillColor': '#30D8E0',
'fillOpacity': 0.3
};
this.theMap.removeLayer(this.geoJson);
this.geoJson = yourMap.geoJSON( Feature, {
style: highlightedFeature
});
this.geoJson.addTo(this.theMap);
}

OnClick in an angular-openlayers-directive marker

Thats it I want to create an onclick event on my marker, I'm using angular-openlayers-directive.
So far I've been able to make some markers show up, but I'm unable to get them after a click event.
I would like to perform some actions with these markers custom properties like name, remarks, etc. But it seems too hard to achieve this with openlayers 3.
<openlayers ol-center="ven" height="100vh">
<ol-layer ol-layer-properties="wms">
<ol-marker ng-repeat="marker in markers"
lat="marker.lat"
lon="marker.lon"
></ol-marker>
</ol-layer>
</openlayers>
So how could I handle an onclick event on these markers and get all their info, or a reference to the javascript object "marker" itself.
I wasn't sure if you wanted to have the click on the popover or the marker itself. Below there are instructions for both. Use the Plunker link at the bottom to see a working demo of both options.
To Register Click on Marker Popover:
If you take a look at the directive, you can see that the marker template uses ng-transclude, so you can do the following:
Markup:
<ol-marker ol-marker-properties="santiago" >
<p ng-click="showDetails(santiago)">Santiago de Compostela</p>
</ol-marker>
In your controller:
$scope.showDetails = function(id) {
alert('lat: '+ id.lat+', '+'lon: '+id.lon);
};
Here I'm passing in the marker object to the showDetails function. When you click the popover label for Santiago de Compostela in the Plunker Demo, you'll see the corresponding lat/lon in the alert.
To Register Click on the Marker:
You can add an onClick property to the marker object as follows:
In your controller:
finisterre: {
lat: 42.907800500000000000,
lon: -9.265031499999964000,
label: {
show: false,
},
onClick: function (event, properties) {
console.log(properties);
alert('lat: '+ properties.lat+', '+'lon: '+properties.lon);
}
}
When you click the marker associated with finisterre in the Plunker Demo, you'll see the corresponding lat/lon in the alert.
NOTE:
I could only get this to work though under the following conditions:
The marker object must have a label property defined
The show property of the label must be set to false.
The ol-marker html element must have some transcluded content OR the message property must be set in the marker label object.
I was able to use CSS to prevent the popover from displaying as you can see in the demo, but it seems a little hacky. If you want the popover to display on click as well, you're all set, just remove the css hidden class I added and add your pop-over html.
Plunker Demo
I just got this working today as it happens. What I am doing for now is adding the properties to my markers once I get them from mongo.
function addMarkerProperties ()
// needed to enable click events on a marker!
// Have a label property defined for the marker.
// Have the show property of the label set to false.
// Have some transcluded content in the marker.
{
for (var i = $scope.markers.length - 1; i >= 0; i--) {
$scope.markers[i].onClick = function (event, properties) { console.log('Clicked a marker'); console.log(this); console.log(properties); };
$scope.markers[i].label = {
// Note: Duplication of data here # message. Fix this later.
"message": $scope.markers[i].name,
"show": false,
"showOnMouseOver": false
};
};
}
Once the markers have all the properties they need. It just sort of works but I do have a bug to iron out as well where the marker titles repeat above the map for.... reasons.
As you click the markers the words disappear.
With the latest release (April 6 2016) of the angular-openlayers-directive library (correct) ngClick-handling seems to be implemented. After a bit of searching I came up with the following solution:
The HTML (simplified):
<html ng-controller="mapController">
<openlayers width="100%" height="400px">
<ol-marker ng-repeat="marker in markers" ol-marker-properties="marker" ng-click="showDetails(marker)"></ol-marker>
</openlayers>
</html>
The Angular Javascript for the map controller (expects that your API endpoint called '/api/markerlist' returns a list of JSON objects with the fields: 'latitude', 'longitude'):
$scope.markers = [];
$scope.initializeMarkers = function() {
var markerList = $http.get("yoursite/api/markerlist")
.succes( function(result) {
angular.forEach(result, function(value, key) {
$scope.markers.push({
lat: value.latitude,
lon: value.longitude,
label: {
message: "Your message",
show: false,
showOnMouseOver: false
}
});
});
}
function showDetails(marker) {
alert('Clicked a marker on the map');
console.log(marker);
}
Finally, be sure that you have included the angular-openlayer-directive CSS, so the messages for the labels are not visible.

Accessing a jQuery element Google Maps Listener

I am using jQuery with a Google Maps Listener. I have boxes in my map and I need to make changes on them when they are too close.
The problem is the next one:
I check if the boxes are close and then make them red (for example). I know the condition is OK because I have a "console.log" and everything is nice. Here is my code:
Little explanation:
A marker is an element in the map. Every marker has his own infobox (the boxes in the map I want to change).
A cluster is a group of markers.
clusterListener2 = google.maps.event.addListener(markerCluster, 'click', function (clusterer) {
zoomLimit=12;
var myzoom = map.getZoom();
var olderPosk=1000000;
var olderPosD=1000000;
if (myzoom>zoomLimit) {
clusterClickController=1;
$.each(clusterer.getMarkers(), (function (index, marker) {
var restak=olderPosk-marker.position.k;
var restaD=olderPosD-marker.position.D;
if (restak<0) restak=restak*(-1);
if (restaD<0) restaD=restaD*(-1);
if ((restak<0.0001)&&(restaD<0.0001)) {
console.log("Close elements");
console.log($(this.infobox));
currentInfobox=$(this.infobox);
currentInfobox.css({"background" : "red"});
}
olderPosk=marker.position.k;
olderPosD=marker.position.D;
marker.marker.open(map, this);
marker.infobox.open(map,this);
marker.marker.isHidden = false;
}));
}
else {
clusterClickController=0;
}
});
So, the "Close elements" console.log is appearing in console and the $(this.infobox) prints a jQuery element but when I do the "background red" statement it does not work.
Any help? Thanks
I think you should use infobox.content_.style.cssText to set the new style instead. As it is shown in line 44 of this jsfiddle.

How can we create an onclick event for a d3 data map?

I am building a d3 data map:
http://datamaps.github.io/
When I click on a country, I want the border to change color. How do I assign an onclick event to a d3 path using datamaps? The svg paths seem to lack a CSS ID as well as any identifying hook.
You can use JQuery "done:function" and specify on("click") as below :
done: function(datamap) {
datamap.svg.selectAll('.datamaps-subunit').on('click', function(geography) {
alert(geography.properties.name);
});
}
Refer to https://github.com/markmarkoh/datamaps for further detail.
You'll need both the done call back as well as the updateChoropleth function. For example, to turn each country black you would do:
done: function(datamap) {
datamap.svg.selectAll('.datamaps-subunit').on('click', function(geography) {
var m = {};
m[geography.id] = '#000000';
datamap.updateChoropleth(m);
});
}

Categories