Leaflet is an exciting tool for making interactive maps. It's free. It's simple. It's easy to write. It isn't tied to any one set of background tiles. It works in all the major browsers. It's under active development.
It even has good documentation. But one thing it doesn't show you how to create is hover effects. Say you've got some shapes or points on your map and you want something to happen when the user rolls her mouse over them. After getting some help from GitHubber patmisch, here's how I made it work.
Getting started
The city of Los Angeles recently redrew its City Council districts. Below is a Leaflet map displaying the boundaries from the redistricting commission's final recommendation. I downloaded the lines as a shapefile from the commission's Web site and converted them into GeoJSON format using Quantum GIS.
This kind of map can be accomplished by following the GeoJSON instructions Leaflet already provides. One hundred percent of the code is below. I've annotated it to provide some clues to what's happening, but this is the baseline for making a static map run and I'm going to assume you get how it works. If you get stuck up, fire off a question in the comments or spend some time with Leaflet's tutorial for beginners.
Leaflet GeoJSON example
Hooking up hovers
Our goal is to make the same map as above, except with polygons that light up on hover and a popup that appears with metadata about the selected council district. Something like this.
First add jQuery to the head of the page, so we can easily make the popup when the time comes.
Then create a second style set that describes how to brighten up the polygon.
var highlightStyle = {
color: '#2262CC',
weight: 3,
opacity: 0.6,
fillOpacity: 0.65,
fillColor: '#2262CC'
};
Now the real work. Look back at how we used the "featureparse" event above to assign the default style to each polygon. You can assign events in the same way, turning them on one at a time as Leaflet loops through your GeoJSON features and adds them to the layer. The only trick is to bind your events using a self-invoking function that gets the scope right and lines things up as they loop by.
Watch as it happens below. The wrapper function passes in the layer and JSON metadata, which are then assigned as the function is executed before each step of the loop is complete.
var onEachFeature = function(feature, layer) {
// Load the default style.
layer.setStyle(defaultStyle);
// Create a self-invoking function that passes in the layer
// and the properties associated with this particular record.
(function(layer, properties) {
// Create a mouseover event
layer.on("mouseover", function (e) {
// Change the style to the highlighted version
layer.setStyle(highlightStyle);
// Create a popup with a unique ID linked to this record
var popup = $("", {
id: "popup-" + properties.DISTRICT,
css: {
position: "absolute",
bottom: "85px",
left: "50px",
zIndex: 1002,
backgroundColor: "white",
padding: "8px",
border: "1px solid #ccc"
}
});
// Insert a headline into that popup
var hed = $("", {
text: "District " + properties.DISTRICT + ": " + properties.REPRESENTATIVE,
css: {fontSize: "16px", marginBottom: "3px"}
}).appendTo(popup);
// Add the popup to the map
popup.appendTo("#map");
});
// Create a mouseout event that undoes the mouseover changes
layer.on("mouseout", function (e) {
// Start by reverting the style back
layer.setStyle(defaultStyle);
// And then destroying the popup
$("#popup-" + properties.DISTRICT).remove();
});
// Close the "anonymous" wrapper function, and call it while passing
// in the variables necessary to make the events work the way we want.
})(layer, feature.properties);
};
That's it. If this doesn't make sense, or I've made a mistake, please leave a comment below. You can find the source code for the complete working demo here.