NYC Open Data, GoogleMaps and React

I first started looking into these topics when I was working on a hackathon project for school. I wanted to create an app the allowed people to find and schedule pick up basketball games in NYC. I found these technologies to be really useful for my app and I hope this guide will be useful.

Step 1: Finding Your Data From NYC Open Data

NYC Open Data is portal that houses datasets from over 80 NYC entities, such as the Parks Department, Department of Buildings and Fire Department of New York City. For my project I needed to find the location of all the outdoor basketball courts in the city. I was able to access the Directory of Basketball Courts page on the Open Data site and given the option of exporting the dataset as a JSON or XML file. The dataset contained the latitude and longitude of each basketball court. It was difficult to visualize this code so I found it very useful to create an account with Mapbox and import the dataset. The other useful thing is that the Mapbox dataset visualizer allows your to edit you GeoJSON file using the intuitive map.

You could visit the Mapbox link below to import the dataset.

What the dataset looked like in the Mapbox dataset editor.

One issue that you might run into is that the Mapbox dataset editor is only compatible with GeoJSON files. Which is a specific format for map data. Some of the datasets on the NYC Open Data are only available as JSON files, so they have to be converted to GeoJSON before they can be used with the Mapbox dataset editor. I found the conversion to be very simple with the help of some NPM modules. The conversion can by done on the terminal command line as follows:

npm install -g json2csv csv2geojson
cat fileName.json | json2csv | csv2geojson > fileName.geojson

Step 2: Creating A React Component for GoogleMaps API

In order to use the Google Maps API with your React component you will need to get an API key, see link below. https://developers.google.com/maps/documentation/javascript/get-api-key

There are many NPM modules out there that help you integrate Google Maps into React. For my project I used the ‘google-maps-react’ module. The documentation for the module was extremely useful, see link below.

You will need to make a parent component which I called App.js and a child component (HoopMaps.js in my case) that renders the map.

Parent (App) Component

The structure of my App.js component.

import React from 'react'
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import { HoopMap } from './'
/**
* COMPONENT
*/
export const UserHome = props => {
const {email} = props
return (
<div>
<h3>Welcome, {email.slice(0, email.indexOf('@'))}</h3>
<HoopMap />
</div>
)
}
/**
* CONTAINER
*/
const mapState = state => {
return {
email: state.user.email
}
}
export default connect(mapState)(UserHome)
/**
* PROP TYPES
*/
UserHome.propTypes = {
email: PropTypes.string
}

Child (HoopMaps) Component

The structure of my HoopMaps.js component.

import React, { Component } from 'react';
// import the Google Maps API Wrapper from google-maps-react
import { Map, InfoWindow, GoogleApiWrapper, Marker} from 'google-maps-react'
// import child component
import courts from '../courts'
import axios from 'axios'
import { withRouter } from "react-router-dom";

const style = {
width: '75%',
height: '75%',
}
class HoopMap extends Component {
constructor(props) {
super(props)
this.state = {
showingInfoWindow: false,
showCourtInfo: false,
activeMarker: {},
courtInfo: {},
activePlayers: 0
}
this.onMapClicked = this.onMapClicked.bind(this)
this.onInfoClick = this.onInfoClick.bind(this)
}
onMarkerClick = async (props, marker, event) => {
const res = await axios.get(`/api/courts/${props.courtId}`)
this.setState({
selectedPlace: props,
activeMarker: marker,
showingInfoWindow: true,
showCourtInfo: true,
courtInfo: res.data,
activePlayers: res.data.users.length
});
}
onInfoClick = () => {
this.props.history.push(`/courts/${this.state.courtInfo.id}`);
}
onMapClicked = (props) => {
if (this.state.showingInfoWindow) {
this.setState({
showingInfoWindow: false,
showCourtInfo: false,
activeMarker: null
})
}
};
render() {
return (
<div>
<h1> FIND A PICKUP GAME </h1>
{this.state.showingInfoWindow&&this.state.showCourtInfo?<button className="w3-button w3-red" onClick={this.onInfoClick}>Court Info</button>:null}
<Map google={this.props.google}
style={style}
onClick={this.onMapClicked}
initialCenter={{lat: 40.7485722, lng: -74.0068633}}
zoom={12}>
{
courts.map((court) => {
return <Marker position={{lat: court.geometry.coordinates[1], lng: court.geometry.coordinates[0]}} icon={{
url: "http://www.clker.com/cliparts/j/N/m/m/d/2/glossy-red-icon-button-md.png",
anchor: new google.maps.Point(10,10),
scaledSize: new google.maps.Size(10,10)
}} onClick={this.onMarkerClick} courtId={court.courtId} />
})}
<InfoWindow
marker={this.state.activeMarker}
visible={this.state.showingInfoWindow}>
<div>
<h1>{this.state.courtInfo.name}</h1>
<h3>{this.state.courtInfo.location}</h3>
<h3>Current Players: {this.state.activePlayers}</h3>
</div>
</InfoWindow>
</Map>
</div>
);
}
}
// OTHER MOST IMPORTANT: Here we are exporting the App component WITH the GoogleApiWrapper. You pass it down with an object containing your API key
export default withRouter(GoogleApiWrapper({
apiKey: 'Your_Google_Maps_API_Key',
})(HoopMap))

We are importing GoogleApiWrapper from the ‘google-maps-react’ module, wrapping the child component with it and exporting it to the parent component.

Step 3: Adding Markers

Map with markers of outdoor courts in NYC.

In order to add the markers I used the built in Marker component of the ‘google-maps-react’ module. You can export your GeoJSON data as follows:

const courtData = {
"features": [
{
"type": "Feature",
"properties": {
"Prop_ID": "B252",
"Name": "West Playground",
"Location": "N/S Ave. Z between West St. and W 1 St.",
"Num_of_Courts": "",
"Accessible": "N"
},
"geometry": {
"coordinates": [
-73.9705,
40.5876
],
"type": "Point"
},
"id": "00dd54fa521680ada5fe4750f7d7ed81"
},
...]
...}
export default courtData

Then remember to import it into your React component.

import courtData from '../courtData'

Using the built in Marker component you can simply map over the features property of the courtData object when the component is rendered.

render() {
return (
<div>
<Map google={this.props.google}
style={style}
onClick={this.onMapClicked}
initialCenter={{lat: 40.7485722, lng: -74.0068633}}
zoom={12}>
{
courts.features.map((court) => {
return <Marker position={{lat: court.geometry.coordinates[1], lng: court.geometry.coordinates[0]}} icon={{
url: "http://www.clker.com/cliparts/j/N/m/m/d/2/glossy-red-icon-button-md.png",
anchor: new google.maps.Point(10,10),
scaledSize: new google.maps.Size(10,10)
}} onClick={this.onMarkerClick} courtId={court.courtId} />
})}
<InfoWindow
marker={this.state.activeMarker}
visible={this.state.showingInfoWindow}>
<div>
<h1>{this.state.courtInfo.name}</h1>
<h3>{this.state.courtInfo.location}</h3>
<h3>Current Players: {this.state.activePlayers}</h3>
</div>
</InfoWindow>
</Map>
</div>
);
}

The marker must contain the latitude and longitude coordinates and not the address. It’s as simple as that. I hope you find this guide useful.

Like what you read? Give Marino Demo a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.