diff --git a/layers/index.js b/layers/index.js index a024e78..cc506d3 100644 --- a/layers/index.js +++ b/layers/index.js @@ -6,6 +6,7 @@ import amtrakLayer from './amtrak/layer.js'; import arenasLayer from './nhl-arenas/layer.js'; import menardsLayer from './menards/layer.js'; import culversLayer from './culvers/layer.js'; +import kwikTripLayer from './kwik-trip/layer.js'; const layerCategories = [ { @@ -66,6 +67,10 @@ const layerCategories = [ name: "Culver's", layer: culversLayer, }, + { + name: "Kwik Trip/Kwik Star", + layer: kwikTripLayer, + } ] } ]; diff --git a/layers/kwik-trip/README.md b/layers/kwik-trip/README.md new file mode 100644 index 0000000..8b04e9d --- /dev/null +++ b/layers/kwik-trip/README.md @@ -0,0 +1,23 @@ +See also https://chandlerswift.com/2022/04/16/the-holy-trinity.html + +```python +# Kwik Trip +# Export to CSV from https://www.kwiktrip.com/Maps-Downloads/Store-List +print("Searching for Kwik Trip locations") +kwiktrip_count = 0 +with open('stores.csv') as f: + reader = csv.DictReader(f) + for row in reader: + kwiktrip_count += 1 + stores.append({ + 'chain': "Kwik Trip", + 'lat': float(row['Latitude']), + 'long': float(row['Longitude']), + 'address': row['Address'].title(), + 'city': row['City'].title(), + 'state': row['State'], + 'zip': row['Zip'], + 'website': f"https://www.kwiktrip.com/locator/store?id={row['Store Number']}", + }) +print(f"{kwiktrip_count} locations found") +``` diff --git a/layers/kwik-trip/get_data.py b/layers/kwik-trip/get_data.py new file mode 100755 index 0000000..237d849 --- /dev/null +++ b/layers/kwik-trip/get_data.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 + +import requests +import json +from bs4 import BeautifulSoup + +print("Searching for Kwik Trip locations") +response = requests.get('https://www.kwiktrip.com/Maps-Downloads/Store-List') + +# HACK HACK HACK +soup = BeautifulSoup(response.text, 'html.parser') +table = soup.find('table') # there's only one, currently; no identifying ID or anything +headers = [th.get_text() for th in table.find('thead').find_all('th')] + +# turn it into a reasonable dict +raw_stores = [] +for row in table.find('tbody').find_all('tr'): + store = {} + for (header, cell) in zip(headers, row.find_all('td')): + store[header] = cell.get_text() + raw_stores.append(store) +print(f"""{len(raw_stores)} locations found""") + +# turn _that_ into GeoJSON Features +stores = [] +for store in raw_stores: + stores.append({ + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [float(store['Longitude']), float(store['Latitude'])], # yes, [lon, lat] since it's [x, y] + }, + "properties": { + 'address': store['Address'].title(), + 'city': store['City'].title(), + 'state': store['State'], + 'zip': store['Zip'], + 'website': f"https://www.kwiktrip.com/locator/store?id={store['Store Number']}", + }, + }) + +geojson = { + "type": "FeatureCollection", + "features": stores, +} + +with open("kwik-trip-data.geojson", "w") as f: + f.write(json.dumps(geojson)) diff --git a/layers/kwik-trip/layer.js b/layers/kwik-trip/layer.js new file mode 100644 index 0000000..754205f --- /dev/null +++ b/layers/kwik-trip/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 kwikTripURL from '/data/kwik-trip-data.geojson?url'; // TODO: remove `?url`? +import pinURL from '/layers/kwik-trip/pin.svg?url'; // TODO: remove `?url`? + +const vectorLayer = new VectorLayer({ + source: new VectorSource({ + url: kwikTripURL, + format: new GeoJSON, + }), + style: new Style({ + image: new Icon({ + anchor: [0.5, 1], + src: pinURL, + }), + }), +}); + +export default vectorLayer; diff --git a/layers/kwik-trip/pin.svg b/layers/kwik-trip/pin.svg new file mode 100644 index 0000000..063a786 --- /dev/null +++ b/layers/kwik-trip/pin.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + +