From 7917d1a1e70c9918ad2f027d45986c1cc6b55b8d Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Sat, 9 Mar 2024 19:54:18 -0600 Subject: [PATCH 1/5] Add Raising Cane's layer --- layers/chains/index.js | 5 + layers/chains/raising-canes/get_data.py | 46 ++++ layers/chains/raising-canes/layer.js | 24 ++ layers/chains/raising-canes/pin.svg | 278 ++++++++++++++++++++++++ 4 files changed, 353 insertions(+) create mode 100755 layers/chains/raising-canes/get_data.py create mode 100644 layers/chains/raising-canes/layer.js create mode 100644 layers/chains/raising-canes/pin.svg diff --git a/layers/chains/index.js b/layers/chains/index.js index 6ad85f2..bd89355 100644 --- a/layers/chains/index.js +++ b/layers/chains/index.js @@ -5,6 +5,7 @@ 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 raisingCanesLayer from './raising-canes/layer.js'; import waffleHouseLayer from './waffle-house/layer.js'; import whataburgerLayer from './whataburger/layer.js'; @@ -39,6 +40,10 @@ const chains = { name: "Punch Pizza", layer: punchPizzaLayer, }, + { + name: "Raising Cane's", + layer: raisingCanesLayer, + }, { name: "Waffle House", layer: waffleHouseLayer, diff --git a/layers/chains/raising-canes/get_data.py b/layers/chains/raising-canes/get_data.py new file mode 100755 index 0000000..dc6e4f6 --- /dev/null +++ b/layers/chains/raising-canes/get_data.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 + +import requests +import json + +print("Searching for Raising Cane's locations") +response = requests.get('https://raisingcanes.com/page-data/sq/d/3976656178.json').json() + +stores = [] + +for s in response['data']['allPrismicStoreLocation']['nodes']: + if s['uid'] == 'ara2': # Not sure what's up with this one: https://raisingcanes.com/locations/ara2/ + continue + elif s['uid'] == 'c524': # Null island? https://raisingcanes.com/locations/c524/ + s['data']['coordinates'] = { + "longitude": -111.9811399, + "latitude": 40.5447361, + } + stores.append({ + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [float(s['data']['coordinates']['longitude']), float(s['data']['coordinates']['latitude'])], # yes, [lon, lat] since it's [x, y] + }, + "properties": { + 'name': s['data']['external_location_data']['displayName'], + 'nickname': s['data']['external_location_data']['nickname'], + 'address': s['data']['external_location_data']['address1'], + 'city': s['data']['external_location_data']['city'], + 'state': s['data']['external_location_data']['state'], + 'zip': s['data']['external_location_data']['postal_code'], + 'website': f"https://raisingcanes.com/locations/{s['uid']}", + 'opened': s['data']['external_location_data']['birthdate'], + 'hours': s['data']['external_location_data']['hours'], + }, + }) + +print(f"""{len(stores)} locations found""") + +geojson = { + "type": "FeatureCollection", + "features": stores, +} + +with open("data.geojson", "w") as f: + f.write(json.dumps(geojson)) diff --git a/layers/chains/raising-canes/layer.js b/layers/chains/raising-canes/layer.js new file mode 100644 index 0000000..af140b4 --- /dev/null +++ b/layers/chains/raising-canes/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/raising-canes/pin.svg b/layers/chains/raising-canes/pin.svg new file mode 100644 index 0000000..344a169 --- /dev/null +++ b/layers/chains/raising-canes/pin.svg @@ -0,0 +1,278 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 9b48d1c7827d30c466a48580ef7c3b4d680c7526 Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Sat, 9 Mar 2024 19:54:43 -0600 Subject: [PATCH 2/5] Populate layers from URL --- main.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/main.js b/main.js index 6aaadc2..43a6c36 100644 --- a/main.js +++ b/main.js @@ -119,8 +119,14 @@ for (let category of layerCategories) { document.querySelector("aside").appendChild(catDiv); } +const urlParams = new URLSearchParams(window.location.search); +const urlLayers = urlParams.getAll('layer'); + for (let category of layerCategories) { for (let layer of category.layers) { + if (urlLayers.includes(layer.name)) { + layer.enabled = true; + } if (layer.enabled) { map.addLayer(layer.layer); } From 52a2ce38381c840652112ff43da7385dad987f4a Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Tue, 12 Mar 2024 00:09:48 -0500 Subject: [PATCH 3/5] Add links for non-tls URLs, too --- main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.js b/main.js index 43a6c36..121bbf5 100644 --- a/main.js +++ b/main.js @@ -140,7 +140,7 @@ function objectToTable(o) { if (typeof value === "object") { value = objectToTable(value); } - if (typeof value === "string" && value.startsWith('https://')) { + if (typeof value === "string" && /^https?:\/\//.test(value)) { value = `${value}` } table += `${key}${value}`; From 44d41ce0178f550b2784858c0cd954bd2b935610 Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Tue, 12 Mar 2024 00:10:03 -0500 Subject: [PATCH 4/5] Call customPopupCallback even if no customPopup --- main.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main.js b/main.js index 121bbf5..652a83e 100644 --- a/main.js +++ b/main.js @@ -161,15 +161,15 @@ map.on('click', function (evt) { } if (layer.hasOwnProperty('customPopup')) { content.innerHTML = layer.customPopup(feature); - if (layer.hasOwnProperty('customPopupCallback')) { - layer.customPopupCallback(feature); - } } else { // exclude geometry -- https://stackoverflow.com/a/208106 const {geometry: _, ...featureData} = feature.getProperties(); content.innerHTML = objectToTable(featureData); } + if (layer.hasOwnProperty('customPopupCallback')) { + layer.customPopupCallback(feature); + } popupOverlay.setPosition(evt.coordinate); From ce164c6af686d774162bbe1a5aa861883e2dd9c6 Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Tue, 12 Mar 2024 00:10:25 -0500 Subject: [PATCH 5/5] Add Culvers Flavor of the Day --- layers/chains/culvers/layer.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/layers/chains/culvers/layer.js b/layers/chains/culvers/layer.js index af140b4..8ee7e58 100644 --- a/layers/chains/culvers/layer.js +++ b/layers/chains/culvers/layer.js @@ -2,6 +2,8 @@ import VectorLayer from 'ol/layer/Vector'; import {Vector as VectorSource} from 'ol/source.js'; import GeoJSON from 'ol/format/GeoJSON.js'; +import { toLonLat } from 'ol/proj'; + import {Style} from 'ol/style.js'; import Icon from 'ol/style/Icon.js'; @@ -21,4 +23,23 @@ const vectorLayer = new VectorLayer({ }), }); +vectorLayer.customPopupCallback = async function(feature) { + const fotd_parent = document.createElement('div'); + fotd_parent.innerHTML = "Flavor of the Day: "; + document.querySelector('#popup-content').append(fotd_parent); + + const fotd_child = document.createElement('span'); + fotd_child.innerHTML = "Loading…"; + + const fotd_image = document.createElement('img') + fotd_parent.append(fotd_child, fotd_image); + + const [long, lat] = toLonLat(feature.getGeometry().getCoordinates()); + const res = await fetch(`https://corsproxy.io/?${encodeURIComponent(`https://www.culvers.com/api/restaurants/getLocations?lat=${lat}&long=${long}&limit=1`)}`) + const res_data = await res.json(); + fotd_child.innerHTML = res_data.data.geofences[0].metadata.flavorOfDayName; + fotd_image.src = `https://cdn.culvers.com/menu-item-detail/${res_data.data.geofences[0].metadata.flavorOfDaySlug}`; + fotd_image.style.width = "min(300px, 60vh)"; +} + export default vectorLayer;