diff --git a/index.html b/index.html
new file mode 100644
index 0000000..a806f50
--- /dev/null
+++ b/index.html
@@ -0,0 +1,44 @@
+
+
+
+
+ Citi Bike
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/css/style.css b/static/css/style.css
new file mode 100644
index 0000000..56acbe4
--- /dev/null
+++ b/static/css/style.css
@@ -0,0 +1,7 @@
+html,
+body,
+#map-id {
+ height: 100%;
+ padding: 0;
+ margin: 0;
+}
diff --git a/static/js/leaflet.extra-markers.min.js b/static/js/leaflet.extra-markers.min.js
new file mode 100644
index 0000000..9ae8973
--- /dev/null
+++ b/static/js/leaflet.extra-markers.min.js
@@ -0,0 +1 @@
+!function(a,b){"use strict";L.ExtraMarkers={},L.ExtraMarkers.version="1.0.1",L.ExtraMarkers.Icon=L.Icon.extend({options:{iconSize:[35,45],iconAnchor:[17,42],popupAnchor:[1,-32],shadowAnchor:[10,12],shadowSize:[36,16],className:"extra-marker",prefix:"",extraClasses:"",shape:"circle",icon:"",innerHTML:"",markerColor:"red",iconColor:"#fff",number:""},initialize:function(a){a=L.Util.setOptions(this,a)},createIcon:function(){var a=b.createElement("div"),c=this.options;return c.icon&&(a.innerHTML=this._createInner()),c.innerHTML&&(a.innerHTML=c.innerHTML),c.bgPos&&(a.style.backgroundPosition=-c.bgPos.x+"px "+-c.bgPos.y+"px"),this._setIconStyles(a,c.shape+"-"+c.markerColor),a},_createInner:function(){var a="",b="",c=this.options;return c.iconColor&&(a="style='color: "+c.iconColor+"' "),c.number&&(b="number='"+c.number+"' "),""},_setIconStyles:function(a,b){var c,d,e=this.options,f=L.point(e["shadow"===b?"shadowSize":"iconSize"]);"shadow"===b?(c=L.point(e.shadowAnchor||e.iconAnchor),d="shadow"):(c=L.point(e.iconAnchor),d="icon"),!c&&f&&(c=f.divideBy(2,!0)),a.className="leaflet-marker-"+d+" extra-marker-"+b+" "+e.className,c&&(a.style.marginLeft=-c.x+"px",a.style.marginTop=-c.y+"px"),f&&(a.style.width=f.x+"px",a.style.height=f.y+"px")},createShadow:function(){var a=b.createElement("div");return this._setIconStyles(a,"shadow"),a}}),L.ExtraMarkers.icon=function(a){return new L.ExtraMarkers.Icon(a)}}(window,document);
\ No newline at end of file
diff --git a/static/js/logic (1).js b/static/js/logic (1).js
new file mode 100644
index 0000000..d617494
--- /dev/null
+++ b/static/js/logic (1).js
@@ -0,0 +1,63 @@
+// var newYorkCoords = [40.73, -74.0059];
+// var mapZoomLevel = 12;
+
+// Create the createMap function.
+function createMap(bikeStations) {
+
+
+ // Create the tile layer that will be the background of our map.
+ let streetmap = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
+ attribution: '© OpenStreetMap contributors'
+ });
+
+ // Create a baseMaps object to hold the lightmap layer.
+ let baseMaps = {
+ "Street Map": streetmap
+ };
+
+ // Create an overlayMaps object to hold the bikeStations layer.
+ let overlayMaps = {
+ "Bike Stations": bikeStations
+ };
+
+ // Create the map object with options.
+ let map = L.map("map-id", {
+ center: [40.73, -74.0059],
+ zoom: 12,
+ layers: [streetmap, bikeStations]
+ });
+
+ // Create a layer control, and pass it baseMaps and overlayMaps. Add the layer control to the map.
+ L.control.layers(baseMaps, overlayMaps, {
+ collapsed: false
+ }).addTo(map);
+
+}
+// Create the createMarkers function.
+function createMarkers(response) {
+
+ // Pull the "stations" property from response.data.
+ let stations = response.data.stations;
+
+ // Initialize an array to hold the bike markers.
+ let bikeMarkers =[];
+
+ // Loop through the stations array.
+ // For each station, create a marker, and bind a popup with the station's name.
+ for (let i = 0; i < stations.length; index++) {
+ let station = stations[index];
+
+ let bikeMarker = L.marker([station.lat, station.lon])
+ .bindPopup("" + station.name + "Capacity: " + station.capacity + "
");
+
+
+ // Add the marker to the bikeMarkers array.
+ bikeMarkers.push(bikeMarkers);
+ }
+ // Create a layer group that's made from the bike markers array, and pass it to the createMap function.
+ createMap(L.layerGroup(bikeMarkers));
+}
+let bikeurl = "https://gbfs.citibikenyc.com/gbfs/en/station_information.json";
+
+// Perform an API call to the Citi Bike API to get the station information. Call createMarkers when it completes.
+d3.json(bikeurl).then(createMarkers);
diff --git a/static/js/logic.js b/static/js/logic.js
new file mode 100644
index 0000000..790b5e3
--- /dev/null
+++ b/static/js/logic.js
@@ -0,0 +1,169 @@
+// let newYorkCoords = [40.73, -74.0059];
+// let mapZoomLevel = 12;
+
+// Create the tile layer that will be the background of our map.
+let streetmap = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
+ attribution: '© OpenStreetMap contributors'
+});
+
+// Initialize all the LayerGroups that we'll use.
+let layers = {
+ COMING_SOON: new L.LayerGroup(),
+ EMPTY: new L.LayerGroup(),
+ LOW: new L.LayerGroup(),
+ NORMAL: new L.LayerGroup(),
+ OUT_OF_ORDER: new L.LayerGroup()
+};
+
+// Create the map with our layers.
+let map = L.map("map-id", {
+ center: [40.73, -74.0059],
+ zoom: 12,
+ layers: [
+ layers.COMING_SOON,
+ layers.EMPTY,
+ layers.LOW,
+ layers.NORMAL,
+ layers.OUT_OF_ORDER
+ ]
+});
+
+// Add our "streetmap" tile layer to the map.
+streetmap.addTo(map);
+
+// Create an overlays object to add to the layer control.
+let overlays = {
+ "Coming Soon": layers.COMING_SOON,
+ "Empty Stations": layers.EMPTY,
+ "Low Stations": layers.LOW,
+ "Healthy Stations": layers.NORMAL,
+ "Out of Order": layers.OUT_OF_ORDER
+};
+
+// Create a control for our layers, and add our overlays to it.
+L.control.layers(null, overlays).addTo(map);
+
+// Create a legend to display information about our map.
+let info = L.control({
+ position: "bottomright"
+});
+
+// When the layer control is added, insert a div with the class of "legend".
+info.onAdd = function() {
+ var div = L.DomUtil.create("div", "legend");
+ return div;
+};
+// Add the info legend to the map.
+info.addTo(map);
+
+// Initialize an object that contains icons for each layer group.
+let icons = {
+ COMING_SOON: L.ExtraMarkers.icon({
+ icon: "ion-settings",
+ iconColor: "white",
+ markerColor: "yellow",
+ shape: "star"
+ }),
+ EMPTY: L.ExtraMarkers.icon({
+ icon: "ion-android-bicycle",
+ iconColor: "white",
+ markerColor: "red",
+ shape: "circle"
+ }),
+ OUT_OF_ORDER: L.ExtraMarkers.icon({
+ icon: "ion-minus-circled",
+ iconColor: "white",
+ markerColor: "blue-dark",
+ shape: "penta"
+ }),
+ LOW: L.ExtraMarkers.icon({
+ icon: "ion-android-bicycle",
+ iconColor: "white",
+ markerColor: "orange",
+ shape: "circle"
+ }),
+ NORMAL: L.ExtraMarkers.icon({
+ icon: "ion-android-bicycle",
+ iconColor: "white",
+ markerColor: "green",
+ shape: "circle"
+ })
+};
+
+// Perform an API call to the Citi Bike station information endpoint.
+d3.json("https://gbfs.citibikenyc.com/gbfs/en/station_information.json").then(function(infoRes) {
+
+ // When the first API call completes, perform another call to the Citi Bike station status endpoint.
+ d3.json("https://gbfs.citibikenyc.com/gbfs/en/station_status.json").then(function(statusRes) {
+ let updatedAt = infoRes.last_updated;
+ let stationStatus = statusRes.data.stations;
+ let stationInfo = infoRes.data.stations;
+
+ // Create an object to keep the number of markers in each layer.
+ let stationCount = {
+ COMING_SOON: 0,
+ EMPTY: 0,
+ LOW: 0,
+ NORMAL: 0,
+ OUT_OF_ORDER: 0
+ };
+
+ // Initialize stationStatusCode, which will be used as a key to access the appropriate layers, icons, and station count for the layer group.
+ let stationStatusCode;
+
+ // Loop through the stations (they're the same size and have partially matching data).
+ for (let i = 0; i < stationInfo.length; i++) {
+
+ // Create a new station object with properties of both station objects.
+ let station = Object.assign({}, stationInfo[i], stationStatus[i]);
+ // If a station is listed but not installed, it's coming soon.
+ if (!station.is_installed) {
+ stationStatusCode = "COMING_SOON";
+ }
+ // If a station has no available bikes, it's empty.
+ else if (!station.num_bikes_available) {
+ stationStatusCode = "EMPTY";
+ }
+ // If a station is installed but isn't renting, it's out of order.
+ else if (station.is_installed && !station.is_renting) {
+ stationStatusCode = "OUT_OF_ORDER";
+ }
+ // If a station has less than five bikes, it's status is low.
+ else if (station.num_bikes_available < 5) {
+ stationStatusCode = "LOW";
+ }
+ // Otherwise, the station is normal.
+ else {
+ stationStatusCode = "NORMAL";
+ }
+
+ // Update the station count.
+ stationCount[stationStatusCode]++;
+ // Create a new marker with the appropriate icon and coordinates.
+ let newMarker = L.marker([station.lat, station.lon], {
+ icon: icons[stationStatusCode]
+ });
+
+ // Add the new marker to the appropriate layer.
+ newMarker.addTo(layers[stationStatusCode]);
+
+ // Bind a popup to the marker that will display on being clicked. This will be rendered as HTML.
+ newMarker.bindPopup(station.name + "
Capacity: " + station.capacity + "
" + station.num_bikes_available + " Bikes Available");
+ }
+
+ // Call the updateLegend function, which will update the legend!
+ updateLegend(updatedAt, stationCount);
+ });
+});
+
+// Update the legend's innerHTML with the last updated time and station count.
+function updateLegend(time, stationCount) {
+ document.querySelector(".legend").innerHTML = [
+ "
Updated: " + moment.unix(time).format("h:mm:ss A") + "
",
+ "Out of Order Stations: " + stationCount.OUT_OF_ORDER + "
",
+ "Stations Coming Soon: " + stationCount.COMING_SOON + "
",
+ "Empty Stations: " + stationCount.EMPTY + "
",
+ "Low Stations: " + stationCount.LOW + "
",
+ "Healthy Stations: " + stationCount.NORMAL + "
"
+ ].join("");
+}
\ No newline at end of file
diff --git a/static/js/style.js b/static/js/style.js
new file mode 100644
index 0000000..8897f73
--- /dev/null
+++ b/static/js/style.js
@@ -0,0 +1,25 @@
+// Toggle Animation by Class
+
+;(function($) {
+ $(function() {
+ $('nav ul li > a:not(:only-child)').click(function(e) {
+ $(this)
+ .siblings('.nav-dropdown')
+ .slideToggle()
+ $('.nav-dropdown')
+ .not($(this).siblings())
+ .hide()
+ e.stopPropagation()
+ })
+ $('html').click(function() {
+ $('.nav-dropdown').hide()
+ })
+ // Toggle open and close nav styles on click
+ $('#nav-toggle').click(function() {
+ $('nav ul').slideToggle();
+ });
+ $('#nav-toggle').on('click', function() {
+ this.classList.toggle('active')
+ })
+ })
+})(jQuery)
\ No newline at end of file