Skip to content

Instantly share code, notes, and snippets.

@chriswhong
chriswhong / choropleth.js
Created March 23, 2017 11:53
Choropleth for mapboxGL
// choropleth.js
// given polygon geojson data and options, returns a GL fill style
// adaptation of Tim Wisniewskis' Leaflet Choropleth
import chroma from 'chroma-js';
const Choropleth = (geojson, opts) => {
opts = opts || {};
@chriswhong
chriswhong / README.md
Last active February 22, 2024 08:46
Node.js proxy endpoint to access TMS tiles via XYZ url

TMS vs XYZ

Web map raster tile URL templates usally look like this: //{servername}/{somepath}/{z}/{x}/{y}.png

Z is the zoom level (0 being zoomed all the way out so the earth fits on a single 256px x 256px tile, 18 or higher getting you down to street level) X and Y are the tiles coordinates, but there are two different standards for where the origin of the Y coordinate is.

If you look at [http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/](this site) which shows the various tile coordinates, you'll see that the X's are identical for 'Google' and 'TMS', but the Ys are different. 'Google', aka 'XYZ' aka a few other names that nobody seems to agree on places the Y origin at the north end of the earth, while TMS places it in the south.

Re-serve a TMS tileset as an XYZ tileset using express.js

@chriswhong
chriswhong / README.md
Last active June 21, 2017 12:06
Logging Maryland MTA Real-time bus data

Logging Maryland MTA Real-time bus data

Technical considerations for logging real-time bus data

Overview

The Maryland MTA has made available real-time bus location data in GTFS-RT format, available at http://mta.maryland.gov/content/developer-resources. Various stakeholders wish to use historical real-time data to assess the timeliness of the bus system. Successful analysis would require a consistent dataset of archived real time locations.

Database vs Static Files

A major consideration is whether to use a database to store the data, or to store it in a well-organized hierarchical tree of static files.

Storing the data in database means a slightly more complex hosting environment. New data are committed to the database, but the data would not be easily accessible without more work to expose certain queries as bulk downloads, or allow users to build their own queries and retreive data on demand (basically, we must build a web api on top of the database in order to make it accessible).

@chriswhong
chriswhong / README.md
Created August 8, 2017 12:24
A Vector Tile microservice for MapPLUTO (or any other data)

Background

We like building mapping applications with carto as the backend, because it gets us an instant map tiler and SQL API. However, carto's tiler is raster-based, and we would like to take advantage of mapboxGL for it's vector-based rendering. We discovered an undocumented vector tile endpoint in carto, which has enabled us to use vector tiles without any additional work

Problem

Using the undocumented MVT API has worked well enough to date, but when faced with a dataset with lots of very small contiguous polygons, the tiler seems to choke at low zoom levels, and does not include all data that should be rendered in a tile.

Solution

We have contemplated setting up a microservice to serve vector tiles of MapPLUTO, either cutting static tiles, or using some other tile server.

TileStrata is a good candidate for this task. It's an extensible nodejs-based tile server.

@chriswhong
chriswhong / geosupport-autocomplete.md
Last active November 6, 2017 14:51
An autocomplete web API for geosupport

Problem

DCP maintains geosupport, the city's official geocoder, which can be accessed by using the libraries directly, or via various client-facing application/services including GOAT, GeoClient, GeoBat, etc.

The NYC Planning Labs team would like to incorporate geosupport results into web mapping applications, but geosupport's architecture does not work well with the "autocomplete" search style that is popular in modern web applications. Traditionally, to use geosupport, the user must provide at least a house number, street name, and borough, and will either git a hit, or a list of possible alternatives.

Below we propose some high-level specifications for a GeoSupport Autocomplete Web API that would be useful for search in modern web applications.

A Model to Emulate: Mapzen Search's Autocomplete API

Mapzen Search has an autocomplete API, which is well-documente, open source, and provides the type of experience developers want in a modern g

@chriswhong
chriswhong / README.md
Created February 27, 2018 06:41
Consuming USGS OrthoImagery in MapboxGL

MapboxGL Layer Definition for consuming tiles from the USGS Imagery MapServer

{
  id: 'usgs-aerials',
  type: 'raster',
  source: {
    type: 'raster',
    tiles: [
      'https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}',
 ],
@chriswhong
chriswhong / RadiusMode.js
Created March 1, 2018 12:04
RadiusMode, a custom mode for mapbox-gl-draw for drawing a radius
// custom mapbopx-gl-draw mode that modifies draw_line_string
// shows a center point, radius line, and circle polygon while drawing
// forces draw.create on creation of second vertex
import MapboxDraw from 'mapbox-gl-draw';
import numeral from 'numeral';
import lineDistance from 'npm:@turf/line-distance';
const RadiusMode = MapboxDraw.modes.draw_line_string;
@chriswhong
chriswhong / gist:762ceac7fb8a1420e7e7adceb770b707
Last active March 3, 2022 09:01
Using ST_AsMVT() and ST_AsMVTGeom() in express to build a vector tile endpoint
/* GET /tiles/:z/:x/:y.mvt */
/* Retreive a vector tile by tileid */
router.get('/tiles/:z/:x/:y.mvt', async (req, res) => {
const { z, x, y } = req.params;
// calculate the bounding polygon for this tile
const bbox = mercator.bbox(x, y, z, false);
// Query the database, using ST_AsMVTGeom() to clip the geometries
// Wrap the whole query with ST_AsMVT(), which will create a protocol buffer
@chriswhong
chriswhong / downloadroute.js
Created July 10, 2018 05:02
Streaming from ps-promise to json2csv to express response
// This code queries postgresql and streams the results into a csv
// Works like a charm for a download button, no hangup for large files!
const Json2csvTransform = require('json2csv').Transform;
const QueryStream = require('pg-query-stream');
const JSONStream = require('JSONStream');
router.get('/download.csv', async (req, res) => {
const { query } = req;
@chriswhong
chriswhong / gist:11e2b2d68505e239f89f46e36aaa03d2
Created July 20, 2018 18:04
Convenience Redirect in express.js. Build URLs using a known unique id
const express = require('express');
const router = express.Router();
router.get('/:ulurpnumber', async (req, res) => {
const { app, params } = req;
const { ulurpnumber } = params;
// find projectid for this ceqrnumber
// http://localhost:3000/projects/ulurp/170358ZMM