Skip to content

Instantly share code, notes, and snippets.

@kaz-a
Last active January 14, 2021 23:52
Show Gist options
  • Select an option

  • Save kaz-a/ebd427d851ecb85c24ae to your computer and use it in GitHub Desktop.

Select an option

Save kaz-a/ebd427d851ecb85c24ae to your computer and use it in GitHub Desktop.
NYC Daycare Finder
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>NYC Daycare Finder</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<link rel="stylesheet" href="https://d19vzq90twjlae.cloudfront.net/leaflet-0.7.3/leaflet.css" />
<script src='https://api.mapbox.com/mapbox.js/v2.2.3/mapbox.js'></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.js"></script>
<link href='https://api.mapbox.com/mapbox.js/v2.2.3/mapbox.css' rel='stylesheet' />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Slackey' rel='stylesheet' type='text/css'>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" integrity="sha512-K1qjQ+NcF2TYO/eI3M6v8EiNYZfA95pQumfvcVrTHtwQVDG+aHRqLi/ETn2uB+1JqwYqVG3LIvdm9lj6imS/pQ==" crossorigin="anonymous"></script>
<script src='https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v0.4.0/leaflet.markercluster.js'></script>
<link href='https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v0.4.0/MarkerCluster.css' rel='stylesheet' />
<link href='https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v0.4.0/MarkerCluster.Default.css' rel='stylesheet' />
<style>
body {
margin: 0;
padding: 0;
font-family: 'Open Sans', sans-serif;
font-size: 13px;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
.container {
position: absolute;
top: 100px;
left: 50px;
width: 450px;
background: rgba(0, 0, 0, 0.7);
}
#checkboxes {
color: white;
padding: 10px;
font-size: 16px;
}
#header {
padding: 10px;
color: white;
font-weight: 300;
font-size: 50px;
}
#dateform {
color: white;
padding: 10px;
font-size: 16px;
}
#poverty {
color: white;
padding: 10px;
font-size: 16px;
padding-bottom: 50px;
}
#submit {
border-radius: 0;
background: white;
border: 1px solid white;
margin-left: -5px;
margin-top: -1px;
}
#submit:hover {
background: black;
border: 1px solid white;
color: white;
}
#refresh:hover {
background: white;
border: 1px solid white;
color: black;
}
#refresh {
border-radius: 0;
background: black;
border: 1px solid white;
margin-left: 0;
margin-top: -1px;
color: white;
}
.dohmh {
margin-bottom: -50px;
margin-left: -30px;
}
.header-small {
color: white;
font-size: 25px;
}
.header-filter {
font-size: 18px;
}
.subhead-filter {
font-size: 12px;
}
.subtitle {
font-size: 12px;
}
.popup_header {
border-bottom: 1px solid grey;
margin: 10px 0;
}
.popup_address {
padding-top: 0px;
}
.popup_title {
margin-bottom: -15px !important;
}
label {
font-weight: 300;
}
input[type=checkbox] {
line-height: 0;
cursor: pointer;
}
input[type=checkbox]:before {
content: "";
display: inline-block;
width: 16px;
height: 16px;
background: grey;
border: 2px solid grey;
}
input[value=GFDC]:checked:before {
background: #f61900;
border: 2px solid #f61900;
}
input[value=FDC]:checked:before {
background: #faa300;
border: 2px solid #faa300;
}
input[value=SACC]:checked:before {
background: #74bc00;
border: 2px solid #74bc00;
}
input[value=GDC]:checked:before {
background: #2b8d4c;
border: 2px solid #2b8d4c;
}
input[value=SBCC]:checked:before {
background: #45cae6;
border: 2px solid #45cae6;
}
input[value=povertyData]:checked:before {
background: white;
border: 2px solid white;
}
input[type=checkbox]:checked:before {
width: 16px;
height: 16px;
}
.form-control {
width: 60%;
background-color: rgba(0, 0, 0, 0);
border: 0px solid #000;
border: 1px solid white;
color: white;
display: inline-block;
border-radius: 0;
}
.dateEntry {
font-size: 12px;
}
.leaflet-container p {
font-size: 12px;
line-height: 16px;
margin: 0;
}
.leaflet-popup-content {
font-family: "Open Sans", sans-serif;
}
.leaflet-popup-content p {
margin: 0;
}
.leaflet-popup-content-wrapper, .map-legends, .map-tooltip {
border-radius: 8px;
}
.marker-cluster-large {
background-color: rgba(111, 47, 114, 0.6);
}
.marker-cluster-large div {
background-color: rgba(111, 47, 114, 0.6);
}
.marker-cluster-medium {
background-color: rgba(165, 88, 158, 0.6);
}
.marker-cluster-medium div {
background-color: rgba(165, 88, 158, 0.6);
}
.marker-cluster-small {
background-color: rgba(216, 156, 213, 0.6);
}
.marker-cluster-small div {
background-color: rgba(216, 156, 213, 0.6);
}
.marker-cluster div {
font-family: 'Open Sans', sans-serif;
font-size: 13px;
color: white;
}
.legend {
line-height: 18px;
color: white;
padding: 10px;
font-family: 'Open Sans', sans-serif;
font-weight: 300;
}
.legend i {
width: 18px;
height: 18px;
float: left;
margin-right: 8px;
opacity: 0.7;
}
</style>
</head>
<body>
<div id="map"></div>
<div class="container">
<div id="header">
<img class="dohmh" src="https://raw.githubusercontent.com/Kaz-A/daycare_finder/master/images/dohmh_logo.png" height="140" /><br />DAYCARE FINDER<br />
<p class="subtitle">
Welcome to the NYC Daycare Finder! This app lets you visualize the locations of all City and State registered daycare facilities,
and filter them by modality and/or last inspection date. It may take a second or two for the initial data to load, so please be patient!
</p>
</div>
<form id="checkboxes">
<p class="header-filter">Filter Data by Modality <br /></p>
<p class="subtitle">Click/unclick the boxes to filter for the daycare modality type. </p>
<div>
<input type="checkbox" name="filters" onclick="showDaycares();" value="GFDC" id="GFDC" checked> &nbsp; <label for="GFDC">GFDC</label> &nbsp;&nbsp;
<input type="checkbox" name="filters" onclick="showDaycares();" value="FDC" id="FDC" checked> &nbsp; <label for="FDC">FDC </label> &nbsp;&nbsp;
<input type="checkbox" name="filters" onclick="showDaycares();" value="SACC" id="SACC" checked> &nbsp; <label for="SACC">SACC </label> &nbsp;&nbsp;
<input type="checkbox" name="filters" onclick="showDaycares();" value="GDC" id="GDC" checked> &nbsp; <label for="GDC">GDC </label> &nbsp;&nbsp;
<input type="checkbox" name="filters" onclick="showDaycares();" value="SBCC" id="SBCC" checked> &nbsp; <label for="SBCC">SBCC </label>
</div>
</form>
<div id="dateform">
<p class="header-filter">Filter Data by Date <br /></p>
<p class="subtitle">Enter date into the box to display all daycares that were inspected on and prior to that date. </p>
<div class="date-entry">
<input type="text" id="userInput" class="form-control" placeholder="mm/dd/yyyy" />
<button id="submit" class="btn btn-default" style="display: inline-block;">></button>
<button id="refresh" class="btn btn-default">CLEAR</button>
</div>
<div>
<span class="dateEntry"></span>
</div>
</div>
<div id="poverty">
<input type="checkbox" class="checkbox-primary" value="povertyData" /> &nbsp; Show Poverty Data
</div>
</div>
<script>
L.mapbox.accessToken = "pk.eyJ1IjoiemFrc2Nsb3NldCIsImEiOiJjaWY2dWxkc2gwcXBjczVtM3pnc3hydnI1In0.ABQHwIrVx95WhAVv_2JPeA";
var map = L.mapbox.map("map")
.setView([40.71, -74.00], 11)
.addLayer(L.mapbox.tileLayer("mapbox://styles/mapbox/decimal"));
var overlays = L.layerGroup().addTo(map);
var layers;
var featureLayer = L.mapbox.featureLayer().addTo(map);
// marker specs
var markerSize = "small";
var gfdc = "#f61900",
fdc = "#faa300",
sacc = "#74bc00",
gdc = "#2b8d4c",
sbcc = "#45cae6";
var gfdcIcon = L.mapbox.marker.icon({ "marker-size": markerSize, "marker-color": gfdc }),
fdcIcon = L.mapbox.marker.icon({ "marker-size": markerSize, "marker-color": fdc }),
saccIcon = L.mapbox.marker.icon({ "marker-size": markerSize, "marker-color": sacc }),
gdcIcon = L.mapbox.marker.icon({ "marker-size": markerSize, "marker-color": gdc }),
sbccIcon = L.mapbox.marker.icon({ "marker-size": markerSize, "marker-color": sbcc });
var daycareData = L.mapbox.featureLayer("https://raw.githubusercontent.com/Kaz-A/daycare_finder/master/childcare.geojson");
daycareData.on('ready', function (e) {
layers = e.target;
this.eachLayer(function (marker) {
if (marker.toGeoJSON().properties.Modality === "GFDC") {
marker.setIcon(gfdcIcon);
} else if (marker.toGeoJSON().properties.Modality === "FDC") {
marker.setIcon(fdcIcon);
} else if (marker.toGeoJSON().properties.Modality === "SACC") {
marker.setIcon(saccIcon);
} else if (marker.toGeoJSON().properties.Modality === "GDC") {
marker.setIcon(gdcIcon);
} else if (marker.toGeoJSON().properties.Modality === "SBCC") {
marker.setIcon(sbccIcon);
} else {
marker.setIcon(L.mapbox.marker.icon({}));
}
})
showDaycares();
});
var modalityFilters = $("#checkboxes")[0].filters;
$("#submit").click(function () {
var input = $("#userInput").val();
$(".dateEntry").html("<br />Showing all daycare facilities inspected on and before <span class = 'dateInput'>" + input + "</span><br />");
showDaycares();
});
$("#refresh").click(function () {
$("#userInput").val("mm/dd/yyyy")
$(".dateEntry").html("");
showDaycares();
});
function showDaycares() {
var input = $("#userInput").val();
var parsed_input = Date.parse(input);
// collect all of the checked boxes and create an array called modalityList (eg. ['GFDC', 'FDC'])
var modalityList = [];
for (var i = 0; i < modalityFilters.length; i++) {
if (modalityFilters[i].checked) {
modalityList.push(modalityFilters[i].value);
}
};
// remove any previously-displayed marker groups
overlays.clearLayers();
// create a new marker group
var modalityClusterGroup = new L.MarkerClusterGroup({
disableClusteringAtZoom: 15
}).addTo(overlays);
// add any markers that fit the filtered criteria to that group
layers.eachLayer(function (modalityLayer) {
var dateFormat = Date.parse(modalityLayer.feature.properties.last_inspectiondate);
var satisfiesModalityFilter = modalityList.indexOf(modalityLayer.feature.properties.Modality) !== -1;
// Only enforce date filter if parsed_input is defined (i.e. user didn't clear it)
var satisfiesDateFilter = isNaN(parsed_input) || dateFormat <= parsed_input;
// Only add layer if it satiesfies
if (satisfiesModalityFilter && satisfiesDateFilter) {
modalityClusterGroup.addLayer(modalityLayer);
};
// popup
var popupContent = "<h4 class='popup_title'>" + modalityLayer.feature.properties.CENTER_NAME +
"</h4><br />" + "<p>" + modalityLayer.feature.properties.ADDRESS +
"</p><br /><hr class='popup_header' /><p>Permit: " + modalityLayer.feature.properties.permit +
"<br />Status: " + modalityLayer.feature.properties.STATUS +
"<br />Modality: " + modalityLayer.feature.properties.Modality +
"<br />Risk Level = " + modalityLayer.feature.properties.risklevel +
"<br />Last Inspection: " + modalityLayer.feature.properties.last_inspectiondate +
"<br /><span class='popup_dsource'>Data by " + modalityLayer.feature.properties.CityVState + "</span></p>";
modalityLayer.bindPopup(popupContent);
});
};
// set the poverty shades
function getColor(d) {
return d > 30 ? "#0868ac" :
d > 20 ? "#43a2ca" :
d > 10 ? "#7bccc4" :
d > 0 ? "#a8ddb5" : "grey";
};
// load poverty data
var povertyData = "https://raw.githubusercontent.com/Kaz-A/daycare_finder/master/poverty.geojson";
var legend = L.control({ position: "bottomright" });
// poverty legend
legend.onAdd = function (map) {
var div = L.DomUtil.create("div", "info legend"),
povertyLevel = [0, 10, 20, 30],
labels = [];
// loop through intervals and generate a label with a colored square for each interval
for (var i = 0; i < povertyLevel.length; i++) {
div.innerHTML +=
'<i style="background:' + getColor(povertyLevel[i] + 1) + '"></i> ' +
povertyLevel[i] + (povertyLevel[i + 1] ? '&ndash;' + povertyLevel[i + 1] + '%<br>' : '%+');
}
return div;
};
// legend.addTo(map);
$.getJSON(povertyData, function (povertyData) {
//get unique poverty % values
var povertyFeatures = povertyData.features;
var uniquePoverty = [];
povertyFeatures.forEach(function (x) {
if (!povertyFeatures[x.properties.PopInPover]) {
uniquePoverty.push(x.properties.PopInPover);
povertyFeatures[x.properties.Poverty] = true;
}
});
// styling the choropleth
function style(feature) {
return {
fillColor: getColor(feature.properties.PopInPover),
weight: 1,
opacity: 0.3,
color: "#000",
dashArray: "1",
fillOpacity: 0.3
};
};
// add poverty data
var addPovertyData = L.geoJson(povertyData, { style: style });
// checkbox event to overlay poverty data
$(".checkbox-primary").click(function () {
if (this.checked) {
addPovertyData.addTo(map);
legend.addTo(map);
} else {
map.removeLayer(addPovertyData);
map.removeControl(legend);
};
});
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment