{"id":715,"date":"2015-02-03T16:13:21","date_gmt":"2015-02-03T23:13:21","guid":{"rendered":"http:\/\/homepages.uc.edu\/~yaozo\/wordpress\/?p=715"},"modified":"2015-02-03T16:13:21","modified_gmt":"2015-02-03T23:13:21","slug":"add-a-before-after-map-slider-to-a-leaflet-map","status":"publish","type":"post","link":"https:\/\/zhuoyao.net\/index.php\/2015\/02\/03\/add-a-before-after-map-slider-to-a-leaflet-map\/","title":{"rendered":"Add a before-after map slider to a Leaflet map!"},"content":{"rendered":"<div class=\"entry-content\">\n<p>The jQuery Before\/After plugin is a great interactive tool to explore changes through time. This plugin has been used to great effect by the New York Times to <a href=\"http:\/\/www.nytimes.com\/interactive\/2011\/03\/13\/world\/asia\/satellite-photos-japan-before-and-after-tsunami.html?_r=0\">show changes in Japan before and after the tsunami<\/a> that destroyed the Fukushima Daiichi Nuclear Plant. In most examples of the plugin, though, the maps are static images and the user cannot zoom or pan.<\/p>\n<p>Thanks to the work of Graham MacDonald at the Urban Institute there is a tool that allows for the combination of the Before\/After plugin with a slippy map (the kind that lets you zoom and pan). You can read <a href=\"http:\/\/datatools.metrotrends.org\/charts\/metrodata\/_Blog\/Maps\/BeforeAfter\/index.cfm\">Graham\u2019s discussion<\/a> but we will provide a walk-through of the code in this post. By the way, the Urban Institute has a very nice implementation of the functionality in their <a href=\"http:\/\/datatools.metrotrends.org\/charts\/metrodata\/_Blog\/Maps\/PovertyRace_DW\/Map.html\">Poverty and Race in America map<\/a>.<\/p>\n<h2>1. Set up your dependencies.<\/h2>\n<p><strong>CSS<\/strong> \u2013 In addition to the Leaflet CSS we\u2019re including Bootstrap as well as CSS that will allow us to use <a href=\"http:\/\/getbootstrap.com\/components\/\">Bootstrap glyphicons<\/a> thanks to Lennard Voogdt and <a href=\"https:\/\/github.com\/lvoogdt\/Leaflet.awesome-markers\">this project<\/a>.<\/p>\n<pre><code class=\" hljs xml\">\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-title\">link<\/span> <span class=\"hljs-attribute\">href<\/span>=<span class=\"hljs-value\">\"\/\/netdna.bootstrapcdn.com\/bootstrap\/3.1.1\/css\/bootstrap.min.css\"<\/span> <span class=\"hljs-attribute\">rel<\/span>=<span class=\"hljs-value\">\"stylesheet\"<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-title\">link<\/span> <span class=\"hljs-attribute\">rel<\/span>=<span class=\"hljs-value\">\"stylesheet\"<\/span> <span class=\"hljs-attribute\">type<\/span>=<span class=\"hljs-value\">\"text\/css\"<\/span> <span class=\"hljs-attribute\">href<\/span>=<span class=\"hljs-value\">\"http:\/\/cdn.leafletjs.com\/leaflet-0.7.3\/leaflet.css\"<\/span> \/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-title\">link<\/span> <span class=\"hljs-attribute\">rel<\/span>=<span class=\"hljs-value\">\"stylesheet\"<\/span> <span class=\"hljs-attribute\">href<\/span>=<span class=\"hljs-value\">\"css\/leaflet.awesome-markers.css\"<\/span>&gt;<\/span>\n<\/code><\/pre>\n<p><code><\/code><strong>JS<\/strong> &#8211; jQuery, jQuery-ui, code that allows users on touch devices to use the map and the code from Graham that creates the map (the map creation function is in<code>jquery.beforeafter-map-0.11.js<\/code>).<\/p>\n<pre><code class=\" hljs xml\">\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-title\">script<\/span> <span class=\"hljs-attribute\">type<\/span>=<span class=\"hljs-value\">\"text\/javascript\"<\/span> <span class=\"hljs-attribute\">src<\/span>=<span class=\"hljs-value\">\"http:\/\/code.jquery.com\/jquery-2.1.1.min.js\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-title\">script<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-title\">script<\/span> <span class=\"hljs-attribute\">type<\/span>=<span class=\"hljs-value\">\"text\/javascript\"<\/span> <span class=\"hljs-attribute\">src<\/span>=<span class=\"hljs-value\">\"http:\/\/code.jquery.com\/ui\/1.11.0\/jquery-ui.min.js\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-title\">script<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-title\">script<\/span> <span class=\"hljs-attribute\">type<\/span>=<span class=\"hljs-value\">\"text\/javascript\"<\/span> <span class=\"hljs-attribute\">src<\/span>=<span class=\"hljs-value\">\"js\/jquery.ui.touch-punch.min.js\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-title\">script<\/span>&gt;<\/span> \n<span class=\"hljs-tag\">&lt;<span class=\"hljs-title\">script<\/span> <span class=\"hljs-attribute\">src<\/span>=<span class=\"hljs-value\">\"\/\/netdna.bootstrapcdn.com\/bootstrap\/3.1.1\/js\/bootstrap.min.js\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-title\">script<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-title\">script<\/span> <span class=\"hljs-attribute\">type<\/span>=<span class=\"hljs-value\">\"text\/javascript\"<\/span> <span class=\"hljs-attribute\">src<\/span>=<span class=\"hljs-value\">\"js\/jquery.beforeafter-map-0.11.js\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-title\">script<\/span>&gt;<\/span>\n<\/code><\/pre>\n<p><code><\/code><strong>HTML<\/strong> &#8211; create an overall div and a div that holds the <em>before<\/em> and <em>after<\/em> map instances (note that the ID for these is <code>before<\/code> and <code>after<\/code>, respectively).<\/p>\n<pre><code class=\" hljs xml\">   <span class=\"hljs-tag\">&lt;<span class=\"hljs-title\">div<\/span> <span class=\"hljs-attribute\">id<\/span>=<span class=\"hljs-value\">\"map-container\"<\/span>&gt;<\/span>\n        <span class=\"hljs-comment\">&lt;!-- Make sure to give the map divs height and width \n         I do it with the map class --&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-title\">div<\/span> <span class=\"hljs-attribute\">id<\/span>=<span class=\"hljs-value\">\"before\"<\/span> <span class=\"hljs-attribute\">class<\/span>=<span class=\"hljs-value\">\"map\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-title\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-title\">div<\/span> <span class=\"hljs-attribute\">id<\/span>=<span class=\"hljs-value\">\"after\"<\/span> <span class=\"hljs-attribute\">class<\/span>=<span class=\"hljs-value\">\"map\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-title\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-title\">div<\/span>&gt;<\/span>\n<\/code><\/pre>\n<p><code><\/code><\/p>\n<h2>2. Create the Leaflet maps<\/h2>\n<p>Set up the maps:<\/p>\n<pre><code class=\" hljs javascript\">    <span class=\"hljs-keyword\">var<\/span> center = [<span class=\"hljs-number\">38.895<\/span>, -<span class=\"hljs-number\">77.020<\/span>];\n        <span class=\"hljs-keyword\">var<\/span> zoom = <span class=\"hljs-number\">12<\/span>;\n        <span class=\"hljs-keyword\">var<\/span> before = L.map(<span class=\"hljs-string\">'before'<\/span>, {\n                attributionControl: <span class=\"hljs-literal\">false<\/span>,\n                inertia: <span class=\"hljs-literal\">false<\/span>,\n                minZoom: <span class=\"hljs-number\">12<\/span>\n            }).setView(center, zoom);\n            \n        <span class=\"hljs-keyword\">var<\/span> after = L.map(<span class=\"hljs-string\">'after'<\/span>, {\n                inertia: <span class=\"hljs-literal\">false<\/span>,\n                minZoom: <span class=\"hljs-number\">12<\/span>\n            }).setView(center, zoom);\n<\/code><\/pre>\n<p><code><\/code>Populate them with layers. In this case I&#8217;m using a MapBox TileLayer that we edited a bit:<\/p>\n<pre><code class=\" hljs javascript\">    L.tileLayer(<span class=\"hljs-string\">'http:\/\/{s}.tiles.mapbox.com\/v3\/spatial.map-qgihrqg5\/{z}\/{x}\/{y}.png'<\/span>).addTo(before); <span class=\"hljs-comment\">\/\/ <\/span>\n    L.tileLayer(<span class=\"hljs-string\">'http:\/\/{s}.tiles.mapbox.com\/v3\/spatial.map-qgihrqg5\/{z}\/{x}\/{y}.png'<\/span>).addTo(after); <span class=\"hljs-comment\">\/\/ <\/span>\n<\/code><\/pre>\n<p><code><\/code><\/p>\n<h2>3. Add features to the map<\/h2>\n<p>We will also add some before\/after features. Red will be before and blue will be after. Note that if you wanted to simply add a traditional Leaflet marker you would use:<\/p>\n<pre><code class=\" hljs css\"> <span class=\"hljs-tag\">L<\/span><span class=\"hljs-class\">.marker<\/span>(<span class=\"hljs-attr_selector\">[38.895, -77.060]<\/span>)<span class=\"hljs-class\">.addTo<\/span>(<span class=\"hljs-tag\">before<\/span>);\n<\/code><\/pre>\n<p><code><\/code>but we wanted to use colored markers and Bootstrap glyphicons. Perhaps drink before and relax with music after?<\/p>\n<pre><code class=\" hljs php\">    <span class=\"hljs-comment\">#BEFORE (red)    <\/span>\n    <span class=\"hljs-keyword\">var<\/span> circle = L.circle([<span class=\"hljs-number\">38.895<\/span>, -<span class=\"hljs-number\">77.020<\/span>], <span class=\"hljs-number\">2000<\/span>, {\n        color: <span class=\"hljs-string\">'red'<\/span>,\n        fillColor: <span class=\"hljs-string\">'red'<\/span>,\n        fillOpacity: <span class=\"hljs-number\">0.5<\/span>\n    }).addTo(before);\n\n    L.marker([<span class=\"hljs-number\">38.895<\/span>, -<span class=\"hljs-number\">77.060<\/span>], {icon: L.AwesomeMarkers.icon({icon: <span class=\"hljs-string\">'glass'<\/span>,  prefix: <span class=\"hljs-string\">'glyphicon'<\/span>,markerColor: <span class=\"hljs-string\">'red'<\/span>}) }).addTo(before);\n    L.marker([<span class=\"hljs-number\">38.895<\/span>, -<span class=\"hljs-number\">77.050<\/span>], {icon: L.AwesomeMarkers.icon({icon: <span class=\"hljs-string\">'glass'<\/span>,  prefix: <span class=\"hljs-string\">'glyphicon'<\/span>,markerColor: <span class=\"hljs-string\">'red'<\/span>}) }).addTo(before);\n    L.marker([<span class=\"hljs-number\">38.895<\/span>, -<span class=\"hljs-number\">77.040<\/span>], {icon: L.AwesomeMarkers.icon({icon: <span class=\"hljs-string\">'glass'<\/span>,  prefix: <span class=\"hljs-string\">'glyphicon'<\/span>,markerColor: <span class=\"hljs-string\">'red'<\/span>}) }).addTo(before);\n\n    <span class=\"hljs-comment\">#AFTER (blue)<\/span>\n    <span class=\"hljs-keyword\">var<\/span> circle = L.circle([<span class=\"hljs-number\">38.895<\/span>, -<span class=\"hljs-number\">77.020<\/span>], <span class=\"hljs-number\">2000<\/span>, {\n        color: <span class=\"hljs-string\">'blue'<\/span>,\n        fillColor: <span class=\"hljs-string\">'blue'<\/span>,\n        fillOpacity: <span class=\"hljs-number\">0.5<\/span>\n    }).addTo(after);\n\n    L.marker([<span class=\"hljs-number\">38.905<\/span>, -<span class=\"hljs-number\">77.010<\/span>], {icon: L.AwesomeMarkers.icon({icon: <span class=\"hljs-string\">'headphones'<\/span>,  prefix: <span class=\"hljs-string\">'glyphicon'<\/span>,markerColor: <span class=\"hljs-string\">'blue'<\/span>}) }).addTo(after);\n    L.marker([<span class=\"hljs-number\">38.915<\/span>, -<span class=\"hljs-number\">77.000<\/span>], {icon: L.AwesomeMarkers.icon({icon: <span class=\"hljs-string\">'headphones'<\/span>,  prefix: <span class=\"hljs-string\">'glyphicon'<\/span>,markerColor: <span class=\"hljs-string\">'blue'<\/span>}) }).addTo(after);\n    L.marker([<span class=\"hljs-number\">38.925<\/span>, -<span class=\"hljs-number\">76.990<\/span>], {icon: L.AwesomeMarkers.icon({icon: <span class=\"hljs-string\">'headphones'<\/span>,  prefix: <span class=\"hljs-string\">'glyphicon'<\/span>,markerColor: <span class=\"hljs-string\">'blue'<\/span>}) }).addTo(after);\n<\/code><\/pre>\n<p><code><\/code><\/p>\n<h2>4. Use the <code>beforeAfter<\/code> function to create the final maps and slider<\/h2>\n<p>The <code>beforeAfter<\/code> function is in the <code>jquery.beforeafter-map-0.11.js<\/code> file created by Graham MacDonald.<\/p>\n<pre><code class=\" hljs javascript\">$(<span class=\"hljs-string\">'#map-container'<\/span>).beforeAfter(before, after);\n<\/code><\/pre>\n<p><code><\/code><\/p>\n<h2>5. Play with your map<\/h2>\n<p><iframe loading=\"lazy\" width=\"650px\" height=\"450px\" src=\"http:\/\/www.zevross.com\/bloghelpers\/mapslider\/index.html\" frameborder=\"0\"><\/iframe><\/p>\n<\/div>\n<footer class=\"entry-meta entry-footer\"><span class=\"cat-links\">Posted in <a title=\"View all posts in LeafletJS\" href=\"http:\/\/zevross.com\/blog\/category\/leafletjs\/\" rel=\"category tag\">LeafletJS<\/a>, <a title=\"View all posts in Web Mapping\" href=\"http:\/\/zevross.com\/blog\/category\/web-mapping\/\" rel=\"category tag\">Web Mapping<\/a><\/span><\/footer>\n","protected":false},"excerpt":{"rendered":"<p>The jQuery Before\/After plugin is a great interactive tool to explore changes through time. This plugin has been used to great effect by the New&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20],"tags":[],"class_list":["post-715","post","type-post","status-publish","format-standard","hentry","category-r"],"_links":{"self":[{"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/posts\/715","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/comments?post=715"}],"version-history":[{"count":0,"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/posts\/715\/revisions"}],"wp:attachment":[{"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/media?parent=715"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/categories?post=715"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/tags?post=715"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}