Hello, NYC Geosearch API! NYC Planning Labs has its very own geocoder*, featuring autocomplete! This might not seem like a big deal, but it's in fact very useful as geocoding in NYC is often difficult to do correctly. Take for example, the confusing addresses in the borough of Queens where adjacent streets share the same name but have different suffixes, and address numbers consist of two hyphenated numbers, the first indicating the lower cross street and the second indicating the building on the block, followed by a 3rd number to represent the street or avenue the building is located on. Other NYC address oddities include the same building having multiple addresses, such as if a building is located on a corner of an intersection. Nuances such as these may throw off geocoders, giving incorrect results or no results at all. The NYC Planning Labs team's geocoder however is backed by the NYC Planning department geo data and does a pretty good job. Plus it's free to use! *read more on geocoding, the process of translating human readable place names to geographic data representations such as latitude, longitude coordinates.
html`<hr />`
Autocomplete FTW: Try typing in an address such as "231 Rutland Road" or "866 Park Place". Type slowly to watch the suggestions role in and get more accurate as you type.
viewof search = text({title: "Search:", placeholder: "Start typing an NYC address here", description: "autcomplete results will be displayed below."})
Search Results:
resultsList = { if (response && response.features.length) { return html` <ol class="ui results-list"> ${response.features.map(feature => html`<li>${feature.properties.label}</li>`)} </ol> `; } return null }
map = { let container = DOM.element('div', { style: `width:${width}px;height:${width * 0.3}px` }); yield container; let map = L.map(container, {scrollWheelZoom: false}).setView([40.7299, -73.9923], 11); let osmLayer = L.tileLayer('https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}@2x.png', { attribution: 'Wikimedia maps beta | © <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' }).addTo(map); if (response && response.features.length) { const resultsLayer = L.geoJson(response, { onEachFeature: function(feature, layer) { layer.bindPopup(`<h3 class="ui">${feature.properties.label}</h3>`) } }).addTo(map); map.fitBounds(resultsLayer.getBounds()); } }
Results from the Geosearch API are returned as a GeoJSON Feature Collection:
response = search.length // delay the request by a couple hundred milliseconds to politely avoid bombarding the API with too many requests ? Promises.delay(200, d3.json(`${autocompleteEndpoint}?text=${search}`)) : null
Search exact
The NYC GeoSearch API also has a regular search endpoint that you may query: This endpoint is better to use when you have an exact address you are looking for. Try one of the following:
viewof selected = select({ description: "Some sample NYC addresses to choose from", options: ["20 W 34th St", "89 E 42nd St", "11 W 53rd St", "Metropolitan Museum of Art", "Coney Island", "World Trade Center", "Prospect Park"], multiple: false })
result = response2 && response2.features.length ? html`<p class="ui">${response2.features[0].properties.label}</p>` : null
map2 = { let container = DOM.element('div', { style: `width:${width}px;height:${width * 0.3}px` }); yield container; let map = L.map(container, {scrollWheelZoom: false}).setView([40.7299, -73.9923], 11); let osmLayer = L.tileLayer('https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}@2x.png', { attribution: 'Wikimedia maps beta | © <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' }).addTo(map); if (response2 && response2.features.length) { const [lng, lat] = response2.features[0].geometry.coordinates; const resultsLayer = L.geoJson(response2, { onEachFeature: function(feature, layer) { layer.bindPopup(`<h3 class="ui">${feature.properties.label}</h3>`) } }).addTo(map); map.setView([lat, lng], 14); } }
response2 = { // delay the request by a couple hundred milliseconds to politely avoid bombarding the API with too many requests return Promises.delay(200, d3.json(`${searchEndpoint}?text=${selected}&size=1`)) }
Happy geocoding!
searchEndpoint = `${baseURL}search`
autocompleteEndpoint = `${baseURL}autocomplete`
baseURL = "https://geosearch.planninglabs.nyc/v1/"
credits Using Leaflet.JS by Tom MacWright NYC Planning Labs Geosearch docs
styles
leafletCSS = html`<link href='${resolve('leaflet@1.2.0/dist/leaflet.css')}' rel='stylesheet' />`
css = html` <style> .ui { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 0.8em; } ol.results-list { //padding-left: 5px; } </style>`
dependencies
import {text, select} from "@jashkenas/inputs"
d3 = require("d3@5.7.0")
L = require('leaflet@1.2.0')