Last active
January 14, 2021 23:52
-
-
Save kaz-a/ebd427d851ecb85c24ae to your computer and use it in GitHub Desktop.
NYC Daycare Finder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!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> <label for="GFDC">GFDC</label> | |
| <input type="checkbox" name="filters" onclick="showDaycares();" value="FDC" id="FDC" checked> <label for="FDC">FDC </label> | |
| <input type="checkbox" name="filters" onclick="showDaycares();" value="SACC" id="SACC" checked> <label for="SACC">SACC </label> | |
| <input type="checkbox" name="filters" onclick="showDaycares();" value="GDC" id="GDC" checked> <label for="GDC">GDC </label> | |
| <input type="checkbox" name="filters" onclick="showDaycares();" value="SBCC" id="SBCC" checked> <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" /> 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] ? '–' + 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