Skip to content

Instantly share code, notes, and snippets.

@gmculp
Last active July 11, 2017 16:48
Show Gist options
  • Save gmculp/5897b1ac22eb4a0d122d to your computer and use it in GitHub Desktop.
Save gmculp/5897b1ac22eb4a0d122d to your computer and use it in GitHub Desktop.
Leaflet Map of Brooklyn 311 Food Poisoning Complaints
<!DOCTYPE html>
<html>
<head>
<title>Leaflet Example</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!--<link rel="stylesheet" href="http://npmcdn.com/leaflet@0.7.7/dist/leaflet.css" /> -->
<link rel="stylesheet" href="http://npmcdn.com/leaflet@1.1.0/dist/leaflet.css" /> <!--necessary for using Leaflet-->
<link rel="stylesheet" href="http://leaflet.github.io/Leaflet.markercluster/dist/MarkerCluster.css" /> <!--necessary for marker cluster plugin-->
<link rel="stylesheet" href="marker_styles.css" /> <!--for markers-->
<!--<link href="http://netdna.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.css" rel="stylesheet">-->
<!--<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">-->
<!--necessary for using FontAwesome-->
<link rel="stylesheet" href="https://unpkg.com/font-awesome-base64"/>
<style>
html, body { height: 100%; width: 100%; margin: 0; }
#map {
height: 100%;
width: 100%;
}
.info {
padding: 8px 18px;
background: white;
background: rgba(255,255,255,0.9);
box-shadow: 0 0 15px rgba(0,0,0,0.2);
border-radius: 5px;
}
.info h4, .info h3, .info h2 {
margin: 0px;
}
.lame {
margin-right: 8px;
vertical-align: middle;
display: inline-block;
}
.legend {
font: 14px/16px Arial, Helvetica, sans-serif;
}
</style>
</head>
<body>
<div id="map"></div>
<!--<script src="https://npmcdn.com/leaflet@0.7.7/dist/leaflet.js"></script> -->
<script src="http://npmcdn.com/leaflet@1.1.0/dist/leaflet.js"></script> <!--necessary for using Leaflet-->
<!--<script src='http://rawgit.com/leaflet-extras/leaflet-providers/master/leaflet-providers.js' type='text/javascript'></script> -->
<!--<script src='https://leaflet-extras.github.io/leaflet-providers/leaflet-providers.js' type='text/javascript'></script> -->
<!--necessary for using Leaflet providers base maps-->
<!--<script src='https://rawgithub.com/leaflet-extras/leaflet-providers/gh-pages/leaflet-providers.js' type='text/javascript'></script> necessary for using Leaflet providers base maps-->
<script src="http://maps.stamen.com/js/tile.stamen.js?v1.2.1"></script>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<!--<script src="https://rawgit.com/Leaflet/Leaflet.markercluster/leaflet-0.7/dist/leaflet.markercluster.js"></script> -->
<script src="http://leaflet.github.io/Leaflet.markercluster/dist/leaflet.markercluster-src.js"></script> <!--necessary for marker cluster plugin-->
<script>
var zoom = 12; //set zoom level here
var center = [40.658528, -73.952551]; //set center coordinates here [latitude, longitude]
var map = L.map('map').setView(center, zoom);
//DECLARING BASE MAP... check out available base maps here: http://leaflet-extras.github.io/leaflet-providers/preview/
//var provider_name = "Stamen.Toner"; //enter provider name here
//L.tileLayer.provider(provider_name).addTo(map); //apply title layer
var watercolor = new L.StamenTileLayer("toner").addTo(map);
map.attributionControl.setPrefix('311 Complaints via NYC OpenData'); //add data source to map's attribute text
var complaint_boro = "Brooklyn"; //enter target borough here
var complaint_type = "Food Poisoning"; //enter complaint type here
var cat_field = "location_type"; //category field... either descriptor or location_type
//set-up dates for complaints placed within past 6 days
var start_date = new Date();
//start_date.setDate(start_date.getDate()-6);
start_date.setYear(start_date.getFullYear()-1);
var end_date = new Date();
//var the_URL = "http://data.cityofnewyork.us/resource/erm2-nwe9.json"; //API Access Endpoint
var the_URL = "https://data.cityofnewyork.us/resource/fhrw-4uyv.json"; //new API Access Endpoint
the_URL += "?"; //a query parameter name is preceded by the question mark
the_URL += "$where="; //Filters the rows to be returned
the_URL += "(latitude IS NOT NULL)"; //only return records with coordinates
the_URL += " AND ";
the_URL += "(borough='" + complaint_boro.toUpperCase() + "')"; //borough of interest
the_URL += " AND ";
the_URL += "(complaint_type='" + complaint_type + "')"; //desired two complaint types nested within parentheses
the_URL += " AND ";
the_URL += "(created_date>='" + f_date(start_date, 'y_mm_dd') + "') AND (created_date<='" + f_date(end_date, 'y_mm_dd') + "')"; //date range
the_URL += "&$group=complaint_type,location_type,incident_address,borough,incident_zip,latitude,longitude"; //fields to group by
the_URL += "&$select=complaint_type,location_type,incident_address,borough,incident_zip,latitude,longitude,count(*)"; //fields to return
//the_URL += "&callback=?"
the_URL = encodeURI(the_URL); //encode special characters such as spaces and quotes
//var xhr = new XMLHttpRequest({mozSystem: true});
console.log("test");
$.getJSON(the_URL, function (json) {
// console.log("test2");
//});
//$.ajax({
// url: the_URL,
// type: "GET",
//jsonp: "$jsonp",
// dataType: "jsonp"
//}).done(function(json) {
// console.log(json[0].toSource());
//create distinct array of all location types
var marker_array = [];
var desc_array = $.distinct($.map( json, function( d, i ) { return d[cat_field]; }));
//create symbols object
//assign Font Awesome icon classes... see http://fortawesome.github.io/Font-Awesome/icons/
//assign marker style via class... see markers.css
var symbols = {};
symbols["Cafeteria - College/University"]={icon:"fa-university",color:"my_marker0"};
symbols["Cafeteria - Private School"]={icon:"fa-bell-o",color:"my_marker0"};
symbols["Cafeteria - Public School"]={icon:"fa-bell",color:"my_marker0"};
symbols["Catering Service"]={icon:"fa-male",color:"my_marker0"};
symbols["Correctional Facility - City"]={icon:"fa-building-o",color:"my_marker0"};
symbols["Food Cart Vendor"]={icon:"fa-truck",color:"my_marker0"};
symbols["Other (Explain Below)"]={icon:"fa-asterisk",color:"my_marker0"};
symbols["Restaurant/Bar/Deli/Bakery"]={icon:"fa-cutlery",color:"my_marker0"};
symbols["Soup Kitchen"]={icon:"fa-users",color:"my_marker0"};
symbols["Senior Center"]={icon:"fa-wheelchair",color:"my_marker0"};
symbols["Street Fair Vendor"]={icon:"fa-road",color:"my_marker0"};
symbols["Summer Camp"]={icon:"fa-sun-o",color:"my_marker0"};
//iterate through 311 Service Requests JSON URL
$.each(json, function(c, c_data){
var this_icon, this_color;
//assign default symbology to unknown location types
if (symbols[c_data[cat_field]]){
this_icon = symbols[c_data[cat_field]].icon;
this_color = symbols[c_data[cat_field]].color;
}
else {
this_icon = symbols[c_data["Other (Explain Below)"]].icon;
this_color = symbols[c_data["Other (Explain Below)"]].color;
}
//create symbol for each record
var my_symbol = L.divIcon({
className: 'my_marker ' + this_color, //symbol color
iconSize: null,
html: '<i class="fa ' + this_icon + '"></i>' //symbol icon
});
//create pop-up html content
var popup_html = c_data.complaint_type;
popup_html += "<br>";
popup_html += c_data.location_type;
popup_html += "<br>";
popup_html += c_data.count + " complaint(s) at this location";
popup_html += "<br>";
popup_html += c_data.incident_address;
popup_html += "<br>";
popup_html += c_data.borough + ", NY " + c_data.incident_zip;
//create marker
var mark=L.marker([c_data.latitude, c_data.longitude], {icon: my_symbol}).bindPopup(popup_html);
//add marker to array
marker_array.push(mark);
});
//add marker array to layer group... all markers will be treated as one layer
var marker = new L.layerGroup(marker_array);
//Custom radius and icon create function
var markers = L.markerClusterGroup({
iconCreateFunction: function (cluster) {
var childCount = cluster.getChildCount();
var c = ' marker-cluster-';
var sz = 40; //use for symbolizing by size
if (childCount < 10) {
c += 'small';
sz = 30; //comment out if using uniform size marker clusters
} else if (childCount < 100) {
c += 'medium';
sz = 40; //comment out if using uniform size marker clusters
} else {
c += 'large';
sz = 50; //comment out if using uniform size marker clusters
}
//create leaflet marker cluster symbol
return new L.DivIcon({ html: '<div><span>' + childCount + '</span></div>', className: 'marker-cluster' + c, iconSize: new L.Point(sz, sz) });
}
});
//add marker layer group to marker cluster group
markers.addLayer(marker);
//add marker cluster layer to map
map.addLayer(markers);
//zoom map to markers layer extent
map.fitBounds(markers.getBounds());
//add scale bare
L.control.scale().addTo(map);
//build legend
var legend = L.control({position: 'topright'}); //possible positions: topleft, bottomleft, topright, bottomright
//legend function
legend.onAdd = function (map) {
//declare legend div html
var div = L.DomUtil.create('div', 'info');
//add legend title
div.innerHTML = "<h2>" + complaint_type + "</h2>";
div.innerHTML += "<h3>311 Service Requests</h3>";
div.innerHTML += "<h4>" + f_date(start_date, '/') + " to " + f_date(end_date, '/') + "</h4>";
//iterate through symbols object
$.each(symbols, function(key, value) {
div.innerHTML += '<div>';
div.innerHTML += '<div class="lame"><div class="my_marker my_marker0"><i class="fa ' + value.icon + '"></i></div></div>';
div.innerHTML += '<div class="lame legend">' + key + '</div>';
div.innerHTML += '</div>';
});
return div;
};
//add legend to map
legend.addTo(map);
//console.log("Request received: " + json[1][cat_field]);
});
//function to return distinct function
$.extend({
distinct : function(anArray) {
var result = [];
$.each(anArray, function(i,v){ if ($.inArray(v, result) == -1) result.push(v); });
return result;
}
});
function f_date(the_date, d_style){
var dd = ('0' + the_date.getDate()).slice(-2);
var mm = ('0' + (the_date.getMonth() + 1)).slice(-2);
var y = the_date.getFullYear();
return (d_style == "y_mm_dd")? y + '-' + mm + '-' + dd: mm + '/'+ dd + '/' + y;
}
</script>
</body>
</html>
.my_marker div{
text-align: center;
font-size: 14px;
font-weight: bold;
font-family: sans-serif;
}
.my_marker {
width: 20px;
height: 20px;
border-width: 2px;
border-radius:15px;
margin-top: 0px;
margin-left: -10px;
border-style: solid;
text-align: center;
}
.my_marker0 {
fill: #FFD700;
background: #FFD700;
stroke: #444;
border-color: #444;
}
/* MARKER CLUSTER STYLE */
/*all marker cluster */
.marker-cluster {
background-clip: padding-box;
background-color: rgba(255, 238, 140, 0.6); /* change back color here*/
}
.marker-cluster div {
text-align: center;
font: bold 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
background-color: rgba(255, 215, 0, 0.7); /* change fore color here*/
}
/*small marker cluster*/
.marker-cluster-small {
border-radius: 15px;
}
.marker-cluster-small div {
width: 20px;
height: 20px;
margin-left: 5px;
margin-top: 5px;
border-radius: 10px;
}
.marker-cluster-small span {
line-height: 20px;
}
/*medium marker cluster*/
.marker-cluster-medium {
border-radius: 20px;
}
.marker-cluster-medium div {
width: 30px;
height: 30px;
margin-left: 5px;
margin-top: 5px;
border-radius: 15px;
}
.marker-cluster-medium span {
line-height: 30px;
}
/*large marker cluster*/
.marker-cluster-large {
border-radius: 30px;
}
.marker-cluster-large div {
width: 40px;
height: 40px;
margin-left: 5px;
margin-top: 5px;
border-radius: 20px;
}
.marker-cluster-large span {
line-height: 40px;
}
/* IE 6-8 fallback colors */
.leaflet-oldie .marker-cluster, .leaflet-oldie .marker-cluster div {
background-color: rgba(255, 215, 0, 1);
}
.leaflet-oldie .marker-cluster div {
background-color: rgba(255, 238, 140, 1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment