Skip to content

Instantly share code, notes, and snippets.

@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 / 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 / index.html
Last active January 6, 2024 02:23
D3 Sankey Link with Variable Width
<!DOCTYPE html>
<meta charset="utf-8">
<title>Variable Width Sankey Link</title>
<style>
path {
fill: steelblue;
}
</style>
@chriswhong
chriswhong / README.md
Last active October 18, 2023 09:37
Clickable Markers in MapboxGL

This example shows how to extend mapboxGL's Marker class to add custom functionality on click.

Why?

MapboxGL has a very convenient Marker class that can be used to quickly get markers on the map with a few lines of code (versus the more complex method of adding sources and layers). They behave a bit differently from the rest of the map features because they are actually HTML elements overlaid on the map canvas.

The stock markers are great, and they are SVG so you can color them by passing in a color option! However, the only interactivity you can easily set up is a popup. When you google 'clickable markers', the examples you find are all using symbol layers with queryRenderedFeatures.

I wanted to trigger navigation in a single page app using the stock Markers and determined a simple extension of the class would help me accomplish this. You can also see these markers in action at https://paintthetown.chriswhong.com

@chriswhong
chriswhong / scrape.js
Created April 22, 2019 03:58
Decrypting Amtrak's real-time train location geoJSON feed
// decrypting Amtrak's real-time train location geoJSON feed
// based on https://github.com/Vivalize/Amtrak-Train-Stats
const fetch = require('node-fetch');
const CryptoJS = require('crypto-js');
// this is the xhr call done by https://www.amtrak.com/track-your-train.html containing encrypted train location data
const dataUrl = 'https://maps.amtrak.com/services/MapDataService/trains/getTrainsData';
// these constants are pulled from RoutesList.v.json, which is an object with keys 'arr', 's', and 'v'
const sValue = '9a3686ac'; // found at s[8]
@chriswhong
chriswhong / README.md
Created February 28, 2020 17:55
Using ogr2ogr to load a CSV into Postgres

The absolute easiest way to get a CSV into a postgresql table is to use ogr2ogr with AUTODETECT_TYPE=YES.

I learned a while back that this is what cartoDB uses to import your CSV into postgis (with a lot of other parameters added)

ogr2ogr -f PostgreSQL PG:"host=localhost user=postgres dbname=postgres password=password"  docs.csv -oo AUTODETECT_TYPE=YES
@chriswhong
chriswhong / config.js
Created December 1, 2022 23:11
Mapbox Scrollytelling Example with Linestring Animation
window.testCallback = () => {
let startTime;
const duration = 10000;
const frame = (time) => {
if (!startTime) startTime = time;
const animationPhase = (time - startTime) / duration;
// Reduce the visible length of the line by using a line-gradient to cutoff the line
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@chriswhong
chriswhong / intakeq-bulk-download.js
Last active March 22, 2022 14:30
Iterates over the list of intakes in IntakeQ web UI, downloading each as a PDF.
// Bulk download of IntakeQ forms
// This script will iterate over the list of intakes in IntakeQ, downloading
// each as a PDF. It also pulls the customer's name from the list and uses it
// to create the filename
// this script does not paginate. To use navigate to a list of intakes, open
// developer tools, paste into the console, press enter
// if you have more than one page, manually navigate to the next page and repeat
// select all table row elements