From c612e3ccd0bda938a3833c4f2c8cf28e1bca3d27 Mon Sep 17 00:00:00 2001 From: Tyler Duckworth Date: Fri, 31 Oct 2025 11:13:33 -0400 Subject: [PATCH 1/4] Frontend initial commit. --- .gitignore | 1 + map-app/.gitignore | 41 + map-app/README.md | 9 + map-app/biome.json | 37 + map-app/data/near_road_sides.json | 1 + map-app/next.config.ts | 7 + map-app/package-lock.json | 2259 +++++++++++++++++ map-app/package.json | 30 + map-app/postcss.config.mjs | 5 + map-app/public/file.svg | 1 + map-app/public/globe.svg | 1 + map-app/public/next.svg | 1 + map-app/public/vercel.svg | 1 + map-app/public/window.svg | 1 + map-app/src/app/SiteMap.tsx | 71 + .../src/app/components/AirQualityStation.tsx | 45 + map-app/src/app/components/DisplayPane.tsx | 50 + map-app/src/app/components/SharedState.tsx | 32 + map-app/src/app/favicon.ico | Bin 0 -> 25931 bytes map-app/src/app/globals.css | 43 + map-app/src/app/layout.tsx | 35 + map-app/src/app/page.tsx | 107 + map-app/src/app/pin.tsx | 21 + map-app/tsconfig.json | 27 + 24 files changed, 2826 insertions(+) create mode 100644 .gitignore create mode 100644 map-app/.gitignore create mode 100644 map-app/README.md create mode 100644 map-app/biome.json create mode 100644 map-app/data/near_road_sides.json create mode 100644 map-app/next.config.ts create mode 100644 map-app/package-lock.json create mode 100644 map-app/package.json create mode 100644 map-app/postcss.config.mjs create mode 100644 map-app/public/file.svg create mode 100644 map-app/public/globe.svg create mode 100644 map-app/public/next.svg create mode 100644 map-app/public/vercel.svg create mode 100644 map-app/public/window.svg create mode 100644 map-app/src/app/SiteMap.tsx create mode 100644 map-app/src/app/components/AirQualityStation.tsx create mode 100644 map-app/src/app/components/DisplayPane.tsx create mode 100644 map-app/src/app/components/SharedState.tsx create mode 100644 map-app/src/app/favicon.ico create mode 100644 map-app/src/app/globals.css create mode 100644 map-app/src/app/layout.tsx create mode 100644 map-app/src/app/page.tsx create mode 100644 map-app/src/app/pin.tsx create mode 100644 map-app/tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40b878d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/map-app/.gitignore b/map-app/.gitignore new file mode 100644 index 0000000..5ef6a52 --- /dev/null +++ b/map-app/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/map-app/README.md b/map-app/README.md new file mode 100644 index 0000000..21c4249 --- /dev/null +++ b/map-app/README.md @@ -0,0 +1,9 @@ +To install the dependencies, run: +``` +> npm install +``` + +To run the project, run: +``` +> npm run dev +``` \ No newline at end of file diff --git a/map-app/biome.json b/map-app/biome.json new file mode 100644 index 0000000..41b3b95 --- /dev/null +++ b/map-app/biome.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": true, + "includes": ["**", "!node_modules", "!.next", "!dist", "!build"] + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2 + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "suspicious": { + "noUnknownAtRules": "off" + } + }, + "domains": { + "next": "recommended", + "react": "recommended" + } + }, + "assist": { + "actions": { + "source": { + "organizeImports": "on" + } + } + } +} diff --git a/map-app/data/near_road_sides.json b/map-app/data/near_road_sides.json new file mode 100644 index 0000000..d3f5233 --- /dev/null +++ b/map-app/data/near_road_sides.json @@ -0,0 +1 @@ +[{"CBSA Full Name":"Atlanta-Sandy Springs-Roswell, GA","RO":4,"Population 2015":5710795,"Population 2020":6087762,"State":"GA","County":"Dekalb","City":"Atlanta","Local Site Name":"DMRC\/ NR-285","AQS ID":"13-089-0003","Latitude":33.698539,"Longitude":-84.272742,"Target Road":"I-285","Recent (>2016) HPMS AADT":147000.0,"Recent (>2016) Est. FE-AADT":320709.698630137,"Orig. AADT (2012-2015)":146000,"Orig. AADT Rank in CBSA":23.0,"Orig. FE-AADT":318528,"Orig. FE-AADT Rank in CBSA":13.0,"Distance to nearest road travel feature (m)":26.0,"Distance to nearest mainline (m)":35.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1420070400000,"CO Start Date":null,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":1430438400000,"BC instrument model":"TEI 5012 MAAP"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":"TSP Pb ","Coming Soon":null},{"CBSA Full Name":"Atlanta-Sandy Springs-Roswell, GA","RO":4,"Population 2015":5710795,"Population 2020":6087762,"State":"GA","County":"Fulton","City":"Atlanta","Local Site Name":"Georgia Tech","AQS ID":"13-121-0056","Latitude":33.778461,"Longitude":-84.391431,"Target Road":"I-85","Recent (>2016) HPMS AADT":382000.0,"Recent (>2016) Est. FE-AADT":544678.4781693107,"Orig. AADT (2012-2015)":284920,"Orig. AADT Rank in CBSA":2.0,"Orig. FE-AADT":406256,"Orig. FE-AADT Rank in CBSA":4.0,"Distance to nearest road travel feature (m)":7.0,"Distance to nearest mainline (m)":7.0,"NO2 Probe Height (m)":4.5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1402790400000,"CO Start Date":1402790400000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":1420070400000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":1427846400000,"BC instrument model":"TEI 5012 MAAP"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1408492800000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":1427760000000,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Austin-Round Rock, TX","RO":6,"Population 2015":2000860,"Population 2020":2228106,"State":"TX","County":"Travis","City":"Austin","Local Site Name":"I-35","AQS ID":"48-453-1068","Latitude":30.353823,"Longitude":-97.691543,"Target Road":"I-35","Recent (>2016) HPMS AADT":144013.0,"Recent (>2016) Est. FE-AADT":268440.5381663566,"Orig. AADT (2012-2015)":188150,"Orig. AADT Rank in CBSA":7.0,"Orig. FE-AADT":350712,"Orig. FE-AADT Rank in CBSA":10.0,"Distance to nearest road travel feature (m)":23.0,"Distance to nearest mainline (m)":43.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1397606400000,"CO Start Date":1482105600000,"Continuous PM2.5 Start Date":1540425600000,"Current Cont. PM2.5 method":"MetOne BAM 1022","FRM PM2.5 Start Date":1483747200000,"FRM PM2.5 Stop Date":1541116800000,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Bakersfield, CA","RO":9,"Population 2015":882176,"Population 2020":901362,"State":"CA","County":"Kern","City":"Bakersfield","Local Site Name":"Westwind","AQS ID":"06-029-2019","Latitude":35.376991,"Longitude":-119.044022,"Target Road":"CA 99","Recent (>2016) HPMS AADT":154000.0,"Recent (>2016) Est. FE-AADT":449974.0,"Orig. AADT (2012-2015)":132000,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":385692,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":18.0,"Distance to nearest mainline (m)":18.0,"NO2 Probe Height (m)":5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1546300800000,"CO Start Date":null,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1546300800000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Baltimore-Columbia-Towson, MD","RO":3,"Population 2015":2797407,"Population 2020":2800189,"State":"MD","County":"Baltimore","City":"Pikesville","Local Site Name":"Old Court Road","AQS ID":"24-005-0009","Latitude":39.371679,"Longitude":-76.746814,"Target Road":"I-695\/I-795","Recent (>2016) HPMS AADT":185270.0,"Recent (>2016) Est. FE-AADT":296188.879845643,"Orig. AADT (2012-2015)":187617,"Orig. AADT Rank in CBSA":9.0,"Orig. FE-AADT":299941,"Orig. FE-AADT Rank in CBSA":29.0,"Distance to nearest road travel feature (m)":21.0,"Distance to nearest mainline (m)":21.0,"NO2 Probe Height (m)":3.4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1451606400000,"CO Start Date":null,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1451606400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Baltimore-Columbia-Towson, MD","RO":3,"Population 2015":2797407,"Population 2020":2800189,"State":"MD","County":"Howard","City":"Laurel","Local Site Name":"Howard County","AQS ID":"24-027-0006","Latitude":39.143161,"Longitude":-76.845961,"Target Road":"I-95","Recent (>2016) HPMS AADT":199131.0,"Recent (>2016) Est. FE-AADT":482295.8151485943,"Orig. AADT (2012-2015)":186750,"Orig. AADT Rank in CBSA":13.0,"Orig. FE-AADT":452309,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":17.0,"Distance to nearest mainline (m)":17.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1396310400000,"CO Start Date":1396310400000,"Continuous PM2.5 Start Date":1396310400000,"Current Cont. PM2.5 method":"Met One BAM 1020","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1396310400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":1396656000000,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Birmingham-Hoover, AL","RO":4,"Population 2015":1145647,"Population 2020":1091921,"State":"AL","County":"Jefferson","City":"Birmingham","Local Site Name":"Arkadelphia","AQS ID":"01-073-2059","Latitude":33.521422,"Longitude":-86.844077,"Target Road":"I-20","Recent (>2016) HPMS AADT":126670.0,"Recent (>2016) Est. FE-AADT":193362.1721793328,"Orig. AADT (2012-2015)":141190,"Orig. AADT Rank in CBSA":4.0,"Orig. FE-AADT":215527,"Orig. FE-AADT Rank in CBSA":6.0,"Distance to nearest road travel feature (m)":25.0,"Distance to nearest mainline (m)":25.0,"NO2 Probe Height (m)":5.5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1388534400000,"CO Start Date":1388534400000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":1388534400000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"BGI Model PQ200 w\/ VSCC ","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1388534400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Boston-Cambridge-Newton, MA-NH","RO":1,"Population 2015":4774321,"Population 2020":4878211,"State":"MA","County":"Middlesex","City":"Chelmsford","Local Site Name":"Chelmsford Road","AQS ID":"25-017-0010","Latitude":42.61211,"Longitude":-71.307519,"Target Road":"I-495","Recent (>2016) HPMS AADT":124793.0,"Recent (>2016) Est. FE-AADT":null,"Orig. AADT (2012-2015)":130000,"Orig. AADT Rank in CBSA":null,"Orig. FE-AADT":null,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":23.0,"Distance to nearest mainline (m)":23.0,"NO2 Probe Height (m)":4.6,"Operational":"YES","Ops Info":null,"NO2 Start Date":1528675200000,"CO Start Date":null,"Continuous PM2.5 Start Date":1528416000000,"Current Cont. PM2.5 method":"TAPI T640","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Boston-Cambridge-Newton, MA-NH","RO":1,"Population 2015":4774321,"Population 2020":4878211,"State":"MA","County":"Suffolk","City":"Boston","Local Site Name":"Von Hillern Street","AQS ID":"25-025-0044","Latitude":42.325131,"Longitude":-71.056009,"Target Road":"I-93","Recent (>2016) HPMS AADT":205861.0,"Recent (>2016) Est. FE-AADT":261440.8427251953,"Orig. AADT (2012-2015)":198239,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":251761,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":10.0,"Distance to nearest mainline (m)":10.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1370044800000,"CO Start Date":1373155200000,"Continuous PM2.5 Start Date":1441065600000,"Current Cont. PM2.5 method":"Met One BAM 1020","FRM PM2.5 Start Date":1380585600000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":1393891200000,"BC instrument model":"TAPI 633"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1377734400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Buffalo-Cheektowaga-Niagara Falls, NY","RO":2,"Population 2015":1135230,"Population 2020":1125637,"State":"NY","County":"Erie","City":"Cheektowaga","Local Site Name":"Buffalo Near Road","AQS ID":"36-029-0023","Latitude":42.921334,"Longitude":-78.765837,"Target Road":"I-90","Recent (>2016) HPMS AADT":126107.0,"Recent (>2016) Est. FE-AADT":212274.6784893794,"Orig. AADT (2012-2015)":131019,"Orig. AADT Rank in CBSA":2.0,"Orig. FE-AADT":220543,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":20.0,"Distance to nearest mainline (m)":20.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1396310400000,"CO Start Date":1406851200000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":1404172800000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Charlotte-Concord-Gastonia, NC-SC","RO":4,"Population 2015":2426363,"Population 2020":2684276,"State":"NC","County":"Mecklenburg","City":"Charlotte","Local Site Name":"Remount Road","AQS ID":"37-119-0045","Latitude":35.213082,"Longitude":-80.874169,"Target Road":"I-77","Recent (>2016) HPMS AADT":138000.0,"Recent (>2016) Est. FE-AADT":220825.3987730062,"Orig. AADT (2012-2015)":163000,"Orig. AADT Rank in CBSA":11.0,"Orig. FE-AADT":260830,"Orig. FE-AADT Rank in CBSA":6.0,"Distance to nearest road travel feature (m)":36.0,"Distance to nearest mainline (m)":36.0,"NO2 Probe Height (m)":4.5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1405555200000,"CO Start Date":1483228800000,"Continuous PM2.5 Start Date":1522540800000,"Current Cont. PM2.5 method":"MetOne BAM 1022","FRM PM2.5 Start Date":1483228800000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1420070400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Chicago-Naperville-Elgin, IL-IN-WI","RO":5,"Population 2015":9551031,"Population 2020":9406638,"State":"IL","County":"Cook","City":"Lansing","Local Site Name":"Kingery Near Road","AQS ID":"17-031-0119","Latitude":41.578699,"Longitude":-87.557857,"Target Road":"I-80\/I-94","Recent (>2016) HPMS AADT":129000.0,"Recent (>2016) Est. FE-AADT":545922.6804123712,"Orig. AADT (2012-2015)":116400,"Orig. AADT Rank in CBSA":458.0,"Orig. FE-AADT":492600,"Orig. FE-AADT Rank in CBSA":8.0,"Distance to nearest road travel feature (m)":37.0,"Distance to nearest mainline (m)":37.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1551398400000,"CO Start Date":1551398400000,"Continuous PM2.5 Start Date":1551398400000,"Current Cont. PM2.5 method":"TAPI T640","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Chicago-Naperville-Elgin, IL-IN-WI","RO":5,"Population 2015":9551031,"Population 2020":9406638,"State":"IL","County":"Cook","City":"Chicago","Local Site Name":"Kennedy Near Road","AQS ID":"17-031-0219","Latitude":41.920681,"Longitude":-87.674425,"Target Road":"I-90\/I-94","Recent (>2016) HPMS AADT":292384.0,"Recent (>2016) Est. FE-AADT":null,"Orig. AADT (2012-2015)":330000,"Orig. AADT Rank in CBSA":8.0,"Orig. FE-AADT":null,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":27.7,"Distance to nearest mainline (m)":27.7,"NO2 Probe Height (m)":3.9,"Operational":"YES","Ops Info":null,"NO2 Start Date":1564099200000,"CO Start Date":null,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Cincinnati, OH-KY-IN","RO":5,"Population 2015":2157719,"Population 2020":2232907,"State":"OH","County":"Hamilton","City":"Cincinnati","Local Site Name":"Near Road","AQS ID":"39-061-0048","Latitude":39.146039,"Longitude":-84.538375,"Target Road":"I-75","Recent (>2016) HPMS AADT":152115.0,"Recent (>2016) Est. FE-AADT":360577.8754601227,"Orig. AADT (2012-2015)":163000,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":386380,"Orig. FE-AADT Rank in CBSA":8.0,"Distance to nearest road travel feature (m)":10.0,"Distance to nearest mainline (m)":10.0,"NO2 Probe Height (m)":4.7,"Operational":"YES","Ops Info":null,"NO2 Start Date":1388534400000,"CO Start Date":1406851200000,"Continuous PM2.5 Start Date":1483228800000,"Current Cont. PM2.5 method":"Thermo 5030 Sharp","FRM PM2.5 Start Date":1388534400000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"BGI Model PQ200 w\/ VSCC ","Black Carbon Start Date":1430438400000,"BC instrument model":"TAPI 633"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1388534400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Cleveland-Elyria, OH","RO":5,"Population 2015":2060810,"Population 2020":2043807,"State":"OH","County":"Cuyahoga","City":"Cleveland","Local Site Name":"ODOT-I-271","AQS ID":"39-035-0073","Latitude":41.440071,"Longitude":-81.49483,"Target Road":"I-271","Recent (>2016) HPMS AADT":181956.0,"Recent (>2016) Est. FE-AADT":340536.9418196017,"Orig. AADT (2012-2015)":153660,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":287580,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":34.0,"Distance to nearest mainline (m)":41.0,"NO2 Probe Height (m)":4.2,"Operational":"YES","Ops Info":null,"NO2 Start Date":1406851200000,"CO Start Date":1406851200000,"Continuous PM2.5 Start Date":1540857600000,"Current Cont. PM2.5 method":"TAPI T640","FRM PM2.5 Start Date":1491004800000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1406851200000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Columbus, OH","RO":5,"Population 2015":2021632,"Population 2020":2138946,"State":"OH","County":"Franklin","City":"Columbus","Local Site Name":"Smoky Row Near Road","AQS ID":"39-049-0038","Latitude":40.111084,"Longitude":-83.065415,"Target Road":"I-270","Recent (>2016) HPMS AADT":135746.0,"Recent (>2016) Est. FE-AADT":272758.2926503748,"Orig. AADT (2012-2015)":142361,"Orig. AADT Rank in CBSA":10.0,"Orig. FE-AADT":286050,"Orig. FE-AADT Rank in CBSA":4.0,"Distance to nearest road travel feature (m)":32.0,"Distance to nearest mainline (m)":32.0,"NO2 Probe Height (m)":5.3,"Operational":"YES","Ops Info":null,"NO2 Start Date":1388534400000,"CO Start Date":1388966400000,"Continuous PM2.5 Start Date":1538092800000,"Current Cont. PM2.5 method":"TAPI T640","FRM PM2.5 Start Date":1483228800000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1388534400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":"YES","CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Dallas-Fort Worth-Arlington, TX","RO":6,"Population 2015":7102796,"Population 2020":7694138,"State":"TX","County":"Dallas","City":"Dallas","Local Site Name":"LBJ Freeway I-635","AQS ID":"48-113-1067","Latitude":32.92118,"Longitude":-96.75355,"Target Road":"I-635","Recent (>2016) HPMS AADT":168815.0,"Recent (>2016) Est. FE-AADT":308595.8819500403,"Orig. AADT (2012-2015)":235790,"Orig. AADT Rank in CBSA":15.0,"Orig. FE-AADT":431027,"Orig. FE-AADT Rank in CBSA":8.0,"Distance to nearest road travel feature (m)":21.0,"Distance to nearest mainline (m)":85.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1396396800000,"CO Start Date":null,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Dallas-Fort Worth-Arlington, TX","RO":6,"Population 2015":7102796,"Population 2020":7694138,"State":"TX","County":"Tarrant","City":"Fort Worth","Local Site Name":"FTW Cal Pkwy I-20","AQS ID":"48-439-1053","Latitude":32.664753,"Longitude":-97.337934,"Target Road":"I-20","Recent (>2016) HPMS AADT":159040.0,"Recent (>2016) Est. FE-AADT":209139.1500974659,"Orig. AADT (2012-2015)":184680,"Orig. AADT Rank in CBSA":36.0,"Orig. FE-AADT":242856,"Orig. FE-AADT Rank in CBSA":90.0,"Distance to nearest road travel feature (m)":15.0,"Distance to nearest mainline (m)":38.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1426118400000,"CO Start Date":1426118400000,"Continuous PM2.5 Start Date":"7\/31\/019","Current Cont. PM2.5 method":"MetOne BAM 1022","FRM PM2.5 Start Date":1426982400000,"FRM PM2.5 Stop Date":1564444800000,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Denver-Aurora-Lakewood, CO","RO":8,"Population 2015":2814330,"Population 2020":2991231,"State":"CO","County":"Denver","City":"Denver","Local Site Name":"1-25 & 9th Avenue","AQS ID":"08-031-0027","Latitude":39.732123,"Longitude":-105.015324,"Target Road":"I-25","Recent (>2016) HPMS AADT":254000.0,"Recent (>2016) Est. FE-AADT":268401.4939759036,"Orig. AADT (2012-2015)":249000,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":263118,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":10.0,"Distance to nearest mainline (m)":13.0,"NO2 Probe Height (m)":5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1370044800000,"CO Start Date":1370044800000,"Continuous PM2.5 Start Date":1388534400000,"Current Cont. PM2.5 method":"Grimm 180","FRM PM2.5 Start Date":1388534400000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":1388620800000,"BC instrument model":"TAPI 633"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1370044800000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":"Continuous PM10LC Grimm","Coming Soon":null},{"CBSA Full Name":"Denver-Aurora-Lakewood, CO","RO":8,"Population 2015":2814330,"Population 2020":2991231,"State":"CO","County":"Denver","City":"Denver","Local Site Name":"Globeville","AQS ID":"08-031-0028","Latitude":39.7859,"Longitude":-104.98888,"Target Road":"I-25","Recent (>2016) HPMS AADT":230000.0,"Recent (>2016) Est. FE-AADT":252562.7604166667,"Orig. AADT (2012-2015)":192000,"Orig. AADT Rank in CBSA":23.0,"Orig. FE-AADT":210835,"Orig. FE-AADT Rank in CBSA":19.0,"Distance to nearest road travel feature (m)":8.0,"Distance to nearest mainline (m)":16.0,"NO2 Probe Height (m)":5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1443657600000,"CO Start Date":null,"Continuous PM2.5 Start Date":1444694400000,"Current Cont. PM2.5 method":"Grimm 180","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1444694400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Detroit-Warren-Dearborn, MI","RO":5,"Population 2015":4302043,"Population 2020":4304136,"State":"MI","County":"Wayne","City":"Detroit","Local Site Name":"Eliza Howell #1","AQS ID":"26-163-0093","Latitude":42.385994,"Longitude":-83.266308,"Target Road":"I-96","Recent (>2016) HPMS AADT":156800.0,"Recent (>2016) Est. FE-AADT":210033.8790035587,"Orig. AADT (2012-2015)":140500,"Orig. AADT Rank in CBSA":null,"Orig. FE-AADT":188200,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":8.0,"Distance to nearest mainline (m)":8.0,"NO2 Probe Height (m)":5.2,"Operational":"YES","Ops Info":null,"NO2 Start Date":1317427200000,"CO Start Date":1317427200000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1314835200000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Fresno, CA","RO":9,"Population 2015":974861,"Population 2020":1000918,"State":"CA","County":"Fresno","City":"Fresno","Local Site Name":"Foundry","AQS ID":"06-019-2016","Latitude":36.710885,"Longitude":-119.777435,"Target Road":"CA 99","Recent (>2016) HPMS AADT":114000.0,"Recent (>2016) Est. FE-AADT":278877.0967741936,"Orig. AADT (2012-2015)":93000,"Orig. AADT Rank in CBSA":16.0,"Orig. FE-AADT":227505,"Orig. FE-AADT Rank in CBSA":4.0,"Distance to nearest road travel feature (m)":20.0,"Distance to nearest mainline (m)":20.0,"NO2 Probe Height (m)":5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1451606400000,"CO Start Date":1577836800000,"Continuous PM2.5 Start Date":1577836800000,"Current Cont. PM2.5 method":"Met One BAM 1020","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1451606400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Hartford-West Hartford-East Hartford, CT","RO":1,"Population 2015":1211324,"Population 2020":1201483,"State":"CT","County":"Hartford","City":"Hartford","Local Site Name":"Huntley Place","AQS ID":"09-003-0025","Latitude":41.771458,"Longitude":-72.679923,"Target Road":"I-84","Recent (>2016) HPMS AADT":164300.0,"Recent (>2016) Est. FE-AADT":238235.0,"Orig. AADT (2012-2015)":159900,"Orig. AADT Rank in CBSA":2.0,"Orig. FE-AADT":231855,"Orig. FE-AADT Rank in CBSA":2.0,"Distance to nearest road travel feature (m)":8.0,"Distance to nearest mainline (m)":21.0,"NO2 Probe Height (m)":3.6,"Operational":"YES","Ops Info":null,"NO2 Start Date":1364774400000,"CO Start Date":1364774400000,"Continuous PM2.5 Start Date":1364774400000,"Current Cont. PM2.5 method":"Met One BAM 1020","FRM PM2.5 Start Date":1394064000000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"TEI 20205i","Black Carbon Start Date":1364860800000,"BC instrument model":"TAPI 633"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1365465600000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":1372291200000,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Houston-The Woodlands-Sugar Land, TX","RO":6,"Population 2015":6656947,"Population 2020":7154478,"State":"TX","County":"Harris","City":"Houston","Local Site Name":"HOU North Loop I-610","AQS ID":"48-201-1052","Latitude":29.814374,"Longitude":-95.387795,"Target Road":"I-610","Recent (>2016) HPMS AADT":193105.0,"Recent (>2016) Est. FE-AADT":319977.0486592123,"Orig. AADT (2012-2015)":202120,"Orig. AADT Rank in CBSA":46.0,"Orig. FE-AADT":334915,"Orig. FE-AADT Rank in CBSA":46.0,"Distance to nearest road travel feature (m)":19.0,"Distance to nearest mainline (m)":19.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1429056000000,"CO Start Date":1429056000000,"Continuous PM2.5 Start Date":1620777600000,"Current Cont. PM2.5 method":"MetOne BAM 1022","FRM PM2.5 Start Date":1428883200000,"FRM PM2.5 Stop Date":1431302400000,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Houston-The Woodlands-Sugar Land, TX","RO":6,"Population 2015":6656947,"Population 2020":7154478,"State":"TX","County":"Harris","City":"Houston","Local Site Name":"SW Freeway I-69","AQS ID":"48-201-1066","Latitude":29.721644,"Longitude":-95.492652,"Target Road":"I-69\/US 59","Recent (>2016) HPMS AADT":256556.0,"Recent (>2016) Est. FE-AADT":392787.08639728,"Orig. AADT (2012-2015)":324119,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":496226,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":23.0,"Distance to nearest mainline (m)":38.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1390348800000,"CO Start Date":null,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Indianapolis-Carmel-Anderson, IN","RO":5,"Population 2015":1988817,"Population 2020":2091019,"State":"IN","County":"Marion","City":"Indianapolis","Local Site Name":"Indianapolis I-70E","AQS ID":"18-097-0087","Latitude":39.787929,"Longitude":-86.130913,"Target Road":"I-70","Recent (>2016) HPMS AADT":165672.0,"Recent (>2016) Est. FE-AADT":316144.01306914,"Orig. AADT (2012-2015)":189760,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":362110,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":25.0,"Distance to nearest mainline (m)":25.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1396310400000,"CO Start Date":1398902400000,"Continuous PM2.5 Start Date":1451606400000,"Current Cont. PM2.5 method":"TAPI T640","FRM PM2.5 Start Date":1391212800000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":1430956800000,"BC instrument model":"Magee AE22"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1400025600000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Jacksonville, FL","RO":4,"Population 2015":1449481,"Population 2020":1587892,"State":"FL","County":"Duval","City":"Jacksonville","Local Site Name":"Pepsi Place","AQS ID":"12-031-0108","Latitude":30.262736,"Longitude":-81.606832,"Target Road":"I-95","Recent (>2016) HPMS AADT":146000.0,"Recent (>2016) Est. FE-AADT":319374.4748201439,"Orig. AADT (2012-2015)":139000,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":304062,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":22.0,"Distance to nearest mainline (m)":35.0,"NO2 Probe Height (m)":4.6,"Operational":"YES","Ops Info":null,"NO2 Start Date":1388534400000,"CO Start Date":1388534400000,"Continuous PM2.5 Start Date":1388534400000,"Current Cont. PM2.5 method":" Thermo 5014i","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Kansas City, MO-KS","RO":7,"Population 2015":2087471,"Population 2020":2173212,"State":"MO","County":"Jackson","City":"Kansas City","Local Site Name":"Blue Ridge","AQS ID":"29-095-0042","Latitude":39.04791,"Longitude":-94.450543,"Target Road":"I-70","Recent (>2016) HPMS AADT":119477.0,"Recent (>2016) Est. FE-AADT":362706.2720118782,"Orig. AADT (2012-2015)":114495,"Orig. AADT Rank in CBSA":5.0,"Orig. FE-AADT":347582,"Orig. FE-AADT Rank in CBSA":3.0,"Distance to nearest road travel feature (m)":34.0,"Distance to nearest mainline (m)":34.0,"NO2 Probe Height (m)":4.5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1372636800000,"CO Start Date":1372636800000,"Continuous PM2.5 Start Date":1372636800000,"Current Cont. PM2.5 method":"Thermo 1405-DF","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":1372636800000,"BC instrument model":"TAPI 633"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1372636800000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Las Vegas-Henderson-Paradise, NV","RO":9,"Population 2015":2114801,"Population 2020":2315963,"State":"NV","County":"Clark","City":"Las Vegas","Local Site Name":"Rancho & Teddy","AQS ID":"32-003-1501\u00a0","Latitude":36.13972,"Longitude":-115.175653,"Target Road":"I-15","Recent (>2016) HPMS AADT":297000.0,"Recent (>2016) Est. FE-AADT":404177.0192307692,"Orig. AADT (2012-2015)":260000,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":353825,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":18.0,"Distance to nearest mainline (m)":18.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1438387200000,"CO Start Date":1483228800000,"Continuous PM2.5 Start Date":1483228800000,"Current Cont. PM2.5 method":"TAPI T640X","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Las Vegas-Henderson-Paradise, NV","RO":9,"Population 2015":2114801,"Population 2020":2315963,"State":"NV","County":"Clark","City":"Las Vegas","Local Site Name":"Casino Center","AQS ID":"32-003-1502\u00a0","Latitude":36.174351,"Longitude":-115.139741,"Target Road":"US 95","Recent (>2016) HPMS AADT":164000.0,"Recent (>2016) Est. FE-AADT":207654.5762711865,"Orig. AADT (2012-2015)":177000,"Orig. AADT Rank in CBSA":10.0,"Orig. FE-AADT":224115,"Orig. FE-AADT Rank in CBSA":12.0,"Distance to nearest road travel feature (m)":9.0,"Distance to nearest mainline (m)":20.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1467331200000,"CO Start Date":null,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1441065600000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Los Angeles-Long Beach-Anaheim, CA","RO":9,"Population 2015":13340068,"Population 2020":13109903,"State":"CA","County":"Los Angeles","City":"Long Beach","Local Site Name":"Long Beach Route 710 Near Road","AQS ID":"06-037-4008","Latitude":33.859701,"Longitude":-118.200719,"Target Road":"I-710","Recent (>2016) HPMS AADT":190000.0,"Recent (>2016) Est. FE-AADT":612560.0,"Orig. AADT (2012-2015)":192000,"Orig. AADT Rank in CBSA":104.0,"Orig. FE-AADT":619008,"Orig. FE-AADT Rank in CBSA":19.0,"Distance to nearest road travel feature (m)":17.5,"Distance to nearest mainline (m)":24.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1427846400000,"CO Start Date":null,"Continuous PM2.5 Start Date":1451606400000,"Current Cont. PM2.5 method":" Thermo 5014i","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":1420070400000,"BC instrument model":"Magee AE22"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1420070400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Los Angeles-Long Beach-Anaheim, CA","RO":9,"Population 2015":13340068,"Population 2020":13109903,"State":"CA","County":"Orange","City":"Anaheim","Local Site Name":"Anaheim Route 5 Near Road","AQS ID":"06-059-0008","Latitude":33.819318,"Longitude":-117.918775,"Target Road":"I-5","Recent (>2016) HPMS AADT":276300.0,"Recent (>2016) Est. FE-AADT":706775.4,"Orig. AADT (2012-2015)":272000,"Orig. AADT Rank in CBSA":32.0,"Orig. FE-AADT":695776,"Orig. FE-AADT Rank in CBSA":3.0,"Distance to nearest road travel feature (m)":8.0,"Distance to nearest mainline (m)":8.0,"NO2 Probe Height (m)":4.5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1388534400000,"CO Start Date":1420070400000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Louisville\/Jefferson County, KY-IN","RO":4,"Population 2015":1278413,"Population 2020":1268993,"State":"KY","County":"Jefferson","City":"Louisville","Local Site Name":"Durrett Lane","AQS ID":"21-111-0075","Latitude":38.19364,"Longitude":-85.711943,"Target Road":"I-264","Recent (>2016) HPMS AADT":188697.0,"Recent (>2016) Est. FE-AADT":286634.2159509202,"Orig. AADT (2012-2015)":163000,"Orig. AADT Rank in CBSA":2.0,"Orig. FE-AADT":247600,"Orig. FE-AADT Rank in CBSA":8.0,"Distance to nearest road travel feature (m)":33.0,"Distance to nearest mainline (m)":33.0,"NO2 Probe Height (m)":4.7,"Operational":"YES","Ops Info":null,"NO2 Start Date":1392768000000,"CO Start Date":1389657600000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":1388534400000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1389657600000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Memphis, TN-MS-AR","RO":4,"Population 2015":1344127,"Population 2020":1348678,"State":"TN","County":"Shelby","City":"Memphis","Local Site Name":"Southwest Tennessee CC","AQS ID":"47-157-0100","Latitude":35.161238,"Longitude":-89.870692,"Target Road":"I-40","Recent (>2016) HPMS AADT":157380.0,"Recent (>2016) Est. FE-AADT":327350.4,"Orig. AADT (2012-2015)":140850,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":292968,"Orig. FE-AADT Rank in CBSA":2.0,"Distance to nearest road travel feature (m)":22.0,"Distance to nearest mainline (m)":22.0,"NO2 Probe Height (m)":4.3,"Operational":"YES","Ops Info":null,"NO2 Start Date":1404172800000,"CO Start Date":1405382400000,"Continuous PM2.5 Start Date":1546300800000,"Current Cont. PM2.5 method":"TAPI T640","FRM PM2.5 Start Date":1483228800000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Miami-Fort Lauderdale-West Palm Beach, FL","RO":4,"Population 2015":6012331,"Population 2020":6173008,"State":"FL","County":"Broward","City":"Fort Lauderdale","Local Site Name":"Ft Lauderdale NR","AQS ID":"12-011-0035","Latitude":26.132734,"Longitude":-80.169764,"Target Road":"I-95","Recent (>2016) HPMS AADT":300000.0,"Recent (>2016) Est. FE-AADT":609961.7647058824,"Orig. AADT (2012-2015)":306000,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":622161,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":12.0,"Distance to nearest mainline (m)":12.0,"NO2 Probe Height (m)":4.5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1440115200000,"CO Start Date":1440115200000,"Continuous PM2.5 Start Date":1459468800000,"Current Cont. PM2.5 method":" Thermo 5014i","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":1459468800000,"BC instrument model":"TAPI 633"," Ultrafine Particulate Start Date":1459468800000,"Ultrafine Particulate Method":"TSI 3031","Meteorology Start Date":1459468800000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Miami-Fort Lauderdale-West Palm Beach, FL","RO":4,"Population 2015":6012331,"Population 2020":6173008,"State":"FL","County":"Dade","City":"Miami","Local Site Name":"Perimiter Rd MDX","AQS ID":"12-086-0035","Latitude":25.785397,"Longitude":-80.284247,"Target Road":"FL-836","Recent (>2016) HPMS AADT":184000.0,"Recent (>2016) Est. FE-AADT":389712.0,"Orig. AADT (2012-2015)":162000,"Orig. AADT Rank in CBSA":17.0,"Orig. FE-AADT":343116,"Orig. FE-AADT Rank in CBSA":13.0,"Distance to nearest road travel feature (m)":17.0,"Distance to nearest mainline (m)":21.0,"NO2 Probe Height (m)":4.6,"Operational":"YES","Ops Info":null,"NO2 Start Date":1484092800000,"CO Start Date":null,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Milwaukee-Waukesha-West Allis, WI","RO":5,"Population 2015":1575747,"Population 2020":1577676,"State":"WI","County":"Milwaukee","City":"Milwaukee","Local Site Name":"Millwaukee College Ave","AQS ID":"55-079-0056","Latitude":42.932639,"Longitude":-87.934389,"Target Road":"I-94","Recent (>2016) HPMS AADT":161167.0,"Recent (>2016) Est. FE-AADT":161167.0,"Orig. AADT (2012-2015)":133000,"Orig. AADT Rank in CBSA":4.0,"Orig. FE-AADT":133000,"Orig. FE-AADT Rank in CBSA":4.0,"Distance to nearest road travel feature (m)":19.0,"Distance to nearest mainline (m)":53.0,"NO2 Probe Height (m)":3.5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1388534400000,"CO Start Date":1388534400000,"Continuous PM2.5 Start Date":1483228800000,"Current Cont. PM2.5 method":238,"FRM PM2.5 Start Date":1484179200000,"FRM PM2.5 Stop Date":1522368000000,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1388534400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Minneapolis-St. Paul-Bloomington, MN-WI","RO":5,"Population 2015":3524583,"Population 2020":3657477,"State":"MN","County":"Dakota","City":"Lakeville","Local Site Name":"Near Road Lakeville","AQS ID":"27-037-0480","Latitude":44.706123,"Longitude":-93.285803,"Target Road":"I-35","Recent (>2016) HPMS AADT":83000.0,"Recent (>2016) Est. FE-AADT":184317.2413793104,"Orig. AADT (2012-2015)":87000,"Orig. AADT Rank in CBSA":169.0,"Orig. FE-AADT":193200,"Orig. FE-AADT Rank in CBSA":56.0,"Distance to nearest road travel feature (m)":34.0,"Distance to nearest mainline (m)":34.0,"NO2 Probe Height (m)":4.6,"Operational":"YES","Ops Info":null,"NO2 Start Date":1420070400000,"CO Start Date":1420070400000,"Continuous PM2.5 Start Date":1420070400000,"Current Cont. PM2.5 method":"Met One BAM 1020","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1420070400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Minneapolis-St. Paul-Bloomington, MN-WI","RO":5,"Population 2015":3524583,"Population 2020":3657477,"State":"MN","County":"Hennepin","City":"Minneapolis","Local Site Name":"Near Road Minneapolis","AQS ID":"27-053-0962","Latitude":44.965256,"Longitude":-93.254768,"Target Road":"I-94\/I-35W","Recent (>2016) HPMS AADT":250000.0,"Recent (>2016) Est. FE-AADT":349503.6101083033,"Orig. AADT (2012-2015)":277000,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":387250,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":16.0,"Distance to nearest mainline (m)":35.0,"NO2 Probe Height (m)":4.9,"Operational":"YES","Ops Info":null,"NO2 Start Date":1364774400000,"CO Start Date":1356998400000,"Continuous PM2.5 Start Date":1380585600000,"Current Cont. PM2.5 method":"Met One BAM 1020","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1364774400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":"YES","CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Nashville-Davidson--Murfreesboro--Franklin, TN","RO":4,"Population 2015":1830345,"Population 2020":1961232,"State":"TN","County":"Davidson","City":"Nashville","Local Site Name":"Near Road","AQS ID":"47-037-0040","Latitude":36.142377,"Longitude":-86.734162,"Target Road":"I-40\/I-24","Recent (>2016) HPMS AADT":156920.0,"Recent (>2016) Est. FE-AADT":368761.5647277468,"Orig. AADT (2012-2015)":144204,"Orig. AADT Rank in CBSA":14.0,"Orig. FE-AADT":338879,"Orig. FE-AADT Rank in CBSA":12.0,"Distance to nearest road travel feature (m)":28.0,"Distance to nearest mainline (m)":28.0,"NO2 Probe Height (m)":4.5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1404172800000,"CO Start Date":1404172800000,"Continuous PM2.5 Start Date":1561939200000,"Current Cont. PM2.5 method":"MetOne BAM 1022","FRM PM2.5 Start Date":1483228800000,"FRM PM2.5 Stop Date":1594166400000,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":1577836800000,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"New Orleans-Metairie, LA","RO":6,"Population 2015":1262888,"Population 2020":1272258,"State":"LA","County":"Orleans","City":"New Orleans","Local Site Name":"I-610","AQS ID":"22-071-0021","Latitude":29.995955,"Longitude":-90.118201,"Target Road":"I-610","Recent (>2016) HPMS AADT":98800.0,"Recent (>2016) Est. FE-AADT":187720.7263103727,"Orig. AADT (2012-2015)":68015,"Orig. AADT Rank in CBSA":23.0,"Orig. FE-AADT":129229,"Orig. FE-AADT Rank in CBSA":23.0,"Distance to nearest road travel feature (m)":32.0,"Distance to nearest mainline (m)":32.0,"NO2 Probe Height (m)":4.22,"Operational":"YES","Ops Info":null,"NO2 Start Date":1395187200000,"CO Start Date":1420070400000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":1417564800000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1424995200000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":1458000000000,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"New York-Newark-Jersey City, NY-NJ-PA","RO":2,"Population 2015":20182305,"Population 2020":19124359,"State":"NJ","County":"Bergen","City":"Fort Lee","Local Site Name":"Fort Lee Near Road","AQS ID":"34-003-0010","Latitude":40.85355,"Longitude":-73.9661,"Target Road":"I-95\/US 1","Recent (>2016) HPMS AADT":282912.0,"Recent (>2016) Est. FE-AADT":556501.2863119068,"Orig. AADT (2012-2015)":311234,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":612212,"Orig. FE-AADT Rank in CBSA":11.0,"Distance to nearest road travel feature (m)":22.0,"Distance to nearest mainline (m)":22.0,"NO2 Probe Height (m)":4.6,"Operational":"YES","Ops Info":null,"NO2 Start Date":1396310400000,"CO Start Date":1396310400000,"Continuous PM2.5 Start Date":1420070400000,"Current Cont. PM2.5 method":"Met One BAM 1022","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"New York-Newark-Jersey City, NY-NJ-PA","RO":2,"Population 2015":20182305,"Population 2020":19124359,"State":"NY","County":"Queens","City":"Queens","Local Site Name":"Queens College Near Road","AQS ID":"36-081-0125","Latitude":40.739275,"Longitude":-73.817672,"Target Road":"I-495 (L.I.E.)","Recent (>2016) HPMS AADT":170874.0,"Recent (>2016) Est. FE-AADT":330809.6971846651,"Orig. AADT (2012-2015)":166339,"Orig. AADT Rank in CBSA":null,"Orig. FE-AADT":322030,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":7.0,"Distance to nearest mainline (m)":29.0,"NO2 Probe Height (m)":3.5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1491004800000,"CO Start Date":1491004800000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":1491004800000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":1491004800000,"Ultrafine Particulate Method":"TAPI 651","Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":1491004800000,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":"Carbonyls","Coming Soon":null},{"CBSA Full Name":"Oklahoma City, OK","RO":6,"Population 2015":1358452,"Population 2020":1425375,"State":"OK","County":"Oklahoma","City":"Oklahoma City","Local Site Name":"Near Road I-44","AQS ID":"40-109-0097","Latitude":35.50298,"Longitude":-97.57766,"Target Road":"I-44","Recent (>2016) HPMS AADT":165000.0,"Recent (>2016) Est. FE-AADT":207768.2549903413,"Orig. AADT (2012-2015)":155300,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":195554,"Orig. FE-AADT Rank in CBSA":7.0,"Distance to nearest road travel feature (m)":13.0,"Distance to nearest mainline (m)":20.0,"NO2 Probe Height (m)":3.96,"Operational":"YES","Ops Info":null,"NO2 Start Date":1427673600000,"CO Start Date":1434499200000,"Continuous PM2.5 Start Date":1522540800000,"Current Cont. PM2.5 method":"TAPI T640","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Philadelphia-Camden-Wilmington, PA-NJ-DE-MD","RO":3,"Population 2015":6069875,"Population 2020":6107906,"State":"PA","County":"Philadelphia","City":"Philadelphia","Local Site Name":"Torresdale","AQS ID":"42-101-0075","Latitude":40.054161,"Longitude":-74.985202,"Target Road":"I-95","Recent (>2016) HPMS AADT":118498.0,"Recent (>2016) Est. FE-AADT":244831.8359682208,"Orig. AADT (2012-2015)":124610,"Orig. AADT Rank in CBSA":6.0,"Orig. FE-AADT":257460,"Orig. FE-AADT Rank in CBSA":4.0,"Distance to nearest road travel feature (m)":14.0,"Distance to nearest mainline (m)":14.0,"NO2 Probe Height (m)":5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1388534400000,"CO Start Date":1388534400000,"Continuous PM2.5 Start Date":1585699200000,"Current Cont. PM2.5 method":"TAPI T640","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1404172800000,"Ozone Start Date":1427846400000,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Philadelphia-Camden-Wilmington, PA-NJ-DE-MD","RO":3,"Population 2015":6069875,"Population 2020":6107906,"State":"PA","County":"Philadelphia","City":"Philadelphia","Local Site Name":"Car-Barn Montgomery I-76","AQS ID":"42-101-0076","Latitude":39.9888,"Longitude":-75.207293,"Target Road":"I-76","Recent (>2016) HPMS AADT":210456.0,"Recent (>2016) Est. FE-AADT":344928.9021974122,"Orig. AADT (2012-2015)":154955,"Orig. AADT Rank in CBSA":5.0,"Orig. FE-AADT":253965,"Orig. FE-AADT Rank in CBSA":3.0,"Distance to nearest road travel feature (m)":18.0,"Distance to nearest mainline (m)":25.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1435708800000,"CO Start Date":1483228800000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":1443657600000,"BC instrument model":null," Ultrafine Particulate Start Date":1443657600000,"Ultrafine Particulate Method":null,"Meteorology Start Date":1435708800000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":"TSP, BaP","Coming Soon":null},{"CBSA Full Name":"Phoenix-Mesa-Scottsdale, AZ","RO":9,"Population 2015":4574531,"Population 2020":5059909,"State":"AZ","County":"Maricopa","City":"Phoenix","Local Site Name":"Thirty-third","AQS ID":"04-013-4020","Latitude":33.461742,"Longitude":-112.127921,"Target Road":"I-10","Recent (>2016) HPMS AADT":250030.0,"Recent (>2016) Est. FE-AADT":471769.4788110834,"Orig. AADT (2012-2015)":260136,"Orig. AADT Rank in CBSA":17.0,"Orig. FE-AADT":490838,"Orig. FE-AADT Rank in CBSA":13.0,"Distance to nearest road travel feature (m)":17.0,"Distance to nearest mainline (m)":17.0,"NO2 Probe Height (m)":"7\u00a0","Operational":"YES","Ops Info":null,"NO2 Start Date":1441065600000,"CO Start Date":1577836800000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1441065600000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Phoenix-Mesa-Scottsdale, AZ","RO":9,"Population 2015":4574531,"Population 2020":5059909,"State":"AZ","County":"Maricopa","City":"Tempe","Local Site Name":"Eastwood","AQS ID":"04-013-4021","Latitude":33.41046,"Longitude":-112.00264,"Target Road":"I-10","Recent (>2016) HPMS AADT":null,"Recent (>2016) Est. FE-AADT":null,"Orig. AADT (2012-2015)":null,"Orig. AADT Rank in CBSA":null,"Orig. FE-AADT":null,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":23.5,"Distance to nearest mainline (m)":23.5,"NO2 Probe Height (m)":4.27,"Operational":"YES","Ops Info":"Replaced Diablo site.","NO2 Start Date":1614902400000,"CO Start Date":1614902400000,"Continuous PM2.5 Start Date":1614902400000,"Current Cont. PM2.5 method":"Thermo 1405-DF","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1615852800000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Pittsburgh, PA","RO":3,"Population 2015":2353045,"Population 2020":2309246,"State":"PA","County":"Allegheny","City":"Wilkinsburg","Local Site Name":"Parkway East Near Road","AQS ID":"42-003-1376","Latitude":40.43746,"Longitude":-79.863545,"Target Road":"I-376","Recent (>2016) HPMS AADT":74421.0,"Recent (>2016) Est. FE-AADT":126039.7606415793,"Orig. AADT (2012-2015)":87534,"Orig. AADT Rank in CBSA":3.0,"Orig. FE-AADT":148248,"Orig. FE-AADT Rank in CBSA":4.0,"Distance to nearest road travel feature (m)":18.0,"Distance to nearest mainline (m)":23.0,"NO2 Probe Height (m)":3,"Operational":"YES","Ops Info":null,"NO2 Start Date":1409529600000,"CO Start Date":1409529600000,"Continuous PM2.5 Start Date":1451606400000,"Current Cont. PM2.5 method":"Thermo 5014i","FRM PM2.5 Start Date":1609459200000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":1409529600000,"BC instrument model":"TAPI 633"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1409529600000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Portland-Vancouver-Hillsboro, OR-WA","RO":10,"Population 2015":2389228,"Population 2020":2510259,"State":"OR","County":"Washington","City":"Portland","Local Site Name":"TBC Near Road","AQS ID":"41-067-0005","Latitude":45.39922,"Longitude":-122.745518,"Target Road":"I-5","Recent (>2016) HPMS AADT":162700.0,"Recent (>2016) Est. FE-AADT":301466.4128205128,"Orig. AADT (2012-2015)":156000,"Orig. AADT Rank in CBSA":5.0,"Orig. FE-AADT":289052,"Orig. FE-AADT Rank in CBSA":4.0,"Distance to nearest road travel feature (m)":16.0,"Distance to nearest mainline (m)":24.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1398902400000,"CO Start Date":1398902400000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":1398038400000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":1404691200000,"BC instrument model":"Magee AE21"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1429574400000,"Ozone Start Date":1429574400000,"Toxics\/ VOCs Start Date":"YES","CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Providence-Warwick, RI-MA","RO":1,"Population 2015":1613070,"Population 2020":1623890,"State":"RI","County":"Providence","City":"Providence","Local Site Name":"Hayes\/ Park Street","AQS ID":"44-007-0030","Latitude":41.829526,"Longitude":-71.417595,"Target Road":"I-95","Recent (>2016) HPMS AADT":159500.0,"Recent (>2016) Est. FE-AADT":356833.0917874397,"Orig. AADT (2012-2015)":186300,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":416790,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":5.0,"Distance to nearest mainline (m)":5.0,"NO2 Probe Height (m)":3.9,"Operational":"YES","Ops Info":null,"NO2 Start Date":1396310400000,"CO Start Date":1396310400000,"Continuous PM2.5 Start Date":1396310400000,"Current Cont. PM2.5 method":"Met One BAM 1020","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":1396310400000,"BC instrument model":"Magee AE 1600"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Raleigh, NC","RO":4,"Population 2015":1273568,"Population 2020":1420376,"State":"NC","County":"Wake","City":"Raleigh","Local Site Name":"Triple Oak","AQS ID":"37-183-0021","Latitude":35.865155,"Longitude":-78.819673,"Target Road":"I-40","Recent (>2016) HPMS AADT":158000.0,"Recent (>2016) Est. FE-AADT":227788.9361702127,"Orig. AADT (2012-2015)":141000,"Orig. AADT Rank in CBSA":3.0,"Orig. FE-AADT":203280,"Orig. FE-AADT Rank in CBSA":3.0,"Distance to nearest road travel feature (m)":19.0,"Distance to nearest mainline (m)":19.0,"NO2 Probe Height (m)":4.3,"Operational":"YES","Ops Info":null,"NO2 Start Date":1389139200000,"CO Start Date":1480550400000,"Continuous PM2.5 Start Date":1483488000000,"Current Cont. PM2.5 method":"MetOne BAM 1022","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Richmond, VA","RO":3,"Population 2015":1271334,"Population 2020":1303469,"State":"VA","County":"City of Richmond","City":"Richmond","Local Site Name":"Bryan Park","AQS ID":"51-760-0025","Latitude":37.590821,"Longitude":-77.469326,"Target Road":"I-95","Recent (>2016) HPMS AADT":159954.0,"Recent (>2016) Est. FE-AADT":275120.88,"Orig. AADT (2012-2015)":151000,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":259720,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":17.0,"Distance to nearest mainline (m)":17.0,"NO2 Probe Height (m)":3.3,"Operational":"YES","Ops Info":null,"NO2 Start Date":1380585600000,"CO Start Date":1380585600000,"Continuous PM2.5 Start Date":1420070400000,"Current Cont. PM2.5 method":"Thermo 5014i","FRM PM2.5 Start Date":1468454400000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Riverside-San Bernardino-Ontario, CA","RO":9,"Population 2015":4489159,"Population 2020":4678371,"State":"CA","County":"San Bernardino","City":"Ontario","Local Site Name":"Ontario Etiwanda Near Road","AQS ID":"06-071-0026\u00a0","Latitude":34.06813,"Longitude":-117.525771,"Target Road":"I-10","Recent (>2016) HPMS AADT":250000.0,"Recent (>2016) Est. FE-AADT":659196.9017529555,"Orig. AADT (2012-2015)":245300,"Orig. AADT Rank in CBSA":6.0,"Orig. FE-AADT":646804,"Orig. FE-AADT Rank in CBSA":3.0,"Distance to nearest road travel feature (m)":23.0,"Distance to nearest mainline (m)":40.0,"NO2 Probe Height (m)":4.5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1420070400000,"CO Start Date":1420070400000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1420070400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Riverside-San Bernardino-Ontario, CA","RO":9,"Population 2015":4489159,"Population 2020":4678371,"State":"CA","County":"San Bernardino","City":"Ontario","Local Site Name":"Ontario Route 60 Near Road","AQS ID":"06-071-0027\u00a0","Latitude":34.03091,"Longitude":-117.617439,"Target Road":"SR-60","Recent (>2016) HPMS AADT":217000.0,"Recent (>2016) Est. FE-AADT":631556.8,"Orig. AADT (2012-2015)":215000,"Orig. AADT Rank in CBSA":14.0,"Orig. FE-AADT":625736,"Orig. FE-AADT Rank in CBSA":5.0,"Distance to nearest road travel feature (m)":18.0,"Distance to nearest mainline (m)":18.0,"NO2 Probe Height (m)":3,"Operational":"YES","Ops Info":null,"NO2 Start Date":1438387200000,"CO Start Date":null,"Continuous PM2.5 Start Date":1438387200000,"Current Cont. PM2.5 method":" Thermo 5014i","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1438387200000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Rochester, NY","RO":2,"Population 2015":1081954,"Population 2020":1067486,"State":"NY","County":"Monroe","City":"Rochester","Local Site Name":"Rochester Near Road","AQS ID":"36-055-0015","Latitude":43.144985,"Longitude":-77.557605,"Target Road":"I-490","Recent (>2016) HPMS AADT":98306.0,"Recent (>2016) Est. FE-AADT":128178.6593566988,"Orig. AADT (2012-2015)":110990,"Orig. AADT Rank in CBSA":3.0,"Orig. FE-AADT":144717,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":4.0,"Distance to nearest mainline (m)":11.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1418860800000,"CO Start Date":1418860800000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":1420502400000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Sacramento--Roseville--Arden-Arcade, CA","RO":9,"Population 2015":2274194,"Population 2020":2374749,"State":"CA","County":"Sacramento","City":"Sacramento","Local Site Name":"Bercut Dr.","AQS ID":"06-067-0015","Latitude":38.593328,"Longitude":-121.503728,"Target Road":"I-5","Recent (>2016) HPMS AADT":190800.0,"Recent (>2016) Est. FE-AADT":487258.064516129,"Orig. AADT (2012-2015)":186000,"Orig. AADT Rank in CBSA":9.0,"Orig. FE-AADT":475000,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":23.0,"Distance to nearest mainline (m)":23.0,"NO2 Probe Height (m)":5.3,"Operational":"YES","Ops Info":null,"NO2 Start Date":1444694400000,"CO Start Date":1444694400000,"Continuous PM2.5 Start Date":1609286400000,"Current Cont. PM2.5 method":"Met One BAM 1020","FRM PM2.5 Start Date":1477958400000,"FRM PM2.5 Stop Date":1608595200000,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":1477958400000,"BC instrument model":"Andersen RTAA-800"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Salt Lake City, UT","RO":8,"Population 2015":1170266,"Population 2020":1240029,"State":"UT","County":"Salt Lake","City":"Murray","Local Site Name":"SLC Near Road","AQS ID":"49-035-4002","Latitude":40.66172,"Longitude":-111.90179,"Target Road":"I-15","Recent (>2016) HPMS AADT":227379.0,"Recent (>2016) Est. FE-AADT":513876.54,"Orig. AADT (2012-2015)":227000,"Orig. AADT Rank in CBSA":null,"Orig. FE-AADT":513020,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":12.0,"Distance to nearest mainline (m)":12.0,"NO2 Probe Height (m)":5,"Operational":"YES","Ops Info":"AQS changed to SLAMS 03\/10\/2022","NO2 Start Date":1546300800000,"CO Start Date":1546300800000,"Continuous PM2.5 Start Date":1546300800000,"Current Cont. PM2.5 method":"Thermo 5030 Sharp","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":1546300800000,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":1546300800000,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"San Antonio-New Braunfels, TX","RO":6,"Population 2015":2384075,"Population 2020":2590732,"State":"TX","County":"Bexar","City":"San Antonio","Local Site Name":"I-35","AQS ID":"48-029-1069","Latitude":29.529448,"Longitude":-98.391439,"Target Road":"I-35","Recent (>2016) HPMS AADT":211409.0,"Recent (>2016) Est. FE-AADT":424509.5652744748,"Orig. AADT (2012-2015)":201840,"Orig. AADT Rank in CBSA":21.0,"Orig. FE-AADT":405295,"Orig. FE-AADT Rank in CBSA":3.0,"Distance to nearest road travel feature (m)":17.0,"Distance to nearest mainline (m)":38.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1389139200000,"CO Start Date":1482364800000,"Continuous PM2.5 Start Date":1541635200000,"Current Cont. PM2.5 method":"MetOne BAM 1022","FRM PM2.5 Start Date":1483228800000,"FRM PM2.5 Stop Date":1541376000000,"Current FRM Method\/model":"R&P 2025","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"San Diego-Carlsbad, CA\u00a0","RO":9,"Population 2015":3299521,"Population 2020":3332427,"State":"CA","County":"San Diego","City":"San Diego","Local Site Name":"Rancho Carmel Drive","AQS ID":"06-073-1017","Latitude":32.985433,"Longitude":-117.082175,"Target Road":"I-15","Recent (>2016) HPMS AADT":223000.0,"Recent (>2016) Est. FE-AADT":358000.0,"Orig. AADT (2012-2015)":223000,"Orig. AADT Rank in CBSA":5.0,"Orig. FE-AADT":358000,"Orig. FE-AADT Rank in CBSA":4.0,"Distance to nearest road travel feature (m)":33.0,"Distance to nearest mainline (m)":33.0,"NO2 Probe Height (m)":2.9,"Operational":"YES","Ops Info":null,"NO2 Start Date":1427328000000,"CO Start Date":1429833600000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":1559347200000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"MetOne E-Seq.","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1427328000000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"San Francisco-Oakland-Hayward, CA","RO":9,"Population 2015":4656132,"Population 2020":4696902,"State":"CA","County":"Alameda","City":"Oakland","Local Site Name":"Laney College","AQS ID":"06-001-0012","Latitude":37.793624,"Longitude":-122.263376,"Target Road":"I-880","Recent (>2016) HPMS AADT":225000.0,"Recent (>2016) Est. FE-AADT":441675.0,"Orig. AADT (2012-2015)":216000,"Orig. AADT Rank in CBSA":22.0,"Orig. FE-AADT":424008,"Orig. FE-AADT Rank in CBSA":2.0,"Distance to nearest road travel feature (m)":19.0,"Distance to nearest mainline (m)":24.0,"NO2 Probe Height (m)":6.4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1391212800000,"CO Start Date":1391212800000,"Continuous PM2.5 Start Date":1391212800000,"Current Cont. PM2.5 method":"Met One BAM 1020","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":1391212800000,"BC instrument model":"TAPI 633"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"San Francisco-Oakland-Hayward, CA","RO":9,"Population 2015":4656132,"Population 2020":4696902,"State":"CA","County":"Alameda","City":"Berkeley","Local Site Name":"Berkeley Aquatic Park","AQS ID":"06-001-0013","Latitude":37.864771,"Longitude":-122.302721,"Target Road":"I-80","Recent (>2016) HPMS AADT":267000.0,"Recent (>2016) Est. FE-AADT":382108.2339622641,"Orig. AADT (2012-2015)":265000,"Orig. AADT Rank in CBSA":3.0,"Orig. FE-AADT":379246,"Orig. FE-AADT Rank in CBSA":5.0,"Distance to nearest road travel feature (m)":13.0,"Distance to nearest mainline (m)":19.0,"NO2 Probe Height (m)":4.5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1467331200000,"CO Start Date":1467331200000,"Continuous PM2.5 Start Date":1467331200000,"Current Cont. PM2.5 method":"Met One BAM 1020","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":1467331200000,"BC instrument model":null," Ultrafine Particulate Start Date":1467331200000,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":"TBD","CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"San Francisco-Oakland-Hayward, CA","RO":9,"Population 2015":4656132,"Population 2020":4696902,"State":"CA","County":"Alameda","City":"Pleasanton","Local Site Name":"Owens Court","AQS ID":"06-001-0015","Latitude":37.701234,"Longitude":-121.903125,"Target Road":"I-580","Recent (>2016) HPMS AADT":233000.0,"Recent (>2016) Est. FE-AADT":null,"Orig. AADT (2012-2015)":null,"Orig. AADT Rank in CBSA":null,"Orig. FE-AADT":null,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":15.0,"Distance to nearest mainline (m)":15.0,"NO2 Probe Height (m)":4.5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1522540800000,"CO Start Date":1522540800000,"Continuous PM2.5 Start Date":1522540800000,"Current Cont. PM2.5 method":"Met One BAM 1020","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"San Jose-Sunnyvale-Santa Clara, CA","RO":9,"Population 2015":1976836,"Population 2020":1971160,"State":"CA","County":"Santa Clara","City":"San Jose","Local Site Name":"Knox Avenue","AQS ID":"06-085-0006","Latitude":37.338198,"Longitude":-121.849891,"Target Road":"US 101","Recent (>2016) HPMS AADT":251000.0,"Recent (>2016) Est. FE-AADT":386540.0,"Orig. AADT (2012-2015)":191000,"Orig. AADT Rank in CBSA":8.0,"Orig. FE-AADT":294140,"Orig. FE-AADT Rank in CBSA":4.0,"Distance to nearest road travel feature (m)":17.0,"Distance to nearest mainline (m)":33.0,"NO2 Probe Height (m)":6.4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1409529600000,"CO Start Date":1409529600000,"Continuous PM2.5 Start Date":1409529600000,"Current Cont. PM2.5 method":"Met One BAM 1020","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":1408579200000,"BC instrument model":"TAPI 633"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":"YES","CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"San Juan, Puerto Rico","RO":2,"Population 2015":2196538,"Population 2020":2081265,"State":"PR","County":"Caguas","City":"Caguas","Local Site Name":"Caguas","AQS ID":"72-025-0007","Latitude":18.198712,"Longitude":-66.052237,"Target Road":"Highway 22","Recent (>2016) HPMS AADT":null,"Recent (>2016) Est. FE-AADT":null,"Orig. AADT (2012-2015)":null,"Orig. AADT Rank in CBSA":null,"Orig. FE-AADT":null,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":50.0,"Distance to nearest mainline (m)":null,"NO2 Probe Height (m)":4.3,"Operational":"YES","Ops Info":null,"NO2 Start Date":1482105600000,"CO Start Date":1486339200000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":1496188800000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"MetOne E-SEQ w\/VSCC","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1538697600000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"San Juan, Puerto Rico","RO":2,"Population 2015":2196538,"Population 2020":2081265,"State":"PR","County":"Guaynabo","City":"Guaynabo","Local Site Name":"Guaynabo","AQS ID":"72-061-0006","Latitude":18.421841,"Longitude":-66.120645,"Target Road":"De Diego Hwy","Recent (>2016) HPMS AADT":null,"Recent (>2016) Est. FE-AADT":null,"Orig. AADT (2012-2015)":127300,"Orig. AADT Rank in CBSA":null,"Orig. FE-AADT":null,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":12.0,"Distance to nearest mainline (m)":12.0,"NO2 Probe Height (m)":5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1404777600000,"CO Start Date":1404777600000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Seattle-Tacoma-Bellevue, WA","RO":10,"Population 2015":3733580,"Population 2020":4018598,"State":"WA","County":"King","City":"Seattle","Local Site Name":"10th & Weller","AQS ID":"53-033-0030","Latitude":47.597354,"Longitude":-122.319785,"Target Road":"I-5","Recent (>2016) HPMS AADT":167093.0,"Recent (>2016) Est. FE-AADT":332515.0699999999,"Orig. AADT (2012-2015)":237000,"Orig. AADT Rank in CBSA":2.0,"Orig. FE-AADT":471630,"Orig. FE-AADT Rank in CBSA":3.0,"Distance to nearest road travel feature (m)":11.0,"Distance to nearest mainline (m)":11.0,"NO2 Probe Height (m)":3,"Operational":"YES","Ops Info":null,"NO2 Start Date":1396310400000,"CO Start Date":1396310400000,"Continuous PM2.5 Start Date":1400457600000,"Current Cont. PM2.5 method":"MetOne BAM 1020","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":1400630400000,"BC instrument model":"Magee AE21"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1397606400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":1415836800000,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Seattle-Tacoma-Bellevue, WA","RO":10,"Population 2015":3733580,"Population 2020":4018598,"State":"WA","County":"Pierce","City":"Tacoma","Local Site Name":"Tacoma","AQS ID":"53-053-0024","Latitude":47.22634,"Longitude":-122.46256,"Target Road":"I-5","Recent (>2016) HPMS AADT":163109.0,"Recent (>2016) Est. FE-AADT":324586.91,"Orig. AADT (2012-2015)":208000,"Orig. AADT Rank in CBSA":12.0,"Orig. FE-AADT":413920,"Orig. FE-AADT Rank in CBSA":14.0,"Distance to nearest road travel feature (m)":13.0,"Distance to nearest mainline (m)":13.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1451606400000,"CO Start Date":null,"Continuous PM2.5 Start Date":1454544000000,"Current Cont. PM2.5 method":"MetOne BAM 1020","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"St. Louis, MO-IL","RO":7,"Population 2015":2811588,"Population 2020":2805473,"State":"MO","County":"St. Louis","City":"St. Louis","Local Site Name":"Rider Trail","AQS ID":"29-189-0016","Latitude":38.752528,"Longitude":-90.449022,"Target Road":"I-70","Recent (>2016) HPMS AADT":166223.0,"Recent (>2016) Est. FE-AADT":375674.4064138641,"Orig. AADT (2012-2015)":161338,"Orig. AADT Rank in CBSA":7.0,"Orig. FE-AADT":364634,"Orig. FE-AADT Rank in CBSA":7.0,"Distance to nearest road travel feature (m)":28.0,"Distance to nearest mainline (m)":28.0,"NO2 Probe Height (m)":4.5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1420070400000,"CO Start Date":null,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1420848000000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":1462060800000,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"St. Louis, MO-IL","RO":7,"Population 2015":2811588,"Population 2020":2805473,"State":"MO","County":"St. Louis City","City":"St. Louis","Local Site Name":"Forest Park","AQS ID":"29-510-0094","Latitude":38.631086,"Longitude":-90.281157,"Target Road":"I-64","Recent (>2016) HPMS AADT":147943.0,"Recent (>2016) Est. FE-AADT":334351.4028532694,"Orig. AADT (2012-2015)":159326,"Orig. AADT Rank in CBSA":8.0,"Orig. FE-AADT":360077,"Orig. FE-AADT Rank in CBSA":8.0,"Distance to nearest road travel feature (m)":21.0,"Distance to nearest mainline (m)":21.0,"NO2 Probe Height (m)":4.5,"Operational":"YES","Ops Info":null,"NO2 Start Date":1356998400000,"CO Start Date":1357171200000,"Continuous PM2.5 Start Date":1357171200000,"Current Cont. PM2.5 method":"Thermo 1405-DF","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":1357257600000,"BC instrument model":"TAPI 633"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1356998400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Tampa-St. Petersburg-Clearwater, FL","RO":4,"Population 2015":2975225,"Population 2020":3243963,"State":"FL","County":"Hillsborough","City":"Tampa","Local Site Name":"Munro St.","AQS ID":"12-057-0113","Latitude":27.95532,"Longitude":-82.469589,"Target Road":"I-275","Recent (>2016) HPMS AADT":216000.0,"Recent (>2016) Est. FE-AADT":371520.0,"Orig. AADT (2012-2015)":190500,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":327660,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":34.0,"Distance to nearest mainline (m)":34.0,"NO2 Probe Height (m)":5.2,"Operational":"YES","Ops Info":"Relocated from Julian B. Lane site","NO2 Start Date":1454284800000,"CO Start Date":1454284800000,"Continuous PM2.5 Start Date":1454284800000,"Current Cont. PM2.5 method":" Thermo 5014i","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":1454284800000,"BC instrument model":"TAPI 633"," Ultrafine Particulate Start Date":1454284800000,"Ultrafine Particulate Method":"TAPI 651","Meteorology Start Date":1454284800000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Tampa-St. Petersburg-Clearwater, FL","RO":4,"Population 2015":2975225,"Population 2020":3243963,"State":"FL","County":"Pinellas","City":"St. Petersburg","Local Site Name":"Sawgrass","AQS ID":"12-103-0027","Latitude":27.834355,"Longitude":-82.665246,"Target Road":"I-275","Recent (>2016) HPMS AADT":145500.0,"Recent (>2016) Est. FE-AADT":230617.5,"Orig. AADT (2012-2015)":141000,"Orig. AADT Rank in CBSA":5.0,"Orig. FE-AADT":223485,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":26.0,"Distance to nearest mainline (m)":26.0,"NO2 Probe Height (m)":4,"Operational":"YES","Ops Info":null,"NO2 Start Date":1463702400000,"CO Start Date":1463702400000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":1464739200000,"BC instrument model":"TAPI 633"," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Washington-Arlington-Alexandria, DC-VA-MD-WV","RO":3,"Population 2015":6097684,"Population 2020":6324629,"State":"DC","County":"District of Columbia","City":"Washington DC","Local Site Name":"Anacostia Freeway","AQS ID":"11-001-0051","Latitude":38.894738,"Longitude":-76.953475,"Target Road":"DC-295","Recent (>2016) HPMS AADT":130892.0,"Recent (>2016) Est. FE-AADT":195801.8732594389,"Orig. AADT (2012-2015)":115480,"Orig. AADT Rank in CBSA":121.0,"Orig. FE-AADT":172747,"Orig. FE-AADT Rank in CBSA":121.0,"Distance to nearest road travel feature (m)":9.0,"Distance to nearest mainline (m)":15.0,"NO2 Probe Height (m)":3,"Operational":"YES","Ops Info":null,"NO2 Start Date":1433116800000,"CO Start Date":1433116800000,"Continuous PM2.5 Start Date":1433116800000,"Current Cont. PM2.5 method":"MetOne BAM 1022","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1433116800000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":1441065600000,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Washington-Arlington-Alexandria, DC-VA-MD-WV","RO":3,"Population 2015":6097684,"Population 2020":6324629,"State":"VA","County":"Fairfax","City":"Springfield","Local Site Name":"Springfield","AQS ID":"51-059-0031","Latitude":38.768495,"Longitude":-77.183444,"Target Road":"I-95","Recent (>2016) HPMS AADT":248891.0,"Recent (>2016) Est. FE-AADT":463560.7445252525,"Orig. AADT (2012-2015)":297000,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":553164,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":10.0,"Distance to nearest mainline (m)":18.0,"NO2 Probe Height (m)":3.3,"Operational":"YES","Ops Info":null,"NO2 Start Date":1459814400000,"CO Start Date":1459814400000,"Continuous PM2.5 Start Date":1459814400000,"Current Cont. PM2.5 method":"Thermo 5014i","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":null},{"CBSA Full Name":"Orlando-Kissimmee-Sanford, FL","RO":4,"Population 2015":2387138,"Population 2020":2639374,"State":"FL","County":"Orange","City":"Orlando","Local Site Name":"I-4","AQS ID":"12-095-0009","Latitude":28.534646,"Longitude":-81.384411,"Target Road":"I-4","Recent (>2016) HPMS AADT":201000.0,"Recent (>2016) Est. FE-AADT":320393.8336747151,"Orig. AADT (2012-2015)":195773,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":312062,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":49.5,"Distance to nearest mainline (m)":49.5,"NO2 Probe Height (m)":4.5,"Operational":"PAUSED","Ops Info":"Construction; Will startback up 2022 ","NO2 Start Date":1467331200000,"CO Start Date":1467331200000,"Continuous PM2.5 Start Date":1480550400000,"Current Cont. PM2.5 method":" Thermo 5014i","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":"Site will move to 15m","Coming Soon":null},{"CBSA Full Name":"Charlotte-Concord-Gastonia, NC-SC","RO":4,"Population 2015":2426363,"Population 2020":2684276,"State":"NC","County":"Mecklenburg","City":"Charlotte","Local Site Name":"Equipment Drive","AQS ID":"37-119-0050","Latitude":35.27831,"Longitude":-80.79698,"Target Road":"I-85","Recent (>2016) HPMS AADT":175000.0,"Recent (>2016) Est. FE-AADT":289840.0,"Orig. AADT (2012-2015)":160000,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":287530,"Orig. FE-AADT Rank in CBSA":3.0,"Distance to nearest road travel feature (m)":24.0,"Distance to nearest mainline (m)":24.0,"NO2 Probe Height (m)":4,"Operational":"NO","Ops Info":"Coming soon","NO2 Start Date":null,"CO Start Date":null,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":"Coming Soon"},{"CBSA Full Name":"Detroit-Warren-Dearborn, MI","RO":5,"Population 2015":4302043,"Population 2020":4304136,"State":"MI","County":"Wayne","City":"Livonia","Local Site Name":"Livonia Near Road 2","AQS ID":"26-163-0101","Latitude":42.393574,"Longitude":-83.431948,"Target Road":"I-275","Recent (>2016) HPMS AADT":null,"Recent (>2016) Est. FE-AADT":null,"Orig. AADT (2012-2015)":null,"Orig. AADT Rank in CBSA":null,"Orig. FE-AADT":null,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":null,"Distance to nearest mainline (m)":null,"NO2 Probe Height (m)":null,"Operational":"NO","Ops Info":"Relocated from Livonia #1","NO2 Start Date":null,"CO Start Date":null,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":"Coming Soon"},{"CBSA Full Name":"Grand Rapids-Wyoming, MI","RO":5,"Population 2015":1009737,"Population 2020":1081372,"State":"MI","County":"Kent","City":"Grand Rapids","Local Site Name":"Grand Rapids Near Road","AQS ID":"26-081-0023","Latitude":42.885368,"Longitude":-85.679765,"Target Road":null,"Recent (>2016) HPMS AADT":null,"Recent (>2016) Est. FE-AADT":null,"Orig. AADT (2012-2015)":null,"Orig. AADT Rank in CBSA":null,"Orig. FE-AADT":null,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":null,"Distance to nearest mainline (m)":null,"NO2 Probe Height (m)":null,"Operational":"NO","Ops Info":"Coming soon","NO2 Start Date":null,"CO Start Date":null,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":"Coming Soon"},{"CBSA Full Name":"Orlando-Kissimmee-Sanford, FL","RO":4,"Population 2015":2387138,"Population 2020":2639374,"State":"FL","County":"Orange","City":"Orlando","Local Site Name":"Presidents Drive NR","AQS ID":"12-095-0011","Latitude":28.44626,"Longitude":-81.41744,"Target Road":"Florida Turnpike","Recent (>2016) HPMS AADT":118000.0,"Recent (>2016) Est. FE-AADT":301726.0,"Orig. AADT (2012-2015)":"?","Orig. AADT Rank in CBSA":36.0,"Orig. FE-AADT":"?","Orig. FE-AADT Rank in CBSA":8.0,"Distance to nearest road travel feature (m)":45.0,"Distance to nearest mainline (m)":45.0,"NO2 Probe Height (m)":"2 to 15","Operational":"NO","Ops Info":"Coming soon","NO2 Start Date":null,"CO Start Date":null,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":"Coming Soon"},{"CBSA Full Name":"Boise, ID","RO":10,"Population 2015":676909,"Population 2020":770353,"State":"ID","County":"Ada","City":"Meridian","Local Site Name":"Meridian","AQS ID":"16-001-0023","Latitude":43.593929,"Longitude":-116.38125,"Target Road":"I-84","Recent (>2016) HPMS AADT":115000.0,"Recent (>2016) Est. FE-AADT":180873.786407767,"Orig. AADT (2012-2015)":103000,"Orig. AADT Rank in CBSA":2.0,"Orig. FE-AADT":162000,"Orig. FE-AADT Rank in CBSA":2.0,"Distance to nearest road travel feature (m)":32.0,"Distance to nearest mainline (m)":32.0,"NO2 Probe Height (m)":4.6,"Operational":"NO","Ops Info":"Shut-down (4\/1\/17)","NO2 Start Date":1333238400000,"CO Start Date":1333238400000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":"Shut-down 4\/1\/17","Coming Soon":"Shutdown"},{"CBSA Full Name":"Des Moines-West Des Moines, IA","RO":7,"Population 2015":622899,"Population 2020":707915,"State":"IA","County":"Polk","City":"Des Moines","Local Site Name":"Rollins","AQS ID":"19-153-6011","Latitude":41.59257,"Longitude":-93.70014,"Target Road":"I-235","Recent (>2016) HPMS AADT":122900.0,"Recent (>2016) Est. FE-AADT":167747.3272727273,"Orig. AADT (2012-2015)":110000,"Orig. AADT Rank in CBSA":6.0,"Orig. FE-AADT":150140,"Orig. FE-AADT Rank in CBSA":14.0,"Distance to nearest road travel feature (m)":13.0,"Distance to nearest mainline (m)":13.0,"NO2 Probe Height (m)":3,"Operational":"NO","Ops Info":"Shut-down (12\/31\/16)","NO2 Start Date":1356998400000,"CO Start Date":null,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":"Shutdown"},{"CBSA Full Name":"Detroit-Warren-Dearborn, MI","RO":5,"Population 2015":4302043,"Population 2020":4304136,"State":"MI","County":"Wayne","City":"Livonia","Local Site Name":"Livonia Near Road","AQS ID":"26-163-0095","Latitude":42.421515,"Longitude":-83.425198,"Target Road":"I-275","Recent (>2016) HPMS AADT":193400.0,"Recent (>2016) Est. FE-AADT":313406.6048667439,"Orig. AADT (2012-2015)":172600,"Orig. AADT Rank in CBSA":null,"Orig. FE-AADT":279700,"Orig. FE-AADT Rank in CBSA":null,"Distance to nearest road travel feature (m)":47.0,"Distance to nearest mainline (m)":56.0,"NO2 Probe Height (m)":5.8,"Operational":"NO","Ops Info":"Shut-down (7\/1\/19) - moved","NO2 Start Date":1420070400000,"CO Start Date":1420070400000,"Continuous PM2.5 Start Date":null,"Current Cont. PM2.5 method":null,"FRM PM2.5 Start Date":1420070400000,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":"R&P 2025 w\/ WINS","Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":1420070400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":"Shutdown"},{"CBSA Full Name":"Phoenix-Mesa-Scottsdale, AZ","RO":9,"Population 2015":4574531,"Population 2020":5059909,"State":"AZ","County":"Maricopa","City":"Tempe","Local Site Name":"Diablo","AQS ID":"04-013-4019","Latitude":33.396242,"Longitude":-111.967999,"Target Road":"I-10","Recent (>2016) HPMS AADT":267488.0,"Recent (>2016) Est. FE-AADT":521639.9512710144,"Orig. AADT (2012-2015)":320138,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":624315,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":13.0,"Distance to nearest mainline (m)":13.0,"NO2 Probe Height (m)":5.1,"Operational":"NO","Ops Info":"Closed Dec. 2020. Moved to Site 4021","NO2 Start Date":"2\/14\/214","CO Start Date":1392940800000,"Continuous PM2.5 Start Date":1398902400000,"Current Cont. PM2.5 method":"Thermo 1405-DF","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":null,"BC instrument model":null," Ultrafine Particulate Start Date":null,"Ultrafine Particulate Method":null,"Meteorology Start Date":null,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":null,"Coming Soon":"Shutdown"},{"CBSA Full Name":"Tampa-St. Petersburg-Clearwater, FL","RO":4,"Population 2015":2975225,"Population 2020":3243963,"State":"FL","County":"Hillsborough","City":"Tampa","Local Site Name":"Julian B. Lane Park","AQS ID":"12-057-1111","Latitude":27.955546,"Longitude":-82.467241,"Target Road":"I-275","Recent (>2016) HPMS AADT":145500.0,"Recent (>2016) Est. FE-AADT":250260.0,"Orig. AADT (2012-2015)":190500,"Orig. AADT Rank in CBSA":1.0,"Orig. FE-AADT":327660,"Orig. FE-AADT Rank in CBSA":1.0,"Distance to nearest road travel feature (m)":null,"Distance to nearest mainline (m)":20.0,"NO2 Probe Height (m)":5,"Operational":"NO","Ops Info":"Shutdown Dec.2015 - Moved to Munroe","NO2 Start Date":1391558400000,"CO Start Date":1391558400000,"Continuous PM2.5 Start Date":1404691200000,"Current Cont. PM2.5 method":" Thermo 5014i","FRM PM2.5 Start Date":null,"FRM PM2.5 Stop Date":null,"Current FRM Method\/model":null,"Black Carbon Start Date":1391558400000,"BC instrument model":"TAPI 633"," Ultrafine Particulate Start Date":1391558400000,"Ultrafine Particulate Method":"TSI 3031","Meteorology Start Date":1391558400000,"Ozone Start Date":null,"Toxics\/ VOCs Start Date":null,"CSN Start Date":null,"SO2 Start Date":null,"Traffic Counter Start Date":null,"Traffic Camera Start Date":null,"Other Info":"Relocated Fall 2015 to Munroe","Coming Soon":"Shutdown"}] \ No newline at end of file diff --git a/map-app/next.config.ts b/map-app/next.config.ts new file mode 100644 index 0000000..e9ffa30 --- /dev/null +++ b/map-app/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + /* config options here */ +}; + +export default nextConfig; diff --git a/map-app/package-lock.json b/map-app/package-lock.json new file mode 100644 index 0000000..c4bf8f0 --- /dev/null +++ b/map-app/package-lock.json @@ -0,0 +1,2259 @@ +{ + "name": "map-app", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "map-app", + "version": "0.1.0", + "dependencies": { + "dockview-core": "^4.9.0", + "dockview-react": "^4.9.0", + "maplibre-gl": "^5.9.0", + "next": "15.5.6", + "react": "19.1.0", + "react-dom": "19.1.0", + "react-map-gl": "^8.1.0" + }, + "devDependencies": { + "@biomejs/biome": "2.2.0", + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "tailwindcss": "^4", + "typescript": "^5" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@biomejs/biome": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.2.0.tgz", + "integrity": "sha512-3On3RSYLsX+n9KnoSgfoYlckYBoU6VRM22cw1gB4Y0OuUVSYd/O/2saOJMrA4HFfA1Ff0eacOvMN1yAAvHtzIw==", + "dev": true, + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "2.2.0", + "@biomejs/cli-darwin-x64": "2.2.0", + "@biomejs/cli-linux-arm64": "2.2.0", + "@biomejs/cli-linux-arm64-musl": "2.2.0", + "@biomejs/cli-linux-x64": "2.2.0", + "@biomejs/cli-linux-x64-musl": "2.2.0", + "@biomejs/cli-win32-arm64": "2.2.0", + "@biomejs/cli-win32-x64": "2.2.0" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.0.tgz", + "integrity": "sha512-zKbwUUh+9uFmWfS8IFxmVD6XwqFcENjZvEyfOxHs1epjdH3wyyMQG80FGDsmauPwS2r5kXdEM0v/+dTIA9FXAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.0.tgz", + "integrity": "sha512-+OmT4dsX2eTfhD5crUOPw3RPhaR+SKVspvGVmSdZ9y9O/AgL8pla6T4hOn1q+VAFBHuHhsdxDRJgFCSC7RaMOw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.0.tgz", + "integrity": "sha512-6eoRdF2yW5FnW9Lpeivh7Mayhq0KDdaDMYOJnH9aT02KuSIX5V1HmWJCQQPwIQbhDh68Zrcpl8inRlTEan0SXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.0.tgz", + "integrity": "sha512-egKpOa+4FL9YO+SMUMLUvf543cprjevNc3CAgDNFLcjknuNMcZ0GLJYa3EGTCR2xIkIUJDVneBV3O9OcIlCEZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.0.tgz", + "integrity": "sha512-5UmQx/OZAfJfi25zAnAGHUMuOd+LOsliIt119x2soA2gLggQYrVPA+2kMUxR6Mw5M1deUF/AWWP2qpxgH7Nyfw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.0.tgz", + "integrity": "sha512-I5J85yWwUWpgJyC1CcytNSGusu2p9HjDnOPAFG4Y515hwRD0jpR9sT9/T1cKHtuCvEQ/sBvx+6zhz9l9wEJGAg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.0.tgz", + "integrity": "sha512-n9a1/f2CwIDmNMNkFs+JI0ZjFnMO0jdOyGNtihgUNFnlmd84yIYY2KMTBmMV58ZlVHjgmY5Y6E1hVTnSRieggA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.0.tgz", + "integrity": "sha512-Nawu5nHjP/zPKTIryh2AavzTc/KEg4um/MxWdXW0A6P/RZOyIpa7+QSjeXwAwX/utJGaCoXRPWtF3m5U/bB3Ww==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", + "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.4.tgz", + "integrity": "sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.3" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.4.tgz", + "integrity": "sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.3" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.3.tgz", + "integrity": "sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.3.tgz", + "integrity": "sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.3.tgz", + "integrity": "sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.3.tgz", + "integrity": "sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.3.tgz", + "integrity": "sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.3.tgz", + "integrity": "sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.3.tgz", + "integrity": "sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.3.tgz", + "integrity": "sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.3.tgz", + "integrity": "sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.4.tgz", + "integrity": "sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.3" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.4.tgz", + "integrity": "sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.3" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.4.tgz", + "integrity": "sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.3" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.4.tgz", + "integrity": "sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.3" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.4.tgz", + "integrity": "sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.3" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.4.tgz", + "integrity": "sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.3" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.4.tgz", + "integrity": "sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.3" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.4.tgz", + "integrity": "sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==", + "cpu": [ + "wasm32" + ], + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.5.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.4.tgz", + "integrity": "sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.4.tgz", + "integrity": "sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.4.tgz", + "integrity": "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mapbox/geojson-rewind": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", + "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", + "dependencies": { + "get-stream": "^6.0.1", + "minimist": "^1.2.6" + }, + "bin": { + "geojson-rewind": "geojson-rewind" + } + }, + "node_modules/@mapbox/jsonlint-lines-primitives": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", + "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@mapbox/point-geometry": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-1.1.0.tgz", + "integrity": "sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ==" + }, + "node_modules/@mapbox/tiny-sdf": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.7.tgz", + "integrity": "sha512-25gQLQMcpivjOSA40g3gO6qgiFPDpWRoMfd+G/GoppPIeP6JDaMMkMrEJnMZhKyyS6iKwVt5YKu02vCUyJM3Ug==" + }, + "node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==" + }, + "node_modules/@mapbox/vector-tile": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-2.0.4.tgz", + "integrity": "sha512-AkOLcbgGTdXScosBWwmmD7cDlvOjkg/DetGva26pIRiZPdeJYjYKarIlb4uxVzi6bwHO6EWH82eZ5Nuv4T5DUg==", + "dependencies": { + "@mapbox/point-geometry": "~1.1.0", + "@types/geojson": "^7946.0.16", + "pbf": "^4.0.1" + } + }, + "node_modules/@mapbox/whoots-js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", + "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@maplibre/maplibre-gl-style-spec": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.3.0.tgz", + "integrity": "sha512-CTJc/Nvldv+GNQuis29VnyV0TYsFTgQBY3SNagTzZ28oHDsDYJ7LwEmfick4Z30wPwI/4gXe3se8PH2IIfLx2g==", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/unitbezier": "^0.0.1", + "json-stringify-pretty-compact": "^4.0.0", + "minimist": "^1.2.8", + "quickselect": "^3.0.0", + "rw": "^1.3.3", + "tinyqueue": "^3.0.0" + }, + "bin": { + "gl-style-format": "dist/gl-style-format.mjs", + "gl-style-migrate": "dist/gl-style-migrate.mjs", + "gl-style-validate": "dist/gl-style-validate.mjs" + } + }, + "node_modules/@maplibre/vt-pbf": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@maplibre/vt-pbf/-/vt-pbf-4.0.3.tgz", + "integrity": "sha512-YsW99BwnT+ukJRkseBcLuZHfITB4puJoxnqPVjo72rhW/TaawVYsgQHcqWLzTxqknttYoDpgyERzWSa/XrETdA==", + "dependencies": { + "@mapbox/point-geometry": "^1.1.0", + "@mapbox/vector-tile": "^2.0.4", + "@types/geojson-vt": "3.2.5", + "@types/supercluster": "^7.1.3", + "geojson-vt": "^4.0.2", + "pbf": "^4.0.1", + "supercluster": "^8.0.1" + } + }, + "node_modules/@next/env": { + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.6.tgz", + "integrity": "sha512-3qBGRW+sCGzgbpc5TS1a0p7eNxnOarGVQhZxfvTdnV0gFI61lX7QNtQ4V1TSREctXzYn5NetbUsLvyqwLFJM6Q==" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.6.tgz", + "integrity": "sha512-ES3nRz7N+L5Umz4KoGfZ4XX6gwHplwPhioVRc25+QNsDa7RtUF/z8wJcbuQ2Tffm5RZwuN2A063eapoJ1u4nPg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.6.tgz", + "integrity": "sha512-JIGcytAyk9LQp2/nuVZPAtj8uaJ/zZhsKOASTjxDug0SPU9LAM3wy6nPU735M1OqacR4U20LHVF5v5Wnl9ptTA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.6.tgz", + "integrity": "sha512-qvz4SVKQ0P3/Im9zcS2RmfFL/UCQnsJKJwQSkissbngnB/12c6bZTCB0gHTexz1s6d/mD0+egPKXAIRFVS7hQg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.6.tgz", + "integrity": "sha512-FsbGVw3SJz1hZlvnWD+T6GFgV9/NYDeLTNQB2MXoPN5u9VA9OEDy6fJEfePfsUKAhJufFbZLgp0cPxMuV6SV0w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.6.tgz", + "integrity": "sha512-3QnHGFWlnvAgyxFxt2Ny8PTpXtQD7kVEeaFat5oPAHHI192WKYB+VIKZijtHLGdBBvc16tiAkPTDmQNOQ0dyrA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.6.tgz", + "integrity": "sha512-OsGX148sL+TqMK9YFaPFPoIaJKbFJJxFzkXZljIgA9hjMjdruKht6xDCEv1HLtlLNfkx3c5w2GLKhj7veBQizQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.6.tgz", + "integrity": "sha512-ONOMrqWxdzXDJNh2n60H6gGyKed42Ieu6UTVPZteXpuKbLZTH4G4eBMsr5qWgOBA+s7F+uB4OJbZnrkEDnZ5Fg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.6.tgz", + "integrity": "sha512-pxK4VIjFRx1MY92UycLOOw7dTdvccWsNETQ0kDHkBlcFH1GrTLUjSiHU1ohrznnux6TqRHgv5oflhfIWZwVROQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.14.tgz", + "integrity": "sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==", + "dev": true, + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.0", + "lightningcss": "1.30.1", + "magic-string": "^0.30.19", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.14" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.14.tgz", + "integrity": "sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.5.1" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.14", + "@tailwindcss/oxide-darwin-arm64": "4.1.14", + "@tailwindcss/oxide-darwin-x64": "4.1.14", + "@tailwindcss/oxide-freebsd-x64": "4.1.14", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.14", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.14", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.14", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.14", + "@tailwindcss/oxide-linux-x64-musl": "4.1.14", + "@tailwindcss/oxide-wasm32-wasi": "4.1.14", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.14", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.14" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.14.tgz", + "integrity": "sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz", + "integrity": "sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.14.tgz", + "integrity": "sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.14.tgz", + "integrity": "sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.14.tgz", + "integrity": "sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.14.tgz", + "integrity": "sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.14.tgz", + "integrity": "sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.14.tgz", + "integrity": "sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.14.tgz", + "integrity": "sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.14.tgz", + "integrity": "sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.0.5", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz", + "integrity": "sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.14.tgz", + "integrity": "sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.14.tgz", + "integrity": "sha512-BdMjIxy7HUNThK87C7BC8I1rE8BVUsfNQSI5siQ4JK3iIa3w0XyVvVL9SXLWO//CtYTcp1v7zci0fYwJOjB+Zg==", + "dev": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.1.14", + "@tailwindcss/oxide": "4.1.14", + "postcss": "^8.4.41", + "tailwindcss": "4.1.14" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==" + }, + "node_modules/@types/geojson-vt": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@types/geojson-vt/-/geojson-vt-3.2.5.tgz", + "integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/node": { + "version": "20.19.22", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.22.tgz", + "integrity": "sha512-hRnu+5qggKDSyWHlnmThnUqg62l29Aj/6vcYgUaSFL9oc7DVjeWEQN3PRgdSc6F8d9QRMWkf36CLMch1Do/+RQ==", + "dev": true, + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", + "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", + "dev": true, + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", + "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", + "dev": true, + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/supercluster": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz", + "integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@vis.gl/react-mapbox": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@vis.gl/react-mapbox/-/react-mapbox-8.1.0.tgz", + "integrity": "sha512-FwvH822oxEjWYOr+pP2L8hpv+7cZB2UsQbHHHT0ryrkvvqzmTgt7qHDhamv0EobKw86e1I+B4ojENdJ5G5BkyQ==", + "peerDependencies": { + "mapbox-gl": ">=3.5.0", + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + }, + "peerDependenciesMeta": { + "mapbox-gl": { + "optional": true + } + } + }, + "node_modules/@vis.gl/react-maplibre": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@vis.gl/react-maplibre/-/react-maplibre-8.1.0.tgz", + "integrity": "sha512-PkAK/gp3mUfhCLhUuc+4gc3PN9zCtVGxTF2hB6R5R5yYUw+hdg84OZ770U5MU4tPMTCG6fbduExuIW6RRKN6qQ==", + "dependencies": { + "@maplibre/maplibre-gl-style-spec": "^19.2.1" + }, + "peerDependencies": { + "maplibre-gl": ">=4.0.0", + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + }, + "peerDependenciesMeta": { + "maplibre-gl": { + "optional": true + } + } + }, + "node_modules/@vis.gl/react-maplibre/node_modules/@maplibre/maplibre-gl-style-spec": { + "version": "19.3.3", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-19.3.3.tgz", + "integrity": "sha512-cOZZOVhDSulgK0meTsTkmNXb1ahVvmTmWmfx9gRBwc6hq98wS9JP35ESIoNq3xqEan+UN+gn8187Z6E4NKhLsw==", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/unitbezier": "^0.0.1", + "json-stringify-pretty-compact": "^3.0.0", + "minimist": "^1.2.8", + "rw": "^1.3.3", + "sort-object": "^3.0.3" + }, + "bin": { + "gl-style-format": "dist/gl-style-format.mjs", + "gl-style-migrate": "dist/gl-style-migrate.mjs", + "gl-style-validate": "dist/gl-style-validate.mjs" + } + }, + "node_modules/@vis.gl/react-maplibre/node_modules/json-stringify-pretty-compact": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz", + "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==" + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bytewise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bytewise/-/bytewise-1.1.0.tgz", + "integrity": "sha512-rHuuseJ9iQ0na6UDhnrRVDh8YnWVlU6xM3VH6q/+yHDeUH2zIhUzP+2/h3LIrhLDBtTqzWpE3p3tP/boefskKQ==", + "dependencies": { + "bytewise-core": "^1.2.2", + "typewise": "^1.0.3" + } + }, + "node_modules/bytewise-core": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bytewise-core/-/bytewise-core-1.2.3.tgz", + "integrity": "sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA==", + "dependencies": { + "typewise-core": "^1.2" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001751", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", + "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dockview": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/dockview/-/dockview-4.9.0.tgz", + "integrity": "sha512-iqPQQiiHmCAw6jS2HmjYM5yvTeSWi6wpxqnK2pEdtv94jb8iAw/Bjwj1o50IDMvAbI9euizFjdZ3XV/FRRn/Ew==", + "dependencies": { + "dockview-core": "^4.9.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/dockview-core": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/dockview-core/-/dockview-core-4.9.0.tgz", + "integrity": "sha512-T23JiOMG14WjHGFeiMvVRCj6gOHy69YOj/VDfF1727rDOA/Ht9SCZjzsGTKSaWoBVZW5wYxCZaDwTX5hfP0zyw==" + }, + "node_modules/dockview-react": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/dockview-react/-/dockview-react-4.9.0.tgz", + "integrity": "sha512-VHaaTOj3ULNcxjLRPmUbpitzaErzxGtAgiP7fY6cxvWS59mr5M37QA5Lf52aXxbqf5jGdR1KG6D6u91DSlyaRg==", + "dependencies": { + "dockview": "^4.9.0" + } + }, + "node_modules/earcut": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.2.tgz", + "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/geojson-vt": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz", + "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==" + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gl-matrix": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.4.tgz", + "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==" + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/json-stringify-pretty-compact": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==" + }, + "node_modules/kdbush": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", + "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==" + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "dev": true, + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/maplibre-gl": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.9.0.tgz", + "integrity": "sha512-YxW9glb/YrDXGDhqy1u+aG113+L86ttAUpTd6sCkGHyUKMXOX8qbGHJQVqxOczy+4CtRKnqcCfSura2MzB0nQA==", + "dependencies": { + "@mapbox/geojson-rewind": "^0.5.2", + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/point-geometry": "^1.1.0", + "@mapbox/tiny-sdf": "^2.0.7", + "@mapbox/unitbezier": "^0.0.1", + "@mapbox/vector-tile": "^2.0.4", + "@mapbox/whoots-js": "^3.1.0", + "@maplibre/maplibre-gl-style-spec": "^24.2.0", + "@maplibre/vt-pbf": "^4.0.3", + "@types/geojson": "^7946.0.16", + "@types/geojson-vt": "3.2.5", + "@types/supercluster": "^7.1.3", + "earcut": "^3.0.2", + "geojson-vt": "^4.0.2", + "gl-matrix": "^3.4.4", + "kdbush": "^4.0.2", + "murmurhash-js": "^1.0.0", + "pbf": "^4.0.1", + "potpack": "^2.1.0", + "quickselect": "^3.0.0", + "supercluster": "^8.0.1", + "tinyqueue": "^3.0.0" + }, + "engines": { + "node": ">=16.14.0", + "npm": ">=8.1.0" + }, + "funding": { + "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/murmurhash-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", + "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/next/-/next-15.5.6.tgz", + "integrity": "sha512-zTxsnI3LQo3c9HSdSf91O1jMNsEzIXDShXd4wVdg9y5shwLqBXi4ZtUUJyB86KGVSJLZx0PFONvO54aheGX8QQ==", + "dependencies": { + "@next/env": "15.5.6", + "@swc/helpers": "0.5.15", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.5.6", + "@next/swc-darwin-x64": "15.5.6", + "@next/swc-linux-arm64-gnu": "15.5.6", + "@next/swc-linux-arm64-musl": "15.5.6", + "@next/swc-linux-x64-gnu": "15.5.6", + "@next/swc-linux-x64-musl": "15.5.6", + "@next/swc-win32-arm64-msvc": "15.5.6", + "@next/swc-win32-x64-msvc": "15.5.6", + "sharp": "^0.34.3" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/pbf": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.1.tgz", + "integrity": "sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA==", + "dependencies": { + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/potpack": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.1.0.tgz", + "integrity": "sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ==" + }, + "node_modules/protocol-buffers-schema": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", + "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==" + }, + "node_modules/quickselect": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==" + }, + "node_modules/react": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/react-map-gl": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/react-map-gl/-/react-map-gl-8.1.0.tgz", + "integrity": "sha512-vDx/QXR3Tb+8/ap/z6gdMjJQ8ZEyaZf6+uMSPz7jhWF5VZeIsKsGfPvwHVPPwGF43Ryn+YR4bd09uEFNR5OPdg==", + "dependencies": { + "@vis.gl/react-mapbox": "8.1.0", + "@vis.gl/react-maplibre": "8.1.0" + }, + "peerDependencies": { + "mapbox-gl": ">=1.13.0", + "maplibre-gl": ">=1.13.0", + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + }, + "peerDependenciesMeta": { + "mapbox-gl": { + "optional": true + }, + "maplibre-gl": { + "optional": true + } + } + }, + "node_modules/resolve-protobuf-schema": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", + "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "dependencies": { + "protocol-buffers-schema": "^3.3.1" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==" + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sharp": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.4.tgz", + "integrity": "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.0", + "semver": "^7.7.2" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.4", + "@img/sharp-darwin-x64": "0.34.4", + "@img/sharp-libvips-darwin-arm64": "1.2.3", + "@img/sharp-libvips-darwin-x64": "1.2.3", + "@img/sharp-libvips-linux-arm": "1.2.3", + "@img/sharp-libvips-linux-arm64": "1.2.3", + "@img/sharp-libvips-linux-ppc64": "1.2.3", + "@img/sharp-libvips-linux-s390x": "1.2.3", + "@img/sharp-libvips-linux-x64": "1.2.3", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", + "@img/sharp-libvips-linuxmusl-x64": "1.2.3", + "@img/sharp-linux-arm": "0.34.4", + "@img/sharp-linux-arm64": "0.34.4", + "@img/sharp-linux-ppc64": "0.34.4", + "@img/sharp-linux-s390x": "0.34.4", + "@img/sharp-linux-x64": "0.34.4", + "@img/sharp-linuxmusl-arm64": "0.34.4", + "@img/sharp-linuxmusl-x64": "0.34.4", + "@img/sharp-wasm32": "0.34.4", + "@img/sharp-win32-arm64": "0.34.4", + "@img/sharp-win32-ia32": "0.34.4", + "@img/sharp-win32-x64": "0.34.4" + } + }, + "node_modules/sort-asc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/sort-asc/-/sort-asc-0.2.0.tgz", + "integrity": "sha512-umMGhjPeHAI6YjABoSTrFp2zaBtXBej1a0yKkuMUyjjqu6FJsTF+JYwCswWDg+zJfk/5npWUUbd33HH/WLzpaA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-desc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/sort-desc/-/sort-desc-0.2.0.tgz", + "integrity": "sha512-NqZqyvL4VPW+RAxxXnB8gvE1kyikh8+pR+T+CXLksVRN9eiQqkQlPwqWYU0mF9Jm7UnctShlxLyAt1CaBOTL1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-object": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sort-object/-/sort-object-3.0.3.tgz", + "integrity": "sha512-nK7WOY8jik6zaG9CRwZTaD5O7ETWDLZYMM12pqY8htll+7dYeqGfEUPcUBHOpSJg2vJOrvFIY2Dl5cX2ih1hAQ==", + "dependencies": { + "bytewise": "^1.1.0", + "get-value": "^2.0.2", + "is-extendable": "^0.1.1", + "sort-asc": "^0.2.0", + "sort-desc": "^0.2.0", + "union-value": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/supercluster": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", + "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", + "dependencies": { + "kdbush": "^4.0.2" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz", + "integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==", + "dev": true + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz", + "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==", + "dev": true, + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyqueue": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typewise": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typewise/-/typewise-1.0.3.tgz", + "integrity": "sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ==", + "dependencies": { + "typewise-core": "^1.2.0" + } + }, + "node_modules/typewise-core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/typewise-core/-/typewise-core-1.2.0.tgz", + "integrity": "sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg==" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "engines": { + "node": ">=18" + } + } + } +} diff --git a/map-app/package.json b/map-app/package.json new file mode 100644 index 0000000..3ea4901 --- /dev/null +++ b/map-app/package.json @@ -0,0 +1,30 @@ +{ + "name": "map-app", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --turbopack", + "build": "next build --turbopack", + "start": "next start", + "lint": "biome check", + "format": "biome format --write" + }, + "dependencies": { + "dockview-core": "^4.9.0", + "dockview-react": "^4.9.0", + "maplibre-gl": "^5.9.0", + "next": "15.5.6", + "react": "19.1.0", + "react-dom": "19.1.0", + "react-map-gl": "^8.1.0" + }, + "devDependencies": { + "@biomejs/biome": "2.2.0", + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "tailwindcss": "^4", + "typescript": "^5" + } +} diff --git a/map-app/postcss.config.mjs b/map-app/postcss.config.mjs new file mode 100644 index 0000000..c7bcb4b --- /dev/null +++ b/map-app/postcss.config.mjs @@ -0,0 +1,5 @@ +const config = { + plugins: ["@tailwindcss/postcss"], +}; + +export default config; diff --git a/map-app/public/file.svg b/map-app/public/file.svg new file mode 100644 index 0000000..004145c --- /dev/null +++ b/map-app/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/map-app/public/globe.svg b/map-app/public/globe.svg new file mode 100644 index 0000000..567f17b --- /dev/null +++ b/map-app/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/map-app/public/next.svg b/map-app/public/next.svg new file mode 100644 index 0000000..5174b28 --- /dev/null +++ b/map-app/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/map-app/public/vercel.svg b/map-app/public/vercel.svg new file mode 100644 index 0000000..7705396 --- /dev/null +++ b/map-app/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/map-app/public/window.svg b/map-app/public/window.svg new file mode 100644 index 0000000..b2b2a44 --- /dev/null +++ b/map-app/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/map-app/src/app/SiteMap.tsx b/map-app/src/app/SiteMap.tsx new file mode 100644 index 0000000..9fb0bb4 --- /dev/null +++ b/map-app/src/app/SiteMap.tsx @@ -0,0 +1,71 @@ +'use client' +import {useState, useMemo, useContext} from 'react'; +import 'maplibre-gl/dist/maplibre-gl.css'; +import { + Map, + Marker, + Popup, + NavigationControl, + FullscreenControl, + ScaleControl, + GeolocateControl +} from 'react-map-gl/maplibre'; +import * as Pins from "./pin" +import { IDockviewPanelProps } from 'dockview-react'; +import { AirQualityStation } from './components/AirQualityStation'; +import RAW_SITES from '../../data/near_road_sides.json'; +const SITES: AirQualityStation[] = RAW_SITES as AirQualityStation[]; + + +import { SharedStateContext, useSharedState } from './components/SharedState'; +interface SiteMapProps { + dockProps: IDockviewPanelProps, + +}; + +export default function SiteMap(props: SiteMapProps) { + const [popupInfo, setPopupInfo] = useState(null); + const {sharedState, setSharedState} = useSharedState(); + const markers = useMemo(() => SITES.map((site, idx) => ( + { + // If we let the click event propagates to the map, it will immediately close the popup + // with `closeOnClick: true` + e.originalEvent.stopPropagation(); + setPopupInfo(site); + setSharedState(site); + }}> + + + )), []); + + + return ( + + {markers} + {popupInfo && ( + setPopupInfo(null)} + > +
+

{popupInfo["Local Site Name"]}

+
+
+ )} +
); +} \ No newline at end of file diff --git a/map-app/src/app/components/AirQualityStation.tsx b/map-app/src/app/components/AirQualityStation.tsx new file mode 100644 index 0000000..b7d8836 --- /dev/null +++ b/map-app/src/app/components/AirQualityStation.tsx @@ -0,0 +1,45 @@ +export type AirQualityStation = { + "CBSA Full Name": string; + "RO": number; + "Population 2015": number; + "Population 2020": number; + "State": string; + "County": string; + "City": string; + "Local Site Name": string; + "AQS ID": string; + "Latitude": number; + "Longitude": number; + "Target Road": string; + "Recent (>2016) HPMS AADT": number; + "Recent (>2016) Est. FE-AADT": number; + "Orig. AADT (2012-2015)": number; + "Orig. AADT Rank in CBSA": number; + "Orig. FE-AADT": number; + "Orig. FE-AADT Rank in CBSA": number; + "Distance to nearest road travel feature (m)": number; + "Distance to nearest mainline (m)": number; + "NO2 Probe Height (m)": number; + "Operational": "YES" | "NO"; // Assuming 'YES' or 'NO' are the only string values + "Ops Info": string | null; + "NO2 Start Date": number | null; + "CO Start Date": number | null; + "Continuous PM2.5 Start Date": number | null; + "Current Cont. PM2.5 method": string | null; + "FRM PM2.5 Start Date": number | null; + "FRM PM2.5 Stop Date": number | null; + "Current FRM Method/model": string | null; + "Black Carbon Start Date": number | null; + "BC instrument model": string | null; + " Ultrafine Particulate Start Date": number | null; + "Ultrafine Particulate Method": string | null; + "Meteorology Start Date": number | null; + "Ozone Start Date": number | null; + "Toxics/ VOCs Start Date": number | null; + "CSN Start Date": number | null; + "SO2 Start Date": number | null; + "Traffic Counter Start Date": number | null; + "Traffic Camera Start Date": number | null; + "Other Info": string | null; + "Coming Soon": string | null; +} \ No newline at end of file diff --git a/map-app/src/app/components/DisplayPane.tsx b/map-app/src/app/components/DisplayPane.tsx new file mode 100644 index 0000000..1a85103 --- /dev/null +++ b/map-app/src/app/components/DisplayPane.tsx @@ -0,0 +1,50 @@ +import { useSharedState } from "./SharedState"; +import { IDockviewPanelProps } from "dockview-core"; + +interface DisplayPaneProps { + dockProps: IDockviewPanelProps, + +}; + +export default function DisplayPane(props: DisplayPaneProps) { + const {sharedState, setSharedState} = useSharedState(); + return ( + +
+ {sharedState ? <> +
+

{sharedState["Local Site Name"]}

+

{sharedState["City"]}, {sharedState.State}

+

AQS ID: {sharedState["AQS ID"]}

+
+ +

Latitude: {sharedState.Latitude}

+

Longitude: {sharedState.Longitude}

+ +

Target Road: {sharedState["Target Road"]}

+

County: {sharedState.County}

+ +

Population:

+
    +
  • 2015 - {sharedState["Population 2015"]}
  • +
  • 2020 - {sharedState["Population 2020"]}
  • +
+
+

NO2

+

Start Date: {sharedState["NO2 Start Date"]}

+

Probe Height: {sharedState["NO2 Probe Height (m)"]} meters

+
+ {sharedState["Continuous PM2.5 Start Date"] && +
+

PM2.5

+

Continuous Start Date: {sharedState["Continuous PM2.5 Start Date"]}

+

Probe Height: {sharedState["Current Cont. PM2.5 method"]}

+
} +
+

Raw JSON

+ {JSON.stringify(sharedState)} +
+ :

No site selected.

} +
+ ); +} \ No newline at end of file diff --git a/map-app/src/app/components/SharedState.tsx b/map-app/src/app/components/SharedState.tsx new file mode 100644 index 0000000..8de7684 --- /dev/null +++ b/map-app/src/app/components/SharedState.tsx @@ -0,0 +1,32 @@ +// src/SharedContext.js +import React, { createContext, useState, useContext, Dispatch, SetStateAction } from 'react'; +import { AirQualityStation } from './AirQualityStation'; +// 1. Define the Context +interface SharedStateContextType { + sharedState: AirQualityStation | null, + setSharedState: Dispatch> +} +export const SharedStateContext = createContext(undefined); + +// 2. Create the Provider component +export const SharedStateProvider = ({ children }: any) => { + const [sharedState, setSharedState] = useState(null); + const contextValue: SharedStateContextType = { + sharedState, + setSharedState, + }; + return ( + + {children} + + ); +}; + +// Custom hook for convenience +export const useSharedState = () => { + const context = useContext(SharedStateContext); + if (context === undefined) { + throw new Error('useSharedState must be used within a SharedStateProvider'); + } + return context; +}; \ No newline at end of file diff --git a/map-app/src/app/favicon.ico b/map-app/src/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 zcmeHv30#a{`}aL_*G&7qml|y<+KVaDM2m#dVr!KsA!#An?kSQM(q<_dDNCpjEux83 zLb9Z^XxbDl(w>%i@8hT6>)&Gu{h#Oeyszu?xtw#Zb1mO{pgX9699l+Qppw7jXaYf~-84xW z)w4x8?=youko|}Vr~(D$UXIbiXABHh`p1?nn8Po~fxRJv}|0e(BPs|G`(TT%kKVJAdg5*Z|x0leQq0 zkdUBvb#>9F()jo|T~kx@OM8$9wzs~t2l;K=woNssA3l6|sx2r3+kdfVW@e^8e*E}v zA1y5{bRi+3Z`uD3{F7LgFJDdvm;nJilkzDku>BwXH(8ItVCXk*-lSJnR?-2UN%hJ){&rlvg`CDTj z)Bzo!3v7Ou#83zEDEFcKt(f1E0~=rqeEbTnMvWR#{+9pg%7G8y>u1OVRUSoox-ovF z2Ydma(;=YuBY(eI|04{hXzZD6_f(v~H;C~y5=DhAC{MMS>2fm~1H_t2$56pc$NH8( z5bH|<)71dV-_oCHIrzrT`2s-5w_+2CM0$95I6X8p^r!gHp+j_gd;9O<1~CEQQGS8) zS9Qh3#p&JM-G8rHekNmKVewU;pJRcTAog68KYo^dRo}(M>36U4Us zfgYWSiHZL3;lpWT=zNAW>Dh#mB!_@Lg%$ms8N-;aPqMn+C2HqZgz&9~Eu z4|Kp<`$q)Uw1R?y(~S>ePdonHxpV1#eSP1B;Ogo+-Pk}6#0GsZZ5!||ev2MGdh}_m z{DeR7?0-1^zVs&`AV6Vt;r3`I`OI_wgs*w=eO%_#7Kepl{B@xiyCANc(l zzIyd4y|c6PXWq9-|KM8(zIk8LPk(>a)zyFWjhT!$HJ$qX1vo@d25W<fvZQ2zUz5WRc(UnFMKHwe1| zWmlB1qdbiA(C0jmnV<}GfbKtmcu^2*P^O?MBLZKt|As~ge8&AAO~2K@zbXelK|4T<{|y4`raF{=72kC2Kn(L4YyenWgrPiv z@^mr$t{#X5VuIMeL!7Ab6_kG$&#&5p*Z{+?5U|TZ`B!7llpVmp@skYz&n^8QfPJzL z0G6K_OJM9x+Wu2gfN45phANGt{7=C>i34CV{Xqlx(fWpeAoj^N0Biu`w+MVcCUyU* zDZuzO0>4Z6fbu^T_arWW5n!E45vX8N=bxTVeFoep_G#VmNlQzAI_KTIc{6>c+04vr zx@W}zE5JNSU>!THJ{J=cqjz+4{L4A{Ob9$ZJ*S1?Ggg3klFp!+Y1@K+pK1DqI|_gq z5ZDXVpge8-cs!o|;K73#YXZ3AShj50wBvuq3NTOZ`M&qtjj#GOFfgExjg8Gn8>Vq5 z`85n+9|!iLCZF5$HJ$Iu($dm?8~-ofu}tEc+-pyke=3!im#6pk_Wo8IA|fJwD&~~F zc16osQ)EBo58U7XDuMexaPRjU@h8tXe%S{fA0NH3vGJFhuyyO!Uyl2^&EOpX{9As0 zWj+P>{@}jxH)8|r;2HdupP!vie{sJ28b&bo!8`D^x}TE$%zXNb^X1p@0PJ86`dZyj z%ce7*{^oo+6%&~I!8hQy-vQ7E)0t0ybH4l%KltWOo~8cO`T=157JqL(oq_rC%ea&4 z2NcTJe-HgFjNg-gZ$6!Y`SMHrlj}Etf7?r!zQTPPSv}{so2e>Fjs1{gzk~LGeesX%r(Lh6rbhSo_n)@@G-FTQy93;l#E)hgP@d_SGvyCp0~o(Y;Ee8{ zdVUDbHm5`2taPUOY^MAGOw*>=s7=Gst=D+p+2yON!0%Hk` zz5mAhyT4lS*T3LS^WSxUy86q&GnoHxzQ6vm8)VS}_zuqG?+3td68_x;etQAdu@sc6 zQJ&5|4(I?~3d-QOAODHpZ=hlSg(lBZ!JZWCtHHSj`0Wh93-Uk)_S%zsJ~aD>{`A0~ z9{AG(e|q3g5B%wYKRxiL2Y$8(4w6bzchKuloQW#e&S3n+P- z8!ds-%f;TJ1>)v)##>gd{PdS2Oc3VaR`fr=`O8QIO(6(N!A?pr5C#6fc~Ge@N%Vvu zaoAX2&(a6eWy_q&UwOhU)|P3J0Qc%OdhzW=F4D|pt0E4osw;%<%Dn58hAWD^XnZD= z>9~H(3bmLtxpF?a7su6J7M*x1By7YSUbxGi)Ot0P77`}P3{)&5Un{KD?`-e?r21!4vTTnN(4Y6Lin?UkSM z`MXCTC1@4A4~mvz%Rh2&EwY))LeoT=*`tMoqcEXI>TZU9WTP#l?uFv+@Dn~b(>xh2 z;>B?;Tz2SR&KVb>vGiBSB`@U7VIWFSo=LDSb9F{GF^DbmWAfpms8Sx9OX4CnBJca3 zlj9(x!dIjN?OG1X4l*imJNvRCk}F%!?SOfiOq5y^mZW)jFL@a|r-@d#f7 z2gmU8L3IZq0ynIws=}~m^#@&C%J6QFo~Mo4V`>v7MI-_!EBMMtb%_M&kvAaN)@ZVw z+`toz&WG#HkWDjnZE!6nk{e-oFdL^$YnbOCN}JC&{$#$O27@|Tn-skXr)2ml2~O!5 zX+gYoxhoc7qoU?C^3~&!U?kRFtnSEecWuH0B0OvLodgUAi}8p1 zrO6RSXHH}DMc$&|?D004DiOVMHV8kXCP@7NKB zgaZq^^O<7PoKEp72kby@W0Z!Y*Ay{&vfg#C&gG@YVR9g?FEocMUi1gSN$+V+ayF45{a zuDZDTN}mS|;BO%gEf}pjBfN2-gIrU#G5~cucA;dokXW89%>AyXJJI z9X4UlIWA|ZYHgbI z5?oFk@A=Ik7lrEQPDH!H+b`7_Y~aDb_qa=B2^Y&Ow41cU=4WDd40dp5(QS-WMN-=Y z9g;6_-JdNU;|6cPwf$ak*aJIcwL@1n$#l~zi{c{EW?T;DaW*E8DYq?Umtz{nJ&w-M zEMyTDrC&9K$d|kZe2#ws6)L=7K+{ zQw{XnV6UC$6-rW0emqm8wJoeZK)wJIcV?dST}Z;G0Arq{dVDu0&4kd%N!3F1*;*pW zR&qUiFzK=@44#QGw7k1`3t_d8&*kBV->O##t|tonFc2YWrL7_eqg+=+k;!F-`^b8> z#KWCE8%u4k@EprxqiV$VmmtiWxDLgnGu$Vs<8rppV5EajBXL4nyyZM$SWVm!wnCj-B!Wjqj5-5dNXukI2$$|Bu3Lrw}z65Lc=1G z^-#WuQOj$hwNGG?*CM_TO8Bg-1+qc>J7k5c51U8g?ZU5n?HYor;~JIjoWH-G>AoUP ztrWWLbRNqIjW#RT*WqZgPJXU7C)VaW5}MiijYbABmzoru6EmQ*N8cVK7a3|aOB#O& zBl8JY2WKfmj;h#Q!pN%9o@VNLv{OUL?rixHwOZuvX7{IJ{(EdPpuVFoQqIOa7giLVkBOKL@^smUA!tZ1CKRK}#SSM)iQHk)*R~?M!qkCruaS!#oIL1c z?J;U~&FfH#*98^G?i}pA{ z9Jg36t4=%6mhY(quYq*vSxptes9qy|7xSlH?G=S@>u>Ebe;|LVhs~@+06N<4CViBk zUiY$thvX;>Tby6z9Y1edAMQaiH zm^r3v#$Q#2T=X>bsY#D%s!bhs^M9PMAcHbCc0FMHV{u-dwlL;a1eJ63v5U*?Q_8JO zT#50!RD619#j_Uf))0ooADz~*9&lN!bBDRUgE>Vud-i5ck%vT=r^yD*^?Mp@Q^v+V zG#-?gKlr}Eeqifb{|So?HM&g91P8|av8hQoCmQXkd?7wIJwb z_^v8bbg`SAn{I*4bH$u(RZ6*xUhuA~hc=8czK8SHEKTzSxgbwi~9(OqJB&gwb^l4+m`k*Q;_?>Y-APi1{k zAHQ)P)G)f|AyjSgcCFps)Fh6Bca*Xznq36!pV6Az&m{O8$wGFD? zY&O*3*J0;_EqM#jh6^gMQKpXV?#1?>$ml1xvh8nSN>-?H=V;nJIwB07YX$e6vLxH( zqYwQ>qxwR(i4f)DLd)-$P>T-no_c!LsN@)8`e;W@)-Hj0>nJ-}Kla4-ZdPJzI&Mce zv)V_j;(3ERN3_@I$N<^|4Lf`B;8n+bX@bHbcZTopEmDI*Jfl)-pFDvo6svPRoo@(x z);_{lY<;);XzT`dBFpRmGrr}z5u1=pC^S-{ce6iXQlLGcItwJ^mZx{m$&DA_oEZ)B{_bYPq-HA zcH8WGoBG(aBU_j)vEy+_71T34@4dmSg!|M8Vf92Zj6WH7Q7t#OHQqWgFE3ARt+%!T z?oLovLVlnf?2c7pTc)~cc^($_8nyKwsN`RA-23ed3sdj(ys%pjjM+9JrctL;dy8a( z@en&CQmnV(()bu|Y%G1-4a(6x{aLytn$T-;(&{QIJB9vMox11U-1HpD@d(QkaJdEb zG{)+6Dos_L+O3NpWo^=gR?evp|CqEG?L&Ut#D*KLaRFOgOEK(Kq1@!EGcTfo+%A&I z=dLbB+d$u{sh?u)xP{PF8L%;YPPW53+@{>5W=Jt#wQpN;0_HYdw1{ksf_XhO4#2F= zyPx6Lx2<92L-;L5PD`zn6zwIH`Jk($?Qw({erA$^bC;q33hv!d!>%wRhj# zal^hk+WGNg;rJtb-EB(?czvOM=H7dl=vblBwAv>}%1@{}mnpUznfq1cE^sgsL0*4I zJ##!*B?=vI_OEVis5o+_IwMIRrpQyT_Sq~ZU%oY7c5JMIADzpD!Upz9h@iWg_>>~j zOLS;wp^i$-E?4<_cp?RiS%Rd?i;f*mOz=~(&3lo<=@(nR!_Rqiprh@weZlL!t#NCc zO!QTcInq|%#>OVgobj{~ixEUec`E25zJ~*DofsQdzIa@5^nOXj2T;8O`l--(QyU^$t?TGY^7#&FQ+2SS3B#qK*k3`ye?8jUYSajE5iBbJls75CCc(m3dk{t?- zopcER9{Z?TC)mk~gpi^kbbu>b-+a{m#8-y2^p$ka4n60w;Sc2}HMf<8JUvhCL0B&Btk)T`ctE$*qNW8L$`7!r^9T+>=<=2qaq-;ll2{`{Rg zc5a0ZUI$oG&j-qVOuKa=*v4aY#IsoM+1|c4Z)<}lEDvy;5huB@1RJPquU2U*U-;gu z=En2m+qjBzR#DEJDO`WU)hdd{Vj%^0V*KoyZ|5lzV87&g_j~NCjwv0uQVqXOb*QrQ zy|Qn`hxx(58c70$E;L(X0uZZ72M1!6oeg)(cdKO ze0gDaTz+ohR-#d)NbAH4x{I(21yjwvBQfmpLu$)|m{XolbgF!pmsqJ#D}(ylp6uC> z{bqtcI#hT#HW=wl7>p!38sKsJ`r8}lt-q%Keqy%u(xk=yiIJiUw6|5IvkS+#?JTBl z8H5(Q?l#wzazujH!8o>1xtn8#_w+397*_cy8!pQGP%K(Ga3pAjsaTbbXJlQF_+m+-UpUUent@xM zg%jqLUExj~o^vQ3Gl*>wh=_gOr2*|U64_iXb+-111aH}$TjeajM+I20xw(((>fej-@CIz4S1pi$(#}P7`4({6QS2CaQS4NPENDp>sAqD z$bH4KGzXGffkJ7R>V>)>tC)uax{UsN*dbeNC*v}#8Y#OWYwL4t$ePR?VTyIs!wea+ z5Urmc)X|^`MG~*dS6pGSbU+gPJoq*^a=_>$n4|P^w$sMBBy@f*Z^Jg6?n5?oId6f{ z$LW4M|4m502z0t7g<#Bx%X;9<=)smFolV&(V^(7Cv2-sxbxopQ!)*#ZRhTBpx1)Fc zNm1T%bONzv6@#|dz(w02AH8OXe>kQ#1FMCzO}2J_mST)+ExmBr9cva-@?;wnmWMOk z{3_~EX_xadgJGv&H@zK_8{(x84`}+c?oSBX*Ge3VdfTt&F}yCpFP?CpW+BE^cWY0^ zb&uBN!Ja3UzYHK-CTyA5=L zEMW{l3Usky#ly=7px648W31UNV@K)&Ub&zP1c7%)`{);I4b0Q<)B}3;NMG2JH=X$U zfIW4)4n9ZM`-yRj67I)YSLDK)qfUJ_ij}a#aZN~9EXrh8eZY2&=uY%2N0UFF7<~%M zsB8=erOWZ>Ct_#^tHZ|*q`H;A)5;ycw*IcmVxi8_0Xk}aJA^ath+E;xg!x+As(M#0=)3!NJR6H&9+zd#iP(m0PIW8$ z1Y^VX`>jm`W!=WpF*{ioM?C9`yOR>@0q=u7o>BP-eSHqCgMDj!2anwH?s%i2p+Q7D zzszIf5XJpE)IG4;d_(La-xenmF(tgAxK`Y4sQ}BSJEPs6N_U2vI{8=0C_F?@7<(G; zo$~G=8p+076G;`}>{MQ>t>7cm=zGtfbdDXm6||jUU|?X?CaE?(<6bKDYKeHlz}DA8 zXT={X=yp_R;HfJ9h%?eWvQ!dRgz&Su*JfNt!Wu>|XfU&68iRikRrHRW|ZxzRR^`eIGt zIeiDgVS>IeExKVRWW8-=A=yA`}`)ZkWBrZD`hpWIxBGkh&f#ijr449~m`j6{4jiJ*C!oVA8ZC?$1RM#K(_b zL9TW)kN*Y4%^-qPpMP7d4)o?Nk#>aoYHT(*g)qmRUb?**F@pnNiy6Fv9rEiUqD(^O zzyS?nBrX63BTRYduaG(0VVG2yJRe%o&rVrLjbxTaAFTd8s;<<@Qs>u(<193R8>}2_ zuwp{7;H2a*X7_jryzriZXMg?bTuegABb^87@SsKkr2)0Gyiax8KQWstw^v#ix45EVrcEhr>!NMhprl$InQMzjSFH54x5k9qHc`@9uKQzvL4ihcq{^B zPrVR=o_ic%Y>6&rMN)hTZsI7I<3&`#(nl+3y3ys9A~&^=4?PL&nd8)`OfG#n zwAMN$1&>K++c{^|7<4P=2y(B{jJsQ0a#U;HTo4ZmWZYvI{+s;Td{Yzem%0*k#)vjpB zia;J&>}ICate44SFYY3vEelqStQWFihx%^vQ@Do(sOy7yR2@WNv7Y9I^yL=nZr3mb zXKV5t@=?-Sk|b{XMhA7ZGB@2hqsx}4xwCW!in#C zI@}scZlr3-NFJ@NFaJlhyfcw{k^vvtGl`N9xSo**rDW4S}i zM9{fMPWo%4wYDG~BZ18BD+}h|GQKc-g^{++3MY>}W_uq7jGHx{mwE9fZiPCoxN$+7 zrODGGJrOkcPQUB(FD5aoS4g~7#6NR^ma7-!>mHuJfY5kTe6PpNNKC9GGRiu^L31uG z$7v`*JknQHsYB!Tm_W{a32TM099djW%5e+j0Ve_ct}IM>XLF1Ap+YvcrLV=|CKo6S zb+9Nl3_YdKP6%Cxy@6TxZ>;4&nTneadr z_ES90ydCev)LV!dN=#(*f}|ZORFdvkYBni^aLbUk>BajeWIOcmHP#8S)*2U~QKI%S zyrLmtPqb&TphJ;>yAxri#;{uyk`JJqODDw%(Z=2`1uc}br^V%>j!gS)D*q*f_-qf8&D;W1dJgQMlaH5er zN2U<%Smb7==vE}dDI8K7cKz!vs^73o9f>2sgiTzWcwY|BMYHH5%Vn7#kiw&eItCqa zIkR2~Q}>X=Ar8W|^Ms41Fm8o6IB2_j60eOeBB1Br!boW7JnoeX6Gs)?7rW0^5psc- zjS16yb>dFn>KPOF;imD}e!enuIniFzv}n$m2#gCCv4jM#ArwlzZ$7@9&XkFxZ4n!V zj3dyiwW4Ki2QG{@i>yuZXQizw_OkZI^-3otXC{!(lUpJF33gI60ak;Uqitp74|B6I zgg{b=Iz}WkhCGj1M=hu4#Aw173YxIVbISaoc z-nLZC*6Tgivd5V`K%GxhBsp@SUU60-rfc$=wb>zdJzXS&-5(NRRodFk;Kxk!S(O(a0e7oY=E( zAyS;Ow?6Q&XA+cnkCb{28_1N8H#?J!*$MmIwLq^*T_9-z^&UE@A(z9oGYtFy6EZef LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/map-app/src/app/globals.css b/map-app/src/app/globals.css new file mode 100644 index 0000000..493557c --- /dev/null +++ b/map-app/src/app/globals.css @@ -0,0 +1,43 @@ +@import "tailwindcss"; + +:root { + --background: #ffffff; + --foreground: #171717; +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #0a0a0a; + --foreground: #ededed; + } +} + +body { + background: var(--background); + color: var(--foreground); + font-family: Arial, Helvetica, sans-serif; +} + +.my-custom-tab { + padding: 0px 8px; + width: 100%; + display: flex; + height: 100%; + align-items: center; + background-color: var(--dv-tabs-and-actions-container-background-color); +} +.my-custom-tab-icon { + font-size: 16px + +} +.my-custom-tab-icon:hover { + border-radius: 2px; + background-color: var(--dv-icon-hover-background-color); + } diff --git a/map-app/src/app/layout.tsx b/map-app/src/app/layout.tsx new file mode 100644 index 0000000..7ad62a6 --- /dev/null +++ b/map-app/src/app/layout.tsx @@ -0,0 +1,35 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; +import 'dockview/dist/styles/dockview.css'; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} diff --git a/map-app/src/app/page.tsx b/map-app/src/app/page.tsx new file mode 100644 index 0000000..b7d4bf5 --- /dev/null +++ b/map-app/src/app/page.tsx @@ -0,0 +1,107 @@ +'use client' +import { + DockviewReact, + DockviewReadyEvent, + DockviewApi, + IDockviewPanelProps, + DockviewPanelApi, + DockviewGroupPanelApi, + IDockviewPanelHeaderProps +} from "dockview-react"; +import SiteMap from "./SiteMap"; +import { SharedStateProvider } from "./components/SharedState"; +import DisplayPane from "./components/DisplayPane"; +const components = { + default: (props: IDockviewPanelProps<{ title: string; x?: number }>) => { + return ( +
+ {`${props.params.title}`} + {props.params.x && {` ${props.params.x}`}} +
+ ); + }, + mapComponent: (props: IDockviewPanelProps) => { + return ( + + ); + }, + displayPane: (props: IDockviewPanelProps) => { + return ( + + ); + }, +}; + +const tabComponents = { + default: (props: IDockviewPanelHeaderProps<{ title: string }>) => { + return ( +
+ {props.params.title} + + + {/* + minimize + + + maximize + + + close + */} +
+ ); + }, +}; + + +const Home = () => { + const onReady = (event: DockviewReadyEvent) => { + const mapPanel = event.api.addPanel({ + id: 'panel_1', + component: 'mapComponent', + tabComponent: 'default', + params: { + title: 'Map', + }, + }); + + const otherPanel = event.api.addPanel({ + id: 'panel_2', + component: 'displayPane', + tabComponent: 'default', + params: { + title: 'Window 2', + }, + initialWidth: 350, + position: { + direction: 'right', + + }, + }); + }; + return ( + +
+
+ +
+
+
+ ); +} + +export default Home; diff --git a/map-app/src/app/pin.tsx b/map-app/src/app/pin.tsx new file mode 100644 index 0000000..83ff59c --- /dev/null +++ b/map-app/src/app/pin.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; + +const ICON = `M20.2,15.7L20.2,15.7c1.1-1.6,1.8-3.6,1.8-5.7c0-5.6-4.5-10-10-10S2,4.5,2,10c0,2,0.6,3.9,1.6,5.4c0,0.1,0.1,0.2,0.2,0.3 + c0,0,0.1,0.1,0.1,0.2c0.2,0.3,0.4,0.6,0.7,0.9c2.6,3.1,7.4,7.6,7.4,7.6s4.8-4.5,7.4-7.5c0.2-0.3,0.5-0.6,0.7-0.9 + C20.1,15.8,20.2,15.8,20.2,15.7z`; + +const pinStyle = { + cursor: 'pointer', + fill: '#d00', + stroke: 'none' +}; + +function Pin({size = 20}) { + return ( + + + + ); +} + +export default React.memo(Pin); \ No newline at end of file diff --git a/map-app/tsconfig.json b/map-app/tsconfig.json new file mode 100644 index 0000000..c133409 --- /dev/null +++ b/map-app/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} From d0452a6d2d143ce60d991db06b67a4a6a3d0b841 Mon Sep 17 00:00:00 2001 From: Tyler Duckworth Date: Thu, 6 Nov 2025 21:11:15 -0500 Subject: [PATCH 2/4] Added windowing and basic plotting --- map-app/package-lock.json | 438 ++++++++++++++++++++- map-app/package.json | 4 +- map-app/src/app/MainWindow.tsx | 105 +++++ map-app/src/app/SiteMap.tsx | 44 ++- map-app/src/app/components/DisplayPane.tsx | 120 ++++-- map-app/src/app/components/GraphPane.tsx | 193 +++++++++ map-app/src/app/components/SharedState.tsx | 27 +- map-app/src/app/layout.tsx | 1 + map-app/src/app/page.tsx | 89 +---- 9 files changed, 897 insertions(+), 124 deletions(-) create mode 100644 map-app/src/app/MainWindow.tsx create mode 100644 map-app/src/app/components/GraphPane.tsx diff --git a/map-app/package-lock.json b/map-app/package-lock.json index c4bf8f0..52cb786 100644 --- a/map-app/package-lock.json +++ b/map-app/package-lock.json @@ -13,8 +13,10 @@ "maplibre-gl": "^5.9.0", "next": "15.5.6", "react": "19.1.0", + "react-datepicker": "^8.8.0", "react-dom": "19.1.0", - "react-map-gl": "^8.1.0" + "react-map-gl": "^8.1.0", + "recharts": "^3.3.0" }, "devDependencies": { "@biomejs/biome": "2.2.0", @@ -201,6 +203,54 @@ "tslib": "^2.4.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.27.16", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.16.tgz", + "integrity": "sha512-9O8N4SeG2z++TSM8QA/KTeKFBVCNEz/AGS7gWPJf6KFRzmRWixFRnCnkPHRDwSVZW6QPDO6uT0P2SpWNKCc9/g==", + "dependencies": { + "@floating-ui/react-dom": "^2.1.6", + "@floating-ui/utils": "^0.2.10", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "dependencies": { + "@floating-ui/dom": "^1.7.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==" + }, "node_modules/@img/colour": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", @@ -874,6 +924,41 @@ "node": ">= 10" } }, + "node_modules/@reduxjs/toolkit": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.10.1.tgz", + "integrity": "sha512-/U17EXQ9Do9Yx4DlNGU6eVNfZvFJfYpUtRRdLf19PbPjdWBxNlxGZXywQZ1p1Nz8nMkWplTI7iD/23m07nolDA==", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^10.2.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==" + }, "node_modules/@swc/helpers": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", @@ -1143,6 +1228,60 @@ "tailwindcss": "4.1.14" } }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + }, "node_modules/@types/geojson": { "version": "7946.0.16", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", @@ -1169,7 +1308,7 @@ "version": "19.2.2", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", - "dev": true, + "devOptional": true, "dependencies": { "csstype": "^3.0.2" } @@ -1191,6 +1330,11 @@ "@types/geojson": "*" } }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==" + }, "node_modules/@vis.gl/react-mapbox": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@vis.gl/react-mapbox/-/react-mapbox-8.1.0.tgz", @@ -1313,11 +1457,143 @@ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true + "devOptional": true + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" }, "node_modules/detect-libc": { "version": "2.1.2", @@ -1370,6 +1646,20 @@ "node": ">=10.13.0" } }, + "node_modules/es-toolkit": { + "version": "1.41.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.41.0.tgz", + "integrity": "sha512-bDd3oRmbVgqZCJS6WmeQieOrzpl3URcWBUVDXxOELlUW2FuW+0glPOz1n0KnRie+PdyvUZcXz2sOn00c6pPRIA==", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, "node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", @@ -1416,6 +1706,23 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, + "node_modules/immer": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", + "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -1931,6 +2238,20 @@ "node": ">=0.10.0" } }, + "node_modules/react-datepicker": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-8.8.0.tgz", + "integrity": "sha512-rIJLhww1B5cQY7GYEfSEXvldlGp+GIVU5oE7lxqeK4fmdv5F9bVndplDmblMCvfSMazXmeJ6OHBvRs/PkEhwUQ==", + "dependencies": { + "@floating-ui/react": "^0.27.15", + "clsx": "^2.1.1", + "date-fns": "^4.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, "node_modules/react-dom": { "version": "19.1.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", @@ -1942,6 +2263,12 @@ "react": "^19.1.0" } }, + "node_modules/react-is": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz", + "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==", + "peer": true + }, "node_modules/react-map-gl": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/react-map-gl/-/react-map-gl-8.1.0.tgz", @@ -1965,6 +2292,72 @@ } } }, + "node_modules/react-redux": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/recharts": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.3.0.tgz", + "integrity": "sha512-Vi0qmTB0iz1+/Cz9o5B7irVyUjX2ynvEgImbgMt/3sKRREcUM07QiYjS1QpAVrkmVlXqy5gykq4nGWMz9AS4Rg==", + "dependencies": { + "@reduxjs/toolkit": "1.x.x || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^10.1.1", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.1.1", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.0.0" + } + }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==" + }, "node_modules/resolve-protobuf-schema": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", @@ -2155,6 +2548,11 @@ "kdbush": "^4.0.2" } }, + "node_modules/tabbable": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.3.0.tgz", + "integrity": "sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==" + }, "node_modules/tailwindcss": { "version": "4.1.14", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz", @@ -2190,6 +2588,11 @@ "node": ">=18" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, "node_modules/tinyqueue": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", @@ -2246,6 +2649,35 @@ "node": ">=0.10.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, "node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", diff --git a/map-app/package.json b/map-app/package.json index 3ea4901..5abf13f 100644 --- a/map-app/package.json +++ b/map-app/package.json @@ -15,8 +15,10 @@ "maplibre-gl": "^5.9.0", "next": "15.5.6", "react": "19.1.0", + "react-datepicker": "^8.8.0", "react-dom": "19.1.0", - "react-map-gl": "^8.1.0" + "react-map-gl": "^8.1.0", + "recharts": "^3.3.0" }, "devDependencies": { "@biomejs/biome": "2.2.0", diff --git a/map-app/src/app/MainWindow.tsx b/map-app/src/app/MainWindow.tsx new file mode 100644 index 0000000..b226f27 --- /dev/null +++ b/map-app/src/app/MainWindow.tsx @@ -0,0 +1,105 @@ +'use client' +import { + DockviewReact, + DockviewReadyEvent, + DockviewApi, + IDockviewPanelProps, + DockviewPanelApi, + DockviewGroupPanelApi, + IDockviewPanelHeaderProps +} from "dockview-react"; +import SiteMap from "./SiteMap"; +import { SharedStateProvider, useSharedState } from "./components/SharedState"; +import DisplayPane from "./components/DisplayPane"; +import { useState } from "react"; +import GraphPane from "./components/GraphPane"; +import { themeLight } from "dockview"; +const components = { + default: (props: IDockviewPanelProps<{ title: string; x?: number }>) => { + return ( +
+ {`${props.params.title}`} + {props.params.x && {` ${props.params.x}`}} +
+ ); + }, + mapComponent: (props: IDockviewPanelProps) => { + return ( + + ); + }, + displayPane: (props: IDockviewPanelProps) => { + return ( + + ); + }, + graphPane: (props: IDockviewPanelProps<{ start_date: string; end_date: string, pollutant: string }>) => { + return ( + + ); + }, +}; + +const tabComponents = { + default: (props: IDockviewPanelHeaderProps<{ title: string }>) => { + return ( +
+ {props.params.title} + + +
+ ); + }, +}; + +export default function MainWindow() { + const {sharedState, setSharedState} = useSharedState(); + + const onReady = (event: DockviewReadyEvent) => { + const mapPanel = event.api.addPanel({ + id: 'panel_1', + component: 'mapComponent', + tabComponent: 'default', + params: { + title: 'Map', + }, + }); + + const otherPanel = event.api.addPanel({ + id: 'panel_2', + component: 'displayPane', + tabComponent: 'default', + params: { + title: 'Window 2', + }, + initialWidth: 350, + position: { + direction: 'right', + + }, + }); + setSharedState({...sharedState, api: event.api}); + }; + return ( +
+
+ +
+
+ ); +} \ No newline at end of file diff --git a/map-app/src/app/SiteMap.tsx b/map-app/src/app/SiteMap.tsx index 9fb0bb4..ed20a4e 100644 --- a/map-app/src/app/SiteMap.tsx +++ b/map-app/src/app/SiteMap.tsx @@ -1,5 +1,5 @@ 'use client' -import {useState, useMemo, useContext} from 'react'; +import {useState, useMemo, useContext, useEffect} from 'react'; import 'maplibre-gl/dist/maplibre-gl.css'; import { Map, @@ -13,19 +13,44 @@ import { import * as Pins from "./pin" import { IDockviewPanelProps } from 'dockview-react'; import { AirQualityStation } from './components/AirQualityStation'; -import RAW_SITES from '../../data/near_road_sides.json'; -const SITES: AirQualityStation[] = RAW_SITES as AirQualityStation[]; +import {SITES} from "./components/SharedState"; -import { SharedStateContext, useSharedState } from './components/SharedState'; +import { SharedStateContext, SiteMetaData, useSharedState } from './components/SharedState'; interface SiteMapProps { dockProps: IDockviewPanelProps, }; + export default function SiteMap(props: SiteMapProps) { const [popupInfo, setPopupInfo] = useState(null); const {sharedState, setSharedState} = useSharedState(); + const [loading, setLoading] = useState(true); + const [siteMetaData, setSiteMetaData] = useState(null); + useEffect(() => { + const getSiteMetaData = async () => { + try { + const response = await fetch("http://localhost:8000/sitemetadata/"); + if (!response.ok) { + throw new Error(`Response status: ${response.status}`); + } + + const result = (await response.json()) as SiteMetaData[]; + setSiteMetaData(result); + + } catch (error: any) { + console.error(error.message); + } + finally { + setLoading(false); + } + } + getSiteMetaData(); + }, []); + + + const markers = useMemo(() => SITES.map((site, idx) => ( - )), []); - - + )), [siteMetaData]); + if (loading) { + return
Loading data...
; + } return ( v.site_id == aqs_id); + console.log(aqs_id); + console.log(sharedState.stations); + if(filteredSites?.length == 1) { + return filteredSites[0]; + } + return null; +} + export default function DisplayPane(props: DisplayPaneProps) { const {sharedState, setSharedState} = useSharedState(); - return ( + const site = sharedState?.currentStation; + const metaData = sharedState ? getMetaDataEntry(sharedState) : undefined; + // props.dockProps.api.addPanel() + function plotNO2() { + plotPollutant("NO2", "NO2 1-hour 2010", metaData?.no2_start_date); + } + function plotPM25() { + plotPollutant("PM25", "PM25 24-hour 2006", metaData?.pm_start_date); + } + function plotCO() { + plotPollutant("CO", "CO 8-hour 1971", metaData?.co_start_date); + } + function plotPollutant(pollutantShortName: string, pollutantName: string, start_date: string | null | undefined) { + console.log(sharedState?.api?.groups); -
- {sharedState ? <> + let panel_id = `${sharedState?.currentStation?.["AQS ID"]}_${pollutantShortName}` + let existingPanel = sharedState?.api?.getPanel(panel_id); + let end_date = new Date(start_date ?? "2019-01-01"); + end_date.setFullYear(end_date.getFullYear() + 1); + if(existingPanel) { + existingPanel.focus() + } + else { + sharedState?.api?.addPanel({ + id: panel_id, + component: 'graphPane', + tabComponent: 'default', + params: { + title: `${sharedState?.currentStation?.["Local Site Name"] ?? "Site Name"} | ${pollutantShortName}`, + start_date: start_date, + end_date: `${end_date.getFullYear()}-${end_date.getMonth()}-${end_date.getDay()}`, + pollutant: pollutantName + }, + position: { + referenceGroup: sharedState?.api?.groups[0] + }, + }); + } + } + useEffect(() => { + props.dockProps.api.updateParameters({title: sharedState?.currentStation?.["Local Site Name"] ?? "Site Info"}) + + }, [sharedState]); + return ( + +
+ {site ? <>
-

{sharedState["Local Site Name"]}

-

{sharedState["City"]}, {sharedState.State}

-

AQS ID: {sharedState["AQS ID"]}

+

{site["Local Site Name"]}

+

{site["City"]}, {site.State}

+

AQS ID: {site["AQS ID"]}

-

Latitude: {sharedState.Latitude}

-

Longitude: {sharedState.Longitude}

+

Latitude: {site.Latitude}

+

Longitude: {site.Longitude}

-

Target Road: {sharedState["Target Road"]}

-

County: {sharedState.County}

+

Target Road: {site["Target Road"]}

+

County: {site.County}

-

Population:

+

Population:

    -
  • 2015 - {sharedState["Population 2015"]}
  • -
  • 2020 - {sharedState["Population 2020"]}
  • +
  • 2015 - {site["Population 2015"].toLocaleString('en-US')}
  • +
  • 2020 - {site["Population 2020"].toLocaleString('en-US')}

NO2

-

Start Date: {sharedState["NO2 Start Date"]}

-

Probe Height: {sharedState["NO2 Probe Height (m)"]} meters

+

Start Date: {site["NO2 Start Date"] && new Date(site["NO2 Start Date"]).toDateString()}

+

Probe Height: {site["NO2 Probe Height (m)"]} meters

+

Data Available Starting: {metaData?.no2_start_date && metaData.no2_start_date}

+
- {sharedState["Continuous PM2.5 Start Date"] && + {site["Continuous PM2.5 Start Date"] &&

PM2.5

-

Continuous Start Date: {sharedState["Continuous PM2.5 Start Date"]}

-

Probe Height: {sharedState["Current Cont. PM2.5 method"]}

+

Sampling Start Date: {site["Continuous PM2.5 Start Date"] && new Date(site["Continuous PM2.5 Start Date"]).toDateString()}

+

Sampling Method: {site["Current Cont. PM2.5 method"]}

+

Data Available Starting: {metaData?.pm_start_date}

+ +
} + + + {site["CO Start Date"] &&
+

CO

+

Sampling Start Date: {site["CO Start Date"] && new Date(site["CO Start Date"]).toDateString()}

+

Data Available Starting: {metaData?.co_start_date}

+ +
} + + {/*

Raw JSON

- {JSON.stringify(sharedState)} -
- :

No site selected.

} + {JSON.stringify(site)} +
*/} + :

Select a site to get started.

} + {/* {metaData ?

{JSON.stringify(metaData)}

:

BLAH

} */}
); } \ No newline at end of file diff --git a/map-app/src/app/components/GraphPane.tsx b/map-app/src/app/components/GraphPane.tsx new file mode 100644 index 0000000..15e9653 --- /dev/null +++ b/map-app/src/app/components/GraphPane.tsx @@ -0,0 +1,193 @@ +import { useEffect, useState } from "react"; +import { useSharedState, SharedStateType, SiteMetaData, SITES} from "./SharedState"; +import { IDockviewPanelProps } from "dockview-core"; +import { Line, LineChart, XAxis, YAxis, Tooltip, Legend } from "recharts"; +import DatePicker from "react-datepicker"; + +interface GraphPaneProps { + dockProps: IDockviewPanelProps, + startDate: string, + endDate: string, + pollutant: string +}; + +interface Query { + startDate: Date, + endDate: Date, + aqs_site_id?: string, + pollutant: string +} + +interface ISiteAqiData { + county: string + date: string + pollutant: string + site_id: string + state: string + units: string + value: number + timestamp: Date +} + +class SiteAqiData implements ISiteAqiData { + county: string; + date: string; + pollutant: string; + site_id: string; + state: string; + units: string; + value: number; + + constructor( + county: string, + date: string, + pollutant: string, + site_id: string, + state: string, + units: string, + value: number, + ) { + this.county = county; + this.date = date; + this.pollutant = pollutant; + this.site_id = site_id; + this.state = state; + this.units = units; + this.value = value; + } + get timestamp(): Date { + return new Date(this.date); + } +} + + +export default function GraphPane(props: GraphPaneProps) { + const {sharedState, setSharedState} = useSharedState(); + const [dataset, setDataset] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [isEditingQuery, setIsEditingQuery] = useState(false); + const [query, setQuery] = useState({ + startDate: new Date(props.startDate), + endDate: new Date(props.endDate), + pollutant: props.pollutant, + aqs_site_id: sharedState?.currentStation?.["AQS ID"] + }); + + function formatTicks(date: Date): string { + const options: Intl.DateTimeFormatOptions = { + month: 'short', + year: 'numeric', + }; + return new Intl.DateTimeFormat('en-US', options).format(date); + } + function formatDate(date: Date) { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed + const day = String(date.getDate()).padStart(2, '0'); + return `${year}-${month}-${day}`; + } + + useEffect(() => { + const fetchData = async () => { + try { + let site_id = query.aqs_site_id ?? ""; + var response = await fetch(`http://127.0.0.1:8000/sitemetadata/87/data?site_id=${site_id}&start_date=${formatDate(query.startDate)}&end_date=${formatDate(query.endDate)}`) + if (!response.ok) { + throw new Error(`Response status: ${response.status}`); + } + + const result = (await response.json()) as SiteAqiData[]; + if(result.length == 0) { + setDataset([]); + } + else { + result.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()) + setDataset(result); + } + setIsLoading(false); + } + catch(ex: any) { + console.error(ex.message); + } + }; + if(!isEditingQuery) { + fetchData(); + } + }, [query, isEditingQuery]); + + function handleFormSubmit(e: React.FormEvent) { + e.preventDefault(); + let form = e.currentTarget; + let site = form.elements.namedItem("site") as HTMLInputElement; + let pollutant = form.elements.namedItem("pollutant") as HTMLInputElement; + setQuery({...query, aqs_site_id: site.value, pollutant: pollutant.value}); + setIsEditingQuery(false); + } + if(isLoading) { + return
Loading data...
+ } + + if(isEditingQuery) { + return ( +
+

Query Panel

+
+
+
+

Start Date:

+ setQuery({...query, startDate: date ?? new Date()})}/> +
+
+

End Date:

+ setQuery({...query, endDate: date ?? new Date()})}/> +
+
+

Site:

+ {SITES && + + } +
+
+

Pollutant:

+ +
+
+ +
+
+ ) + } + + + + return ( +
+
+ +
+ {dataset.length != 0 ? <> + + formatTicks(new Date(unixTime))}/> + + + + + + :

No data was found. Please try again.

} + + +
+ + ) +} \ No newline at end of file diff --git a/map-app/src/app/components/SharedState.tsx b/map-app/src/app/components/SharedState.tsx index 8de7684..7d73c99 100644 --- a/map-app/src/app/components/SharedState.tsx +++ b/map-app/src/app/components/SharedState.tsx @@ -1,16 +1,37 @@ // src/SharedContext.js import React, { createContext, useState, useContext, Dispatch, SetStateAction } from 'react'; import { AirQualityStation } from './AirQualityStation'; +import { DockviewApi } from 'dockview-core'; +import RAW_SITES from '../../../data/near_road_sides.json'; +export const SITES: AirQualityStation[] = RAW_SITES as AirQualityStation[]; +export interface SiteMetaData { + city: string + co_start_date: string | null + county: string + latitude: number + longitude: number + no2_start_date: string | null + pm_start_date: string | null + site_id: string + state: string + url: string +} + // 1. Define the Context +export interface SharedStateType { + currentStation?: AirQualityStation | null, + stations?: SiteMetaData[] | null, + api?: DockviewApi +} interface SharedStateContextType { - sharedState: AirQualityStation | null, - setSharedState: Dispatch> + sharedState: SharedStateType | null + setSharedState: Dispatch> } export const SharedStateContext = createContext(undefined); // 2. Create the Provider component export const SharedStateProvider = ({ children }: any) => { - const [sharedState, setSharedState] = useState(null); + const [sharedState, setSharedState] = useState(null); const contextValue: SharedStateContextType = { sharedState, setSharedState, diff --git a/map-app/src/app/layout.tsx b/map-app/src/app/layout.tsx index 7ad62a6..66cc2d9 100644 --- a/map-app/src/app/layout.tsx +++ b/map-app/src/app/layout.tsx @@ -1,5 +1,6 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; +import "react-datepicker/dist/react-datepicker.css"; import "./globals.css"; import 'dockview/dist/styles/dockview.css'; diff --git a/map-app/src/app/page.tsx b/map-app/src/app/page.tsx index b7d4bf5..13a4aa0 100644 --- a/map-app/src/app/page.tsx +++ b/map-app/src/app/page.tsx @@ -9,97 +9,16 @@ import { IDockviewPanelHeaderProps } from "dockview-react"; import SiteMap from "./SiteMap"; -import { SharedStateProvider } from "./components/SharedState"; +import { SharedStateProvider, useSharedState } from "./components/SharedState"; import DisplayPane from "./components/DisplayPane"; -const components = { - default: (props: IDockviewPanelProps<{ title: string; x?: number }>) => { - return ( -
- {`${props.params.title}`} - {props.params.x && {` ${props.params.x}`}} -
- ); - }, - mapComponent: (props: IDockviewPanelProps) => { - return ( - - ); - }, - displayPane: (props: IDockviewPanelProps) => { - return ( - - ); - }, -}; - -const tabComponents = { - default: (props: IDockviewPanelHeaderProps<{ title: string }>) => { - return ( -
- {props.params.title} - - - {/* - minimize - - - maximize - - - close - */} -
- ); - }, -}; +import MainWindow from "./MainWindow"; const Home = () => { - const onReady = (event: DockviewReadyEvent) => { - const mapPanel = event.api.addPanel({ - id: 'panel_1', - component: 'mapComponent', - tabComponent: 'default', - params: { - title: 'Map', - }, - }); - - const otherPanel = event.api.addPanel({ - id: 'panel_2', - component: 'displayPane', - tabComponent: 'default', - params: { - title: 'Window 2', - }, - initialWidth: 350, - position: { - direction: 'right', - - }, - }); - }; + return ( -
-
- -
-
+
); } From a50a8152b768a364533f0eac1b948424f9b5654f Mon Sep 17 00:00:00 2001 From: Tyler Duckworth Date: Fri, 7 Nov 2025 14:47:56 -0500 Subject: [PATCH 3/4] Added further improvements and cleaned up styling --- map-app/src/app/MainWindow.tsx | 24 ++++++++++++------- map-app/src/app/components/DisplayPane.tsx | 9 ++++--- map-app/src/app/components/GraphPane.tsx | 28 +++++++++++++--------- map-app/src/app/globals.css | 4 ++++ 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/map-app/src/app/MainWindow.tsx b/map-app/src/app/MainWindow.tsx index b226f27..1328927 100644 --- a/map-app/src/app/MainWindow.tsx +++ b/map-app/src/app/MainWindow.tsx @@ -6,7 +6,8 @@ import { IDockviewPanelProps, DockviewPanelApi, DockviewGroupPanelApi, - IDockviewPanelHeaderProps + IDockviewPanelHeaderProps, + DockviewDefaultTab } from "dockview-react"; import SiteMap from "./SiteMap"; import { SharedStateProvider, useSharedState } from "./components/SharedState"; @@ -51,11 +52,12 @@ const components = { const tabComponents = { default: (props: IDockviewPanelHeaderProps<{ title: string }>) => { return ( -
- {props.params.title} - - -
+ + ); + }, + nonClosableTab: (props: IDockviewPanelHeaderProps<{ title: string }>) => { + return ( + ); }, }; @@ -67,7 +69,8 @@ export default function MainWindow() { const mapPanel = event.api.addPanel({ id: 'panel_1', component: 'mapComponent', - tabComponent: 'default', + tabComponent: 'nonClosableTab', + title: "Map", params: { title: 'Map', }, @@ -76,7 +79,8 @@ export default function MainWindow() { const otherPanel = event.api.addPanel({ id: 'panel_2', component: 'displayPane', - tabComponent: 'default', + tabComponent: 'nonClosableTab', + title: "Site Info", params: { title: 'Window 2', }, @@ -96,8 +100,10 @@ export default function MainWindow() { onReady={onReady} theme={themeLight} components={components} + // defaultTabComponent={tabComponents.default} tabComponents={tabComponents} - singleTabMode="fullwidth" + // singleTabMode="fullwidth" + scrollbars="native" /> diff --git a/map-app/src/app/components/DisplayPane.tsx b/map-app/src/app/components/DisplayPane.tsx index aaae100..03dde2b 100644 --- a/map-app/src/app/components/DisplayPane.tsx +++ b/map-app/src/app/components/DisplayPane.tsx @@ -47,9 +47,9 @@ export default function DisplayPane(props: DisplayPaneProps) { sharedState?.api?.addPanel({ id: panel_id, component: 'graphPane', - tabComponent: 'default', + title: `${sharedState?.currentStation?.["Local Site Name"] ?? "Site Name"} | ${pollutantShortName}`, + // tabComponent: 'default', params: { - title: `${sharedState?.currentStation?.["Local Site Name"] ?? "Site Name"} | ${pollutantShortName}`, start_date: start_date, end_date: `${end_date.getFullYear()}-${end_date.getMonth()}-${end_date.getDay()}`, pollutant: pollutantName @@ -61,12 +61,11 @@ export default function DisplayPane(props: DisplayPaneProps) { } } useEffect(() => { - props.dockProps.api.updateParameters({title: sharedState?.currentStation?.["Local Site Name"] ?? "Site Info"}) - + props.dockProps.api.setTitle(sharedState?.currentStation?.["Local Site Name"] ?? "Site Info"); }, [sharedState]); return ( -
+
{site ? <>

{site["Local Site Name"]}

diff --git a/map-app/src/app/components/GraphPane.tsx b/map-app/src/app/components/GraphPane.tsx index 15e9653..236c1c5 100644 --- a/map-app/src/app/components/GraphPane.tsx +++ b/map-app/src/app/components/GraphPane.tsx @@ -67,23 +67,28 @@ export default function GraphPane(props: GraphPaneProps) { const [isLoading, setIsLoading] = useState(false); const [isEditingQuery, setIsEditingQuery] = useState(false); const [query, setQuery] = useState({ - startDate: new Date(props.startDate), - endDate: new Date(props.endDate), + startDate: getDateFromString(props.startDate), + endDate: getDateFromString(props.endDate), pollutant: props.pollutant, aqs_site_id: sharedState?.currentStation?.["AQS ID"] }); + function getDateFromString(dateString: string): Date { + const [year, month, day] = dateString.split('-'); + return new Date(+year, +month - 1, +day); + } function formatTicks(date: Date): string { const options: Intl.DateTimeFormatOptions = { month: 'short', year: 'numeric', + timeZone: "UTC" }; return new Intl.DateTimeFormat('en-US', options).format(date); } function formatDate(date: Date) { - const year = date.getFullYear(); - const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed - const day = String(date.getDate()).padStart(2, '0'); + const year = date.getUTCFullYear(); + const month = String(date.getUTCMonth() + 1).padStart(2, '0'); // Months are 0-indexed + const day = String(date.getUTCDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } @@ -135,16 +140,16 @@ export default function GraphPane(props: GraphPaneProps) {

Start Date:

- setQuery({...query, startDate: date ?? new Date()})}/> + setQuery({...query, startDate: date ?? new Date()})}/>

End Date:

- setQuery({...query, endDate: date ?? new Date()})}/> + setQuery({...query, endDate: date ?? new Date()})}/>

Site:

{SITES && - {SITES.map(s => ( ))} @@ -153,14 +158,14 @@ export default function GraphPane(props: GraphPaneProps) {

Pollutant:

-
- +
) @@ -184,7 +189,8 @@ export default function GraphPane(props: GraphPaneProps) { - :

No data was found. Please try again.

} + :
+

No data was found. Please try again.

}
diff --git a/map-app/src/app/globals.css b/map-app/src/app/globals.css index 493557c..a4ce59e 100644 --- a/map-app/src/app/globals.css +++ b/map-app/src/app/globals.css @@ -41,3 +41,7 @@ body { border-radius: 2px; background-color: var(--dv-icon-hover-background-color); } + +.dv-default-tab-content { + padding-left: 0.5rem; +} \ No newline at end of file From c65d0eaa55c76f18de7e5628f7d76b9b855060ca Mon Sep 17 00:00:00 2001 From: Tyler Duckworth Date: Mon, 17 Nov 2025 14:23:47 -0500 Subject: [PATCH 4/4] Fixed a few issues and changed the labeling on the charts. --- map-app/src/app/MainWindow.tsx | 10 +- map-app/src/app/SiteMap.tsx | 2 +- map-app/src/app/components/DisplayPane.tsx | 31 +++--- map-app/src/app/components/GraphPane.tsx | 96 ++++++++----------- map-app/src/app/components/SharedState.tsx | 19 ++-- .../AirQualityStation.tsx | 0 map-app/src/app/types/SiteAqiData.tsx | 41 ++++++++ map-app/src/app/types/SiteMetaData.tsx | 12 +++ 8 files changed, 121 insertions(+), 90 deletions(-) rename map-app/src/app/{components => types}/AirQualityStation.tsx (100%) create mode 100644 map-app/src/app/types/SiteAqiData.tsx create mode 100644 map-app/src/app/types/SiteMetaData.tsx diff --git a/map-app/src/app/MainWindow.tsx b/map-app/src/app/MainWindow.tsx index 1328927..970c721 100644 --- a/map-app/src/app/MainWindow.tsx +++ b/map-app/src/app/MainWindow.tsx @@ -15,6 +15,7 @@ import DisplayPane from "./components/DisplayPane"; import { useState } from "react"; import GraphPane from "./components/GraphPane"; import { themeLight } from "dockview"; + const components = { default: (props: IDockviewPanelProps<{ title: string; x?: number }>) => { return ( @@ -42,9 +43,14 @@ const components = { ); }, - graphPane: (props: IDockviewPanelProps<{ start_date: string; end_date: string, pollutant: string }>) => { + graphPane: (props: IDockviewPanelProps<{ start_date: string; end_date: string, pollutant: string, label: string }>) => { return ( - + ); }, }; diff --git a/map-app/src/app/SiteMap.tsx b/map-app/src/app/SiteMap.tsx index ed20a4e..70a3a55 100644 --- a/map-app/src/app/SiteMap.tsx +++ b/map-app/src/app/SiteMap.tsx @@ -12,7 +12,7 @@ import { } from 'react-map-gl/maplibre'; import * as Pins from "./pin" import { IDockviewPanelProps } from 'dockview-react'; -import { AirQualityStation } from './components/AirQualityStation'; +import { AirQualityStation } from './types/AirQualityStation'; import {SITES} from "./components/SharedState"; diff --git a/map-app/src/app/components/DisplayPane.tsx b/map-app/src/app/components/DisplayPane.tsx index 03dde2b..d138a0d 100644 --- a/map-app/src/app/components/DisplayPane.tsx +++ b/map-app/src/app/components/DisplayPane.tsx @@ -1,7 +1,8 @@ import { useEffect } from "react"; import { metadata } from "../layout"; -import { useSharedState, SharedStateType, SiteMetaData } from "./SharedState"; +import { useSharedState, SharedStateType } from "./SharedState"; import { DockviewApi, IDockviewPanelProps } from "dockview-core"; +import { SiteMetaData } from "../types/SiteMetaData"; interface DisplayPaneProps { dockProps: IDockviewPanelProps, @@ -9,10 +10,7 @@ interface DisplayPaneProps { function getMetaDataEntry(sharedState: SharedStateType): SiteMetaData | null { let aqs_id = sharedState.currentStation?.["AQS ID"]; - let filteredSites = sharedState.stations?.filter(v => v.site_id == aqs_id); - console.log(aqs_id); - console.log(sharedState.stations); if(filteredSites?.length == 1) { return filteredSites[0]; } @@ -23,18 +21,20 @@ export default function DisplayPane(props: DisplayPaneProps) { const {sharedState, setSharedState} = useSharedState(); const site = sharedState?.currentStation; const metaData = sharedState ? getMetaDataEntry(sharedState) : undefined; - // props.dockProps.api.addPanel() + function plotNO2() { - plotPollutant("NO2", "NO2 1-hour 2010", metaData?.no2_start_date); + plotPollutant("NO2", "NO2 1-hour 2010", metaData?.no2_start_date, "Nitrogen Dioxide (NO2)"); } + function plotPM25() { - plotPollutant("PM25", "PM25 24-hour 2006", metaData?.pm_start_date); + plotPollutant("PM25", "PM25 24-hour 2006", metaData?.pm_start_date, "Fine Particulate Matter (PM2.5)"); } + function plotCO() { - plotPollutant("CO", "CO 8-hour 1971", metaData?.co_start_date); + plotPollutant("CO", "CO 8-hour 1971", metaData?.co_start_date, "Carbon Monoxide (CO)"); } - function plotPollutant(pollutantShortName: string, pollutantName: string, start_date: string | null | undefined) { - console.log(sharedState?.api?.groups); + + function plotPollutant(pollutantShortName: string, pollutantName: string, start_date: string | null | undefined, label: string) { let panel_id = `${sharedState?.currentStation?.["AQS ID"]}_${pollutantShortName}` let existingPanel = sharedState?.api?.getPanel(panel_id); @@ -52,7 +52,8 @@ export default function DisplayPane(props: DisplayPaneProps) { params: { start_date: start_date, end_date: `${end_date.getFullYear()}-${end_date.getMonth()}-${end_date.getDay()}`, - pollutant: pollutantName + pollutant: pollutantName, + label: label }, position: { referenceGroup: sharedState?.api?.groups[0] @@ -60,9 +61,11 @@ export default function DisplayPane(props: DisplayPaneProps) { }); } } + useEffect(() => { props.dockProps.api.setTitle(sharedState?.currentStation?.["Local Site Name"] ?? "Site Info"); }, [sharedState]); + return (
@@ -110,12 +113,8 @@ export default function DisplayPane(props: DisplayPaneProps) {
} - {/*
-

Raw JSON

- {JSON.stringify(site)} -
*/} + :

Select a site to get started.

} - {/* {metaData ?

{JSON.stringify(metaData)}

:

BLAH

} */}
); } \ No newline at end of file diff --git a/map-app/src/app/components/GraphPane.tsx b/map-app/src/app/components/GraphPane.tsx index 236c1c5..e2b6384 100644 --- a/map-app/src/app/components/GraphPane.tsx +++ b/map-app/src/app/components/GraphPane.tsx @@ -1,63 +1,24 @@ import { useEffect, useState } from "react"; -import { useSharedState, SharedStateType, SiteMetaData, SITES} from "./SharedState"; +import { useSharedState, SharedStateType, SITES} from "./SharedState"; import { IDockviewPanelProps } from "dockview-core"; -import { Line, LineChart, XAxis, YAxis, Tooltip, Legend } from "recharts"; +import { Line, LineChart, XAxis, YAxis, Tooltip, Legend, Label } from "recharts"; import DatePicker from "react-datepicker"; +import SiteAqiData from "../types/SiteAqiData"; interface GraphPaneProps { dockProps: IDockviewPanelProps, startDate: string, endDate: string, - pollutant: string + pollutant: string, + label: string }; -interface Query { +interface GraphQuery { startDate: Date, endDate: Date, aqs_site_id?: string, - pollutant: string -} - -interface ISiteAqiData { - county: string - date: string - pollutant: string - site_id: string - state: string - units: string - value: number - timestamp: Date -} - -class SiteAqiData implements ISiteAqiData { - county: string; - date: string; - pollutant: string; - site_id: string; - state: string; - units: string; - value: number; - - constructor( - county: string, - date: string, - pollutant: string, - site_id: string, - state: string, - units: string, - value: number, - ) { - this.county = county; - this.date = date; - this.pollutant = pollutant; - this.site_id = site_id; - this.state = state; - this.units = units; - this.value = value; - } - get timestamp(): Date { - return new Date(this.date); - } + pollutant: string, + label: string } @@ -66,23 +27,36 @@ export default function GraphPane(props: GraphPaneProps) { const [dataset, setDataset] = useState([]); const [isLoading, setIsLoading] = useState(false); const [isEditingQuery, setIsEditingQuery] = useState(false); - const [query, setQuery] = useState({ + const [query, setQuery] = useState({ startDate: getDateFromString(props.startDate), endDate: getDateFromString(props.endDate), pollutant: props.pollutant, - aqs_site_id: sharedState?.currentStation?.["AQS ID"] + aqs_site_id: sharedState?.currentStation?.["AQS ID"], + label: props.label }); + const [yLabel, setyLabel] = useState(); function getDateFromString(dateString: string): Date { const [year, month, day] = dateString.split('-'); return new Date(+year, +month - 1, +day); } function formatTicks(date: Date): string { - const options: Intl.DateTimeFormatOptions = { - month: 'short', - year: 'numeric', - timeZone: "UTC" - }; + let daysOverRange = (query.endDate.getTime() - query.startDate.getTime()) / ( 1000 * 60 * 60 * 24); + + let options: Intl.DateTimeFormatOptions; + if(daysOverRange > 31) { + options = { + month: 'short', + year: 'numeric', + timeZone: "UTC" + }; + } + else { + options = { + month: '2-digit', + day: '2-digit' + }; + } return new Intl.DateTimeFormat('en-US', options).format(date); } function formatDate(date: Date) { @@ -96,7 +70,7 @@ export default function GraphPane(props: GraphPaneProps) { const fetchData = async () => { try { let site_id = query.aqs_site_id ?? ""; - var response = await fetch(`http://127.0.0.1:8000/sitemetadata/87/data?site_id=${site_id}&start_date=${formatDate(query.startDate)}&end_date=${formatDate(query.endDate)}`) + var response = await fetch(`http://127.0.0.1:8000/sitemetadata/87/data?site_id=${site_id}&start_date=${formatDate(query.startDate)}&end_date=${formatDate(query.endDate)}&pollutant=${query.pollutant}`) if (!response.ok) { throw new Error(`Response status: ${response.status}`); } @@ -108,6 +82,7 @@ export default function GraphPane(props: GraphPaneProps) { else { result.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()) setDataset(result); + setyLabel(result[0].units) } setIsLoading(false); } @@ -128,6 +103,7 @@ export default function GraphPane(props: GraphPaneProps) { setQuery({...query, aqs_site_id: site.value, pollutant: pollutant.value}); setIsEditingQuery(false); } + if(isLoading) { return
Loading data...
} @@ -180,15 +156,19 @@ export default function GraphPane(props: GraphPaneProps) { {dataset.length != 0 ? <> + style={{ width: '100%', maxWidth: '850px', height: '100%', maxHeight: '70vh', aspectRatio: 1.618 }} + margin={{left:20}} + > formatTicks(new Date(unixTime))}/> - + + - +

:

No data was found. Please try again.

} diff --git a/map-app/src/app/components/SharedState.tsx b/map-app/src/app/components/SharedState.tsx index 7d73c99..99ba65c 100644 --- a/map-app/src/app/components/SharedState.tsx +++ b/map-app/src/app/components/SharedState.tsx @@ -1,21 +1,14 @@ // src/SharedContext.js import React, { createContext, useState, useContext, Dispatch, SetStateAction } from 'react'; -import { AirQualityStation } from './AirQualityStation'; +import { AirQualityStation } from '../types/AirQualityStation'; import { DockviewApi } from 'dockview-core'; import RAW_SITES from '../../../data/near_road_sides.json'; +import { SiteMetaData } from '../types/SiteMetaData'; + + export const SITES: AirQualityStation[] = RAW_SITES as AirQualityStation[]; -export interface SiteMetaData { - city: string - co_start_date: string | null - county: string - latitude: number - longitude: number - no2_start_date: string | null - pm_start_date: string | null - site_id: string - state: string - url: string -} + + // 1. Define the Context export interface SharedStateType { diff --git a/map-app/src/app/components/AirQualityStation.tsx b/map-app/src/app/types/AirQualityStation.tsx similarity index 100% rename from map-app/src/app/components/AirQualityStation.tsx rename to map-app/src/app/types/AirQualityStation.tsx diff --git a/map-app/src/app/types/SiteAqiData.tsx b/map-app/src/app/types/SiteAqiData.tsx new file mode 100644 index 0000000..72860b5 --- /dev/null +++ b/map-app/src/app/types/SiteAqiData.tsx @@ -0,0 +1,41 @@ +interface ISiteAqiData { + county: string + date: string + pollutant: string + site_id: string + state: string + units: string + value: number + timestamp: Date +} + +export default class SiteAqiData implements ISiteAqiData { + county: string; + date: string; + pollutant: string; + site_id: string; + state: string; + units: string; + value: number; + + constructor( + county: string, + date: string, + pollutant: string, + site_id: string, + state: string, + units: string, + value: number, + ) { + this.county = county; + this.date = date; + this.pollutant = pollutant; + this.site_id = site_id; + this.state = state; + this.units = units; + this.value = value; + } + get timestamp(): Date { + return new Date(this.date); + } +} \ No newline at end of file diff --git a/map-app/src/app/types/SiteMetaData.tsx b/map-app/src/app/types/SiteMetaData.tsx new file mode 100644 index 0000000..1a7f4c2 --- /dev/null +++ b/map-app/src/app/types/SiteMetaData.tsx @@ -0,0 +1,12 @@ +export interface SiteMetaData { + city: string + co_start_date: string | null + county: string + latitude: number + longitude: number + no2_start_date: string | null + pm_start_date: string | null + site_id: string + state: string + url: string +} \ No newline at end of file