diff options
author | Jakob Stendahl <jakob.stendahl@outlook.com> | 2022-04-28 01:32:54 +0200 |
---|---|---|
committer | Jakob Stendahl <jakob.stendahl@outlook.com> | 2022-04-28 01:33:08 +0200 |
commit | 55cd53f4e6b1e13d2866a84a9631be8f89651cf2 (patch) | |
tree | 5b77ffc3311b490d4f979055e97823011280aace | |
parent | ae52909d00cdcda30d6ed07e302c0a50abe70b75 (diff) | |
download | Aurora-data-55cd53f4e6b1e13d2866a84a9631be8f89651cf2.tar.gz Aurora-data-55cd53f4e6b1e13d2866a84a9631be8f89651cf2.zip |
Add one hour forecast
-rw-r--r-- | src/components/Basic/Bar.svelte | 48 | ||||
-rw-r--r-- | src/components/Forecast/ForecastDrawer.svelte | 108 | ||||
-rw-r--r-- | src/components/Forecast/OneHourForecast/OneHourForecast.svelte | 76 | ||||
-rw-r--r-- | src/components/Forecast/OneHourForecast/PredictionItem.svelte | 91 | ||||
-rw-r--r-- | src/components/Forecast/ThreeDayForecast/PredictionItem.svelte (renamed from src/components/PredictedSpaceWeatherThing.svelte) | 2 | ||||
-rw-r--r-- | src/components/Forecast/ThreeDayForecast/ThreeDayForecast.svelte (renamed from src/components/PredictedSpaceWeather.svelte) | 78 | ||||
-rw-r--r-- | src/routes/index.svelte | 4 | ||||
-rw-r--r-- | src/stores.ts | 8 |
8 files changed, 338 insertions, 77 deletions
diff --git a/src/components/Basic/Bar.svelte b/src/components/Basic/Bar.svelte new file mode 100644 index 0000000..7b17c3e --- /dev/null +++ b/src/components/Basic/Bar.svelte @@ -0,0 +1,48 @@ +<script lang="ts"> + export let percentage = 0.7; + export let vertical = false; +</script> + +<style> + :root { + --progress: 100%; + } + + .wrapper { + position: relative; + background-color: #c6c6c6; + border-radius:15px; + width: 100%; + height: 100%; + } + + .bar-wrapper { + overflow: hidden; + position: relative; + border-radius: 15px; + height: 100%; + width: 100%; + top: calc(100% - var(--progress)); + } + + .bar { + position: absolute; + height: 100%; + width: 100%; + bottom: calc(100% - var(--progress)); + overflow: hidden; + background: linear-gradient(0deg, + rgba(217,217,217,1) 0%, + rgba(164,255,177,1) 70%, + rgba(255,136,240,1) 100%); + border-radius: 15px; + } +</style> + +<div> + <div class="wrapper" class:vertical style="--progress: {percentage*100}%"> + <div class="bar-wrapper"> + <div class="bar"></div> + </div> + </div> +</div> diff --git a/src/components/Forecast/ForecastDrawer.svelte b/src/components/Forecast/ForecastDrawer.svelte new file mode 100644 index 0000000..b47a810 --- /dev/null +++ b/src/components/Forecast/ForecastDrawer.svelte @@ -0,0 +1,108 @@ +<script lang="ts"> + import OneHourForecast from "./OneHourForecast/OneHourForecast.svelte"; + import ThreeDayForecast from "./ThreeDayForecast/ThreeDayForecast.svelte"; + + import { earth_weather, space_weather } from "../../stores.ts"; + + let selected_version = ThreeDayForecast; + +</script> + +<style> + .drawer { + border-top-left-radius: 2rem; + border-top-right-radius: 2rem; + --bg-opacity: 1; + background-color: #f7fafc; + background-color: rgba(247, 250, 252, var(--bg-opacity)); + padding: 1.5rem; + --text-opacity: 1; + color: #1a202c; + color: rgba(26, 32, 44, var(--text-opacity)); + height: 100%; + overflow: hidden; + align-self: stretch; + box-shadow: 0px -6px 7px 0px black; + } + + @media (min-width: 640px), (min-height: 720px) { + .drawer { + padding: 2rem; + padding-top: 1.5rem; + } + } + + @media (min-width: 640px) { + .drawer { + border-bottom-right-radius: 1rem; + border-bottom-left-radius: 1rem; + } + } + + .drawer .header { + display: flex; + align-items: flex-start; + } + + .drawer h2 { + text-transform: uppercase; + font-size: 0.875rem; + letter-spacing: 0.1em; + font-weight: 700; + margin-top: 0.25rem; + margin-bottom: 0.5rem; + margin-right: auto; + } + + .version-picker { + display: flex; + font-size: 0.875rem; + gap: 0.5rem; + align-items: center; + color: #616161; + } + .version-picker > * { + transition: all 0.1s ease; + } + + .version-picker .selected { + background-color: #c2c2c2; + padding: 3px 5px; + box-sizing: border-box; + border-radius: 10px; + color: black; + } + + .no-data { + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + color: grey; + + } + + .no-data { + margin-top: 1rem; + } +</style> + +<div class="drawer"> + {#if !$earth_weather.updating && !$space_weather.updating} + <div class="header"> + <h2>Forecast</h2> + <div class="version-picker"> + <div class:selected={selected_version == OneHourForecast} on:click={() => selected_version = OneHourForecast}>hour</div> + <div class:selected={selected_version == ThreeDayForecast} on:click={() => selected_version = ThreeDayForecast}>3 day</div> + </div> + </div> + <svelte:component this={selected_version} /> + {:else} + <div class="no-data"> + <i class="fas fa-7x fa-exclamation-triangle"></i> + <p>No prediction data</p> + </div> + {/if} +</div> diff --git a/src/components/Forecast/OneHourForecast/OneHourForecast.svelte b/src/components/Forecast/OneHourForecast/OneHourForecast.svelte new file mode 100644 index 0000000..3222dc8 --- /dev/null +++ b/src/components/Forecast/OneHourForecast/OneHourForecast.svelte @@ -0,0 +1,76 @@ +<script lang="ts"> + import PredictionItem from './PredictionItem.svelte'; + + import { onMount } from 'svelte'; + import { earth_weather, space_weather } from '../../../stores'; + + const monthNames = ["January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + ]; + + let predictions; + + space_weather.subscribe(assembleWeatherData); + earth_weather.subscribe(assembleWeatherData); + + async function assembleWeatherData() { + if ($space_weather.updating || $earth_weather.updating) { + predictions = null; + return; + } + + // First just reorganize the space_weather data + let forecast = $space_weather.usnoaa_data_raw.geospace_pred_est_kp_1_hour.filter(x => x.model_prediction_time >= new Date()); + predictions = forecast.map( + pred => ({ + "time": pred.model_prediction_time, + "kp": Math.round(pred.k), + "temp": null, + "clouds": null, + "hasNOMETData": $earth_weather.available + }) + ); + + // Add earth weather data if it is available + if ($earth_weather.available) { + predictions.forEach((pred, i) => { + let closestDate = new Date(0,0,0); + let temp; + let clouds; + + $earth_weather.yr_data_raw.properties.timeseries.forEach((earth_pred, i) => { + let predDate = new Date(earth_pred.time); + if (Math.abs(predDate.getTime() - pred.time.getTime()) < Math.abs(closestDate.getTime() - pred.time.getTime())) { + closestDate = predDate; + temp = (earth_pred["data"]["instant"]["details"]["air_temperature"]); + clouds = earth_pred["data"]["instant"]["details"]["cloud_area_fraction"]; + } + }); + + predictions[i] = { + ...predictions[i], "temp": temp, "clouds": clouds + } + }); + } + + } + +</script> + +<style> + .prediction-table { + height: 100%; + overflow-y: scroll; + padding-bottom: 1rem; + } + + .prediction-table::-webkit-scrollbar { + display: none; + } +</style> + +<div class="prediction-table"> + {#each predictions as prediction, i} + <PredictionItem {prediction}/> + {/each} +</div> diff --git a/src/components/Forecast/OneHourForecast/PredictionItem.svelte b/src/components/Forecast/OneHourForecast/PredictionItem.svelte new file mode 100644 index 0000000..201c4f5 --- /dev/null +++ b/src/components/Forecast/OneHourForecast/PredictionItem.svelte @@ -0,0 +1,91 @@ +<script> + import Chip from "../../Basic/Chip.svelte"; + + export let prediction; + + const monthNames = ["January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + ]; + + function zpad(value, n=2) { + let r = value; + for (let i = 0; i < n - value.length; i++) { + r = "0" + r; + } + return r; + } + + let kp = prediction["kp"]; + let date = prediction["time"].getDate() + ". " + monthNames[prediction["time"].getMonth()]; + let time = zpad(prediction["time"].getHours().toString()) + ":" + zpad(prediction["time"].getMinutes().toString()); + let temp = prediction["temp"]; + let clouds = prediction["clouds"]; + let hasNOMETData = prediction["hasNOMETData"]; +</script> + +<style> + .prediction-details { + display: flex; + border-bottom-width: 1px; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + font-size: 0.75rem; + letter-spacing: 0.05em; + align-items: center; + } + + .prediction-details:last-of-type { + border-width: 0; + padding-bottom: 0; + } + + .prediction-details > * { + margin: 5px; + } + + .prediction-details div:last-child { + margin-left: auto; + } + + .prediction-details h3 { + font-size: 0.875rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + margin-right: 0.5rem; + } + + .prediction-details .data { + display: flex; + flex-direction: row; + } + + .prediction-details .data h2 { + margin-right: 1rem; + font-size: 1.5rem; + } + .prediction-details .data p { + min-width: 3.3rem; + } + .prediction-details .data i { + width: 1rem; + text-align: center; + } + +</style> + +<div class="prediction-details"> + <div> + <h3>{time}</h3> + <p>{date}</p> + </div> + <div class="data"> + <h2>{kp}</h2> + {#if hasNOMETData} + <div> + <p><i class="fas fa-thermometer-half"></i> {Math.round(temp)}°C</p> + <p><i class="fas fa-cloud"></i> {Math.round(clouds)}%</p> + </div> + {/if} + </div> +</div> diff --git a/src/components/PredictedSpaceWeatherThing.svelte b/src/components/Forecast/ThreeDayForecast/PredictionItem.svelte index 13bf1c2..0d4a94d 100644 --- a/src/components/PredictedSpaceWeatherThing.svelte +++ b/src/components/Forecast/ThreeDayForecast/PredictionItem.svelte @@ -1,5 +1,5 @@ <script> - import Chip from "./Basic/Chip.svelte"; + import Chip from "../../Basic/Chip.svelte"; export let prediction; diff --git a/src/components/PredictedSpaceWeather.svelte b/src/components/Forecast/ThreeDayForecast/ThreeDayForecast.svelte index 2282a40..7e13c2b 100644 --- a/src/components/PredictedSpaceWeather.svelte +++ b/src/components/Forecast/ThreeDayForecast/ThreeDayForecast.svelte @@ -1,8 +1,8 @@ <script lang="ts"> - import PredictedSpaceWeatherThing from './PredictedSpaceWeatherThing.svelte'; + import PredictionItem from './PredictionItem.svelte'; import { onMount } from 'svelte'; - import { earth_weather, space_weather } from '../stores'; + import { earth_weather, space_weather } from '../../../stores'; const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" @@ -59,45 +59,6 @@ </script> <style> - .predicted-weather { - border-top-left-radius: 2rem; - border-top-right-radius: 2rem; - --bg-opacity: 1; - background-color: #f7fafc; - background-color: rgba(247, 250, 252, var(--bg-opacity)); - padding: 1.5rem; - --text-opacity: 1; - color: #1a202c; - color: rgba(26, 32, 44, var(--text-opacity)); - height: 100%; - overflow: hidden; - align-self: stretch; - box-shadow: 0px -6px 7px 0px black; - } - - @media (min-width: 640px), (min-height: 720px) { - .predicted-weather { - padding: 2rem; - padding-top: 1.5rem; - } - } - - @media (min-width: 640px) { - .predicted-weather { - border-bottom-right-radius: 1rem; - border-bottom-left-radius: 1rem; - } - } - - .predicted-weather h2 { - text-transform: uppercase; - font-size: 0.875rem; - letter-spacing: 0.1em; - font-weight: 700; - margin-top: 0.25rem; - margin-bottom: 0.5rem; - } - .prediction-table { height: 100%; overflow-y: scroll; @@ -107,37 +68,10 @@ .prediction-table::-webkit-scrollbar { display: none; } - - .no-data { - height: 100%; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - text-align: center; - color: grey; - - } - - .no-data { - margin-top: 1rem; - } </style> -<div class="predicted-weather"> - {#if predictions} - <div className="flex flex-row justify-between items-top"> - <h2>Predicted</h2> - </div> - <div class="prediction-table"> - {#each predictions as prediction, i} - <PredictedSpaceWeatherThing {prediction}/> - {/each} - </div> - {:else} - <div class="no-data"> - <i class="fas fa-7x fa-exclamation-triangle"></i> - <p>No prediction data</p> - </div> - {/if} +<div class="prediction-table"> + {#each predictions as prediction, i} + <PredictionItem {prediction}/> + {/each} </div> diff --git a/src/routes/index.svelte b/src/routes/index.svelte index 7efda23..64bcce9 100644 --- a/src/routes/index.svelte +++ b/src/routes/index.svelte @@ -1,6 +1,6 @@ <script lang="ts"> import WeatherCurrent from '../components/WeatherCurrent.svelte'; - import PredictedSpaceWeather from '../components/PredictedSpaceWeather.svelte'; + import ForecastDrawer from '../components/Forecast/ForecastDrawer.svelte'; //import { theme, fetchingData, fetchDataError, weatherData } from "../stores.ts"; //weatherData.subscribe(console.log); @@ -27,5 +27,5 @@ <div class="homescreen"> <WeatherCurrent/> - <PredictedSpaceWeather /> + <ForecastDrawer/> </div> diff --git a/src/stores.ts b/src/stores.ts index 05da19b..2e91c25 100644 --- a/src/stores.ts +++ b/src/stores.ts @@ -134,7 +134,8 @@ async function getSpaceWeather() { }, "usnoaa_data_raw": { "solar_wind_mag_field": false, - "noaa_planetary_k_index_forecast": false + "noaa_planetary_k_index_forecast": false, + "geospace_pred_est_kp_1_hour": false } }; @@ -144,8 +145,11 @@ async function getSpaceWeather() { ret.now.bz = ret.usnoaa_data_raw.solar_wind_mag_field["Bz"]; ret.now.bt = ret.usnoaa_data_raw.solar_wind_mag_field["Bt"]; + res = await fetch("https://services.swpc.noaa.gov/json/geospace/geospace_pred_est_kp_1_hour.json"); + ret.usnoaa_data_raw.geospace_pred_est_kp_1_hour = (await res.json()).map(x => ({...x, "model_prediction_time": new Date(x.model_prediction_time)})); + res = await fetch("https://services.swpc.noaa.gov/products/noaa-planetary-k-index-forecast.json") - ret.usnoaa_data_raw.noaa_planetary_k_index_forecast = await res.json() + ret.usnoaa_data_raw.noaa_planetary_k_index_forecast = await res.json(); ret.usnoaa_data_raw.noaa_planetary_k_index_forecast.shift(); let cDate = new Date(); |