From bfef3a2c7182b58090b0b2331bb29f7f25663cb6 Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Fri, 28 Jul 2023 06:50:50 -0500 Subject: [PATCH 1/5] Add Country Kitchen layer --- layers/chains/country-kitchen/get_data.py | 50 +++++++++++++++++++ layers/chains/country-kitchen/layer.js | 24 +++++++++ layers/chains/country-kitchen/pin.svg | 59 +++++++++++++++++++++++ layers/chains/index.js | 5 ++ 4 files changed, 138 insertions(+) create mode 100755 layers/chains/country-kitchen/get_data.py create mode 100644 layers/chains/country-kitchen/layer.js create mode 100644 layers/chains/country-kitchen/pin.svg diff --git a/layers/chains/country-kitchen/get_data.py b/layers/chains/country-kitchen/get_data.py new file mode 100755 index 0000000..ad81cbb --- /dev/null +++ b/layers/chains/country-kitchen/get_data.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 + +import requests +import json +import re + +# Stolen from my machine, appears to work; sufficient and necessary to get +# around their firewall apparently? +UA={ + "User-Agent": 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/114.0' +} + +response = requests.get('https://countrykitchenrestaurants.com/locations/', headers=UA) + +data = re.search(r'jQuery\(document\).ready\(function\(\$\) \{var map1 = \$\("#map1"\).maps\((.*)\).data\("wpgmp_maps"\);\}\);', response.text) +data = json.loads(data[1]) + +locations = [] +for location in data['places']: + if "coming soon" in location['title'].lower(): + continue + if location['title'] == "Dodgeville, WI": + # currently location['location']['country'] == 'WI', and no location['location']['state'] -- D'oh! + location['location']['state'] = 'WI' + try: + locations.append({ + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [float(location['location']['lng']), float(location['location']['lat'])], # yes, [lon, lat] since it's [x, y] + }, + "properties": { + 'address': location['address'], + 'city': location['location']['city'], + 'state': location['location']['state'], + 'zip': location['location']['postal_code'], + }, + }) + except: + print(location) + +geojson = { + "type": "FeatureCollection", + "features": locations, +} + +print(len(locations), "locations found") + +with open("data.geojson", "w") as f: + f.write(json.dumps(geojson)) diff --git a/layers/chains/country-kitchen/layer.js b/layers/chains/country-kitchen/layer.js new file mode 100644 index 0000000..af140b4 --- /dev/null +++ b/layers/chains/country-kitchen/layer.js @@ -0,0 +1,24 @@ +import VectorLayer from 'ol/layer/Vector'; +import {Vector as VectorSource} from 'ol/source.js'; +import GeoJSON from 'ol/format/GeoJSON.js'; + +import {Style} from 'ol/style.js'; +import Icon from 'ol/style/Icon.js'; + +import url from './data.geojson?url'; // TODO: remove `?url`? +import pin from './pin.svg?url'; // TODO: remove `?url`? + +const vectorLayer = new VectorLayer({ + source: new VectorSource({ + url: url, + format: new GeoJSON, + }), + style: new Style({ + image: new Icon({ + anchor: [0.5, 1], + src: pin, + }), + }), +}); + +export default vectorLayer; diff --git a/layers/chains/country-kitchen/pin.svg b/layers/chains/country-kitchen/pin.svg new file mode 100644 index 0000000..ef37b03 --- /dev/null +++ b/layers/chains/country-kitchen/pin.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + diff --git a/layers/chains/index.js b/layers/chains/index.js index d27025c..d12b301 100644 --- a/layers/chains/index.js +++ b/layers/chains/index.js @@ -1,3 +1,4 @@ +import countryKitchenLayer from './country-kitchen/layer.js'; import culversLayer from './culvers/layer.js'; import krispyKremeLayer from './krispy-kreme/layer.js'; import kwikTripLayer from './kwik-trip/layer.js'; @@ -9,6 +10,10 @@ import whataburgerLayer from './whataburger/layer.js'; const chains = { name: "Chains", layers: [ + { + name: "Country Kitchen", + layer: countryKitchenLayer, + }, { name: "Culver's", layer: culversLayer, From 354d952567870afab0a2c63f0fb84f7ef12262c5 Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Fri, 28 Jul 2023 08:14:48 -0500 Subject: [PATCH 2/5] Fix spacing/padding/overflow style issues --- style.css | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/style.css b/style.css index f82d90d..b1beee7 100644 --- a/style.css +++ b/style.css @@ -1,5 +1,10 @@ @import "node_modules/ol/ol.css"; +html, body { + margin: 0; + padding: 0; +} + #map { position: absolute; top: 0; @@ -10,13 +15,19 @@ } .nav-open #map { - left: min(max(200px, 20%), 400px); + left: min(max(300px, 20%), 400px); } aside { - width: min(max(200px, 20%), 400px); - margin-left: max(min(-200px, -20%), -400px); + width: min(max(300px, 20%), 400px); + margin-left: max(min(-300px, -20%), -400px); transition: 0.25s; + max-height: 100vh; + overflow-y: auto; +} + +aside > div { + padding: 0 0.5em; } .nav-open aside { From eed4688c3bc8afca1aedca314c6d1f4db8c9b8fc Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Fri, 28 Jul 2023 13:15:45 -0500 Subject: [PATCH 3/5] Add US Public Land (national park/forest) layers --- layers/index.js | 2 ++ layers/national-land/get_data.sh | 22 ++++++++++++++ layers/national-land/index.js | 51 ++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100755 layers/national-land/get_data.sh create mode 100644 layers/national-land/index.js diff --git a/layers/index.js b/layers/index.js index 9a7fe5f..eef17c8 100644 --- a/layers/index.js +++ b/layers/index.js @@ -9,6 +9,7 @@ import bikepackingLayer from './bikepacking/layer.js'; import chains from './chains/index.js'; import census_bureau from './census-bureau/index.js'; import states from './states/index.js'; +import national_land from './national-land/index.js'; const layerCategories = [ { // Base maps @@ -75,6 +76,7 @@ const layerCategories = [ chains, census_bureau, states, + national_land, ]; export default layerCategories; diff --git a/layers/national-land/get_data.sh b/layers/national-land/get_data.sh new file mode 100755 index 0000000..ea0f24f --- /dev/null +++ b/layers/national-land/get_data.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +curl --silent --output nps_boundary_geojson.zip http://gstore.unm.edu/apps/rgisarchive/datasets/7bbe8af5-029b-4adf-b06c-134f0dd57226/nps_boundary.derived.geojson +unzip nps_boundary_geojson.zip nps_boundary.geojson +rm nps_boundary_geojson.zip + +# for resolution in 20m 5m; do +# curl --silent --remote-name https://www2.census.gov/geo/tiger/GENZ2022/shp/cb_2022_us_county_${resolution}.zip +# unzip cb_2022_us_county_${resolution}.zip +# ogr2ogr -f GeoJSON us-counties-${resolution}.geojson cb_2022_us_county_${resolution}.shp +# sed -i '/^"crs":/d' us-counties-${resolution}.geojson # TODO: handle this projection properly +# rm cb_2022_us_county_${resolution}.* +# # python cleanup_data.py us-counties-${resolution}.geojson # Only needed for KML files +# done + +# https://data.fs.usda.gov/geodata/edw/datasets.php?xmlKeyword=Original+Proclaimed+National+Forests +curl --silent --remote-name https://data.fs.usda.gov/geodata/edw/edw_resources/shp/S_USA.ProclaimedForest.zip +unzip S_USA.ProclaimedForest.zip +ogr2ogr -f GeoJSON us-national-forests.geojson S_USA.ProclaimedForest.shp +sed -i '/^"crs":/d' us-national-forests.geojson # TODO: handle this projection properly +rm S_USA.ProclaimedForest.* +# TODO: some kind of cleanup to save space? diff --git a/layers/national-land/index.js b/layers/national-land/index.js new file mode 100644 index 0000000..20df671 --- /dev/null +++ b/layers/national-land/index.js @@ -0,0 +1,51 @@ +import GeoJSON from 'ol/format/GeoJSON.js'; +import VectorLayer from 'ol/layer/Vector.js'; +import VectorSource from 'ol/source/Vector.js'; + +import nationalParks from './nps_boundary.geojson?url'; +import nationalForests from './us-national-forests.geojson?url'; + +import { Fill, Stroke, Style, Text } from 'ol/style.js'; + +function style(feature){ + return new Style({ + text: new Text({ + text: feature.get('FORESTNAME') || (feature.get('UNIT_NAME') + " National Park"), + }), + fill: new Fill({ + color: 'rgba(255,255,255,0.4)', + }), + stroke: new Stroke({ + color: '#008800', + width: 1.25, + }), + }); +} + +const layers = { + name: "US Public Land", + layers: [ + { + name: "National Parks", + layer: new VectorLayer({ + source: new VectorSource({ + url: nationalParks, + format: new GeoJSON(), + }), + style: style, + }), + }, + { + name: "National Forests", + layer: new VectorLayer({ + source: new VectorSource({ + url: nationalForests, + format: new GeoJSON(), + }), + style: style, + }), + }, + ], +}; + +export default layers; From 78f9830400d29a215183a2621b2be6487180ef65 Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Fri, 28 Jul 2023 08:21:58 -0500 Subject: [PATCH 4/5] Only open categories with active layers by default --- main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.js b/main.js index e071a85..b44d4d9 100644 --- a/main.js +++ b/main.js @@ -26,7 +26,7 @@ const map = new Map({ for (let category of layerCategories) { const catDiv = document.createElement("div"); catDiv.innerHTML = ` -
+
l.enabled).length > 0 ? "open" : ""}> ${category.name}
    From 645aa85751fd930e73c35c21b2c43b8ae3af6a01 Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Sat, 19 Aug 2023 13:52:20 -0500 Subject: [PATCH 5/5] Add Punch Pizza --- layers/chains/index.js | 5 +++ layers/chains/punch-pizza/get_data.py | 43 +++++++++++++++++++ layers/chains/punch-pizza/layer.js | 24 +++++++++++ layers/chains/punch-pizza/pin.svg | 60 +++++++++++++++++++++++++++ 4 files changed, 132 insertions(+) create mode 100755 layers/chains/punch-pizza/get_data.py create mode 100644 layers/chains/punch-pizza/layer.js create mode 100644 layers/chains/punch-pizza/pin.svg diff --git a/layers/chains/index.js b/layers/chains/index.js index d12b301..6ad85f2 100644 --- a/layers/chains/index.js +++ b/layers/chains/index.js @@ -4,6 +4,7 @@ import krispyKremeLayer from './krispy-kreme/layer.js'; import kwikTripLayer from './kwik-trip/layer.js'; import menardsLayer from './menards/layer.js'; import milwaukeeBurgerCompanyLayer from './milwaukee-burger-company/layer.js'; +import punchPizzaLayer from './punch-pizza/layer.js'; import waffleHouseLayer from './waffle-house/layer.js'; import whataburgerLayer from './whataburger/layer.js'; @@ -34,6 +35,10 @@ const chains = { name: "Milwaukee Burger Company", layer: milwaukeeBurgerCompanyLayer, }, + { + name: "Punch Pizza", + layer: punchPizzaLayer, + }, { name: "Waffle House", layer: waffleHouseLayer, diff --git a/layers/chains/punch-pizza/get_data.py b/layers/chains/punch-pizza/get_data.py new file mode 100755 index 0000000..63a3b82 --- /dev/null +++ b/layers/chains/punch-pizza/get_data.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +import requests +import json +from bs4 import BeautifulSoup +import re +import urllib.parse + +# Stolen from my machine, appears to work; sufficient and necessary to get +# around their firewall apparently? +UA={ + "User-Agent": 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/114.0' +} + +response = requests.get('https://punchpizza.com/locations/', headers=UA) + +soup = BeautifulSoup(response.text, 'html.parser') +location_links = soup.select('div.loctop > .wpb_wrapper > ul > li > a') # Two rows with the same id :eyeroll: + +locations = [] +for location_link in location_links: + location_response = response = requests.get(urllib.parse.urljoin("https://punchpizza.com", location_link['href']), headers=UA) + latlon = re.search(r'var punchloc = {lat: ([0-9.-]*), lng: ([0-9.-]*)};', location_response.text) + if not latlon: + raise Exception("No latlon found") + locations.append({ + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [float(latlon[2]), float(latlon[1])], # yes, [lon, lat] since it's [x, y] + }, + # TODO: addresses are kind of a mess + }) + +geojson = { + "type": "FeatureCollection", + "features": locations, +} + +print(len(locations), "locations found") + +with open("data.geojson", "w") as f: + f.write(json.dumps(geojson)) diff --git a/layers/chains/punch-pizza/layer.js b/layers/chains/punch-pizza/layer.js new file mode 100644 index 0000000..96b894e --- /dev/null +++ b/layers/chains/punch-pizza/layer.js @@ -0,0 +1,24 @@ +import VectorLayer from 'ol/layer/Vector'; +import {Vector as VectorSource} from 'ol/source.js'; +import GeoJSON from 'ol/format/GeoJSON.js'; + +import {Style} from 'ol/style.js'; +import Icon from 'ol/style/Icon.js'; + +import url from './data.geojson?url'; // TODO: remove `?url`? +import pin from './pin.svg?url'; // TODO: remove `?url`? + +const vectorLayer = new VectorLayer({ + source: new VectorSource({ + url: url, + format: new GeoJSON, + }), + style: new Style({ + image: new Icon({ + anchor: [0.5, 1], + src: pin, // or https://punchpizza.com/wp-content/themes/sprung-total/img/mappoint-punch.png + }), + }), +}); + +export default vectorLayer; diff --git a/layers/chains/punch-pizza/pin.svg b/layers/chains/punch-pizza/pin.svg new file mode 100644 index 0000000..0b526c5 --- /dev/null +++ b/layers/chains/punch-pizza/pin.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + +