From 31cd14cd86ee83c6f74166494fff34b1284b9cff Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Fri, 1 Mar 2024 19:18:40 -0600 Subject: [PATCH 1/3] Standardize on lon/lat not lat/lon --- get_data.py | 4 ++-- index.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/get_data.py b/get_data.py index 7df10f1..8a2280c 100644 --- a/get_data.py +++ b/get_data.py @@ -34,8 +34,8 @@ for state in states[:51]: # Just the 50 and DC, not Guam/American Samoa/PR/etc for feature in data['features']: # {"type": "Feature", "properties": {"STATEFP": "01", "PLACEFP": "02260", "PLACENS": "02405163", "GEOID": "0102260", "NAME": "Ardmore", "NAMELSAD": "Ardmore town", "LSAD": "43", "CLASSFP": "C1", "PCICBSA": "N", "PCINECTA": "N", "MTFCC": "G4110", "FUNCSTAT": "A", "ALAND": 5289895, "AWATER": 21830, "INTPTLAT": "+34.9878376", "INTPTLON": "-086.8290225"}, "geometry": {"type": "Polygon", "coordinates": [[[-86.856689, 34.992046], [-86.855354, 34.992044], [-86.855101, 34.99204] state_place = (feature['properties']['STATEFP'], feature['properties']['PLACEFP']) - lat_lon = (float(feature['properties']['INTPTLAT']), float(feature['properties']['INTPTLON'])) - place_locations[state_place] = lat_lon + lon_lat = (float(feature['properties']['INTPTLON']), float(feature['properties']['INTPTLAT'])) + place_locations[state_place] = lon_lat print("done") print("Fetching population data for all states…", flush=True, end="") diff --git a/index.html b/index.html index d24b864..1f87ae2 100644 --- a/index.html +++ b/index.html @@ -184,7 +184,7 @@ for (let city of cities) { if (city.guessed) { ctx.beginPath(); - const c = transform([city.location[1], city.location[0]]) + const c = transform(city.location) console.log(city.location, c) ctx.arc(c[0], c[1], 2, 0, 2*Math.PI, true); ctx.fill(); From 70c954d4faa91dd7894c52197522ef1cc8d8b80b Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Tue, 5 Mar 2024 23:27:09 -0600 Subject: [PATCH 2/3] Fix projection (mercator) and centering --- index.html | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index 1f87ae2..23ce8f5 100644 --- a/index.html +++ b/index.html @@ -126,7 +126,7 @@ const cities = await response.json(); await state_shape_data_request; // We can't draw until this is in const state_shape = state_shape_data.features.find(f => f.properties.NAME.toLowerCase() == stateName.toLowerCase()); - const state_bounds = find_bounds(state_shape.geometry.coordinates[0]); + const state_mercator_adjusted_bounds = find_bounds(state_shape.geometry.coordinates[0].map(mercator)); if (!state_shape) { console.error("Unable to find state in shapes"); } @@ -169,14 +169,21 @@ const ctx = canvas.getContext("2d"); ctx.clearRect(0, 0, canvas.width, canvas.height); + const [minx, maxx, miny, maxy] = state_mercator_adjusted_bounds; + const height_scale = (canvas.height - 8) / (maxy - miny); + const width_scale = (canvas.width - 8) / (maxx - minx); + const scale = Math.min(height_scale, width_scale); + + const y_offset = miny - (canvas.height / scale - (maxy - miny)) / 2; + const x_offset = minx - (canvas.width / scale - (maxx - minx)) / 2; + function transform(pt) { - // TODO: this just works for MN, and not very well at that - return [(pt[0]+98)*80, 600-(pt[1]-42)*80]; + pt = mercator(pt) + return [scale * (pt[0] - x_offset), canvas.height - (scale * (pt[1] - y_offset))]; } ctx.beginPath(); ctx.moveTo(...transform(state_shape.geometry.coordinates[0][0])) - console.log(transform(state_shape.geometry.coordinates[0][0])) for (let coord of state_shape.geometry.coordinates[0].slice(1)) { ctx.lineTo(...transform(coord)); } @@ -194,6 +201,14 @@ }).mount(); } + function mercator(pt) { + const radians_from_eq = Math.abs(Math.PI/180 * pt[1]); + // https://en.wikipedia.org/wiki/Mercator_projection#Derivation + const y_radians = Math.log(Math.tan(Math.PI/4 + radians_from_eq/2)); + const y_degrees = 180/Math.PI * y_radians; + return [pt[0], y_degrees]; + } + // returns minx, maxx, miny, maxy function find_bounds(coords) { return [ From 4c9ef7aa441f74dd81967338c31fd7dd06d12445 Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Tue, 5 Mar 2024 23:29:06 -0600 Subject: [PATCH 3/3] Add checkbox to show unguessed cities --- index.html | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 23ce8f5..9a61f3d 100644 --- a/index.html +++ b/index.html @@ -61,6 +61,9 @@
+
+ Show unguessed cities +
@@ -137,6 +140,7 @@ simplified_cities: cities.map(city => simplify(city.name)), city_guess: "", message: "", + show_unguessed_cities: true, achievements: { "Top Five": cities => cities.slice(0, 5), "Top Ten": cities => cities.slice(0, 10), @@ -192,10 +196,15 @@ if (city.guessed) { ctx.beginPath(); const c = transform(city.location) - console.log(city.location, c) + ctx.fillStyle = "black"; + ctx.arc(c[0], c[1], 2, 0, 2*Math.PI, true); + } else if (this.show_unguessed_cities) { + ctx.beginPath(); + const c = transform(city.location) + ctx.fillStyle = "lightgray"; ctx.arc(c[0], c[1], 2, 0, 2*Math.PI, true); - ctx.fill(); } + ctx.fill(); } }, }).mount();