Now I need to style it

This commit is contained in:
Lani Aung
2025-06-12 19:37:52 -07:00
parent 8b828f79fd
commit 30043f755a
3 changed files with 122 additions and 101 deletions
+11 -1
View File
@@ -8,14 +8,24 @@ body {
#weather-panel { #weather-panel {
border-radius: 50px; border-radius: 50px;
box-shadow: #999a 0 0 25px; box-shadow: #999a 0 0 25px;
color: #fff;
font-family: Verdana, sans-serif; font-family: Verdana, sans-serif;
font-weight: bold;
height: 500px; height: 500px;
left: calc(50% - 250px); left: calc(50% - 250px);
padding: 40px; padding: 40px;
position: absolute; position: absolute;
text-shadow: #fff 0 0 5px, #fff 0 0 5px, #fff 0 0 5px, #fff 0 0 5px; text-shadow: #000 1px 1px,
#000 -1px 1px,
#000 -1px -1px,
#000 1px -1px;
top: calc(50% - 250px); top: calc(50% - 250px);
width: 500px; width: 500px;
z-index: 10; z-index: 10;
@supports (-webkit-text-stroke: 1px #000) {
-webkit-text-stroke: 1px #000;
-webkit-text-fill-color: #fff;
}
} }
} }
+101 -99
View File
@@ -1,4 +1,5 @@
import { fetchWeatherApi } from 'openmeteo' import { fetchWeatherApi } from "openmeteo"
import { VariablesWithTime } from "@openmeteo/sdk/variables-with-time"
export default class Weather { export default class Weather {
private readonly apiUrl = "https://api.open-meteo.com/v1/forecast" private readonly apiUrl = "https://api.open-meteo.com/v1/forecast"
@@ -15,113 +16,124 @@ export default class Weather {
this.options = new WeatherOptions(latitude ?? 47.61002138071677, longitude ?? -122.17906310779568) this.options = new WeatherOptions(latitude ?? 47.61002138071677, longitude ?? -122.17906310779568)
const me = this const me = this
setInterval(() => me.fetchWeather().then(() => me.setDisplay()), 60 * 1000) setInterval(() => me.fetchWeather().then(() => me.setDisplay()), 60000)
me.fetchWeather().then(() => me.setDisplay()) me.fetchWeather().then(() => me.setDisplay())
} }
async fetchWeather(): Promise<void> { async fetchWeather(): Promise<void> {
const me = this const me = this
const parameters: any = { ...me.options } const parameters: any = { ...me.options }
let getData = false if (!me.doFetchData(parameters)) return
const responses = await fetchWeatherApi(me.apiUrl, parameters)
for (const response of responses) {
const current = response.current()
const hourly = response.hourly()
const daily = response.daily()
if (current != null) me.setCurrentData(current)
if (hourly != null) me.setHourlyData(hourly)
if (daily != null) me.setDailyData(daily)
}
}
private doFetchData(parameters: any): boolean {
const me = this
if (!me.lastFetched) { if (!me.lastFetched) {
parameters["daily"] = me.dailyVariables parameters["daily"] = me.dailyVariables
parameters["hourly"] = me.hourlyVariables parameters["hourly"] = me.hourlyVariables
parameters["current"] = me.currentVariables parameters["current"] = me.currentVariables
me.lastFetched = new LastFetched() me.lastFetched = new LastFetched()
getData = true return true
} else { } else {
// Reasonable-ish timers? // Weather data is updated :00, :15, :30, :45 so wait at least a minute
if (me.lastFetched.minutesSinceCurrent() > 15) { if (me.lastFetched.current.getMinutes() % 15 < 5) {
parameters["current"] = me.currentVariables const now = new Date()
me.lastFetched.current = new Date() // Make sure data is over 5 minutes old at least
getData = true if ((now.getTime() - me.lastFetched.current.getTime()) > 300000) {
parameters["current"] = me.currentVariables
me.lastFetched.current = new Date()
return true
}
} }
// Reasonable-ish timers?
if (me.lastFetched.hoursSinceHourly() > 3) { if (me.lastFetched.hoursSinceHourly() > 3) {
parameters["hourly"] = me.hourlyVariables parameters["hourly"] = me.hourlyVariables
me.lastFetched.hourly = new Date() me.lastFetched.hourly = new Date()
getData = true return true
} }
if (me.lastFetched.hoursSinceDaily() > 8) { if (me.lastFetched.hoursSinceDaily() > 8) {
parameters["daily"] = me.dailyVariables parameters["daily"] = me.dailyVariables
me.lastFetched.daily = new Date() me.lastFetched.daily = new Date()
getData = true return true
} }
} }
if (!getData) return return false
}
const responses = await fetchWeatherApi(me.apiUrl, parameters) private setCurrentData(current: VariablesWithTime) {
for (const response of responses) { this.current = {
const utcOffsetSeconds = response.utcOffsetSeconds() time: new Date(Number(current.time()) * 1000),
const current = response.current() temperature: current.variables(0)!.value(),
const hourly = response.hourly() humidity: current.variables(1)!.value(),
const daily = response.daily() feelsLike: current.variables(2)!.value(),
precipitation: current.variables(3)!.value(),
windSpeed: current.variables(4)!.value(),
windGusts: current.variables(5)!.value(),
windDirection: current.variables(6)!.value(),
cloudCoverage: current.variables(7)!.value()
}
}
if (current != null) { private setHourlyData(hourly: VariablesWithTime) {
me.current = { const length = Number(hourly.timeEnd() - hourly.time()) / hourly.interval()
time: new Date(Number(current.time()) * 1000), const temperatures = hourly.variables(0)!.valuesArray()
temperature: current.variables(0)!.value(), const precipitationTotals = hourly.variables(1)!.valuesArray()
humidity: current.variables(1)!.value(), const precipitationProbabilities = hourly.variables(2)!.valuesArray()
feelsLike: current.variables(2)!.value(), this.hourly.length = 0
precipitation: current.variables(3)!.value(),
windSpeed: current.variables(4)!.value(),
windGusts: current.variables(5)!.value(),
windDirection: current.variables(6)!.value(),
cloudCoverage: current.variables(7)!.value()
}
}
if (hourly != null) { for (let i = 0; i < length; i++) {
const length = Number(hourly.timeEnd() - hourly.time()) / hourly.interval() this.hourly.push({
const temperatures = hourly.variables(0)!.valuesArray() time: new Date((Number(hourly.time()) + i * hourly.interval()) * 1000),
const precipitationTotals = hourly.variables(1)!.valuesArray() temperature: temperatures[i],
const precipitationProbabilities = hourly.variables(2)!.valuesArray() precipitation: precipitationTotals[i],
me.hourly.length = 0 precipitationProbability: precipitationProbabilities[i]
})
}
}
for (let i = 0; i < length; i++) { private setDailyData(daily: VariablesWithTime) {
me.hourly.push({ const length = Number(daily.timeEnd() - daily.time()) / daily.interval()
time: new Date((Number(hourly.time()) + i * hourly.interval() + utcOffsetSeconds) * 1000), const maxTemperatures = daily.variables(0)!.valuesArray()
temperature: temperatures[i], const minTemperatures = daily.variables(1)!.valuesArray()
precipitation: precipitationTotals[i], const sunrise = daily.variables(2)
precipitationProbability: precipitationProbabilities[i] const sunset = daily.variables(3)
}) const maxUVs = daily.variables(4)!.valuesArray()
} const precipitationTotals = daily.variables(5)!.valuesArray()
} const precipitationHours = daily.variables(6)!.valuesArray()
const maxWindSpeeds = daily.variables(7)!.valuesArray()
const maxWindGusts = daily.variables(8)!.valuesArray()
const prominentWindDirections = daily.variables(9)!.valuesArray()
if (daily != null) { this.daily.length = 0
const length = Number(daily.timeEnd() - daily.time()) / daily.interval()
const maxTemperatures = daily.variables(0)!.valuesArray()
const minTemperatures = daily.variables(1)!.valuesArray()
const sunrise = daily.variables(2)
const sunset = daily.variables(3)
const maxUVs = daily.variables(4)!.valuesArray()
const precipitationTotals = daily.variables(5)!.valuesArray()
const precipitationHours = daily.variables(6)!.valuesArray()
const maxWindSpeeds = daily.variables(7)!.valuesArray()
const maxWindGusts = daily.variables(8)!.valuesArray()
const prominentWindDirections = daily.variables(9)!.valuesArray()
me.daily.length = 0 for (let i = 0; i < length; i++) {
this.daily.push({
for (let i = 0; i < length; i++) { time: new Date((Number(daily.time()) + i * daily.interval()) * 1000),
me.daily.push({ maxTemperature: maxTemperatures[i],
time: new Date((Number(daily.time()) + i * daily.interval()) * 1000), minTemperature: minTemperatures[i],
maxTemperature: maxTemperatures[i], sunrise: new Date((Number(sunrise.valuesInt64(i))) * 1000),
minTemperature: minTemperatures[i], sunset: new Date((Number(sunset.valuesInt64(i))) * 1000),
sunrise: new Date((Number(sunrise.valuesInt64(i))) * 1000), maxUV: maxUVs[i],
sunset: new Date((Number(sunset.valuesInt64(i))) * 1000), totalPrecipitation: precipitationTotals[i],
maxUV: maxUVs[i], hoursOfPrecipitation: precipitationHours[i],
totalPrecipitation: precipitationTotals[i], maxWindSpeed: maxWindSpeeds[i],
hoursOfPrecipitation: precipitationHours[i], maxWindGusts: maxWindGusts[i],
maxWindSpeed: maxWindSpeeds[i], prominentWindDirection: prominentWindDirections[i]
maxWindGusts: maxWindGusts[i], })
prominentWindDirection: prominentWindDirections[i]
})
}
}
} }
} }
@@ -134,31 +146,25 @@ export default class Weather {
} }
while (panel.firstChild) panel.removeChild(panel.firstChild) while (panel.firstChild) panel.removeChild(panel.firstChild)
this.setDisplayCurrent(panel)
}
private setDisplayCurrent(panel: HTMLElement) {
const currentSection = document.createElement("section") const currentSection = document.createElement("section")
currentSection.id = "current-section" currentSection.id = "current-section"
panel.appendChild(currentSection) panel.appendChild(currentSection)
this.setDisplayCurrent(currentSection)
} }
private setDisplayCurrent(section: HTMLElement) { private InCardinals(direction: number): string {
const header = document.createElement("header") if (direction > 337.5 || direction <= 22.5) return "N"
header.textContent = "Current" if (direction > 22.5 || direction <= 67.5) return "NE"
if (direction > 67.5 || direction <= 112.5) return "E"
section.appendChild(header) if (direction > 112.5 || direction <= 157.5) return "SE"
if (direction > 157.5 || direction <= 202.5) return "S"
const list = document.createElement("dl") if (direction > 202.5 || direction <= 249.5) return "SW"
for (let key of Object.keys(this.current)) { if (direction > 249.5 || direction <= 294.5) return "W"
const term = document.createElement("dt") if (direction > 294.5 || direction <= 337.5) return "NW"
term.textContent = key return null
const value = document.createElement("dd")
value.textContent = (this.current as any)[key]
list.append(term, value)
}
section.appendChild(list)
} }
} }
@@ -215,10 +221,6 @@ class LastFetched {
hourly: Date = new Date() hourly: Date = new Date()
daily: Date = new Date() daily: Date = new Date()
minutesSinceCurrent(): number {
return (new Date().getTime() - this.current.getTime()) / 60000
}
hoursSinceHourly(): number { hoursSinceHourly(): number {
return (new Date().getTime() - this.hourly.getTime()) / 3600000 return (new Date().getTime() - this.hourly.getTime()) / 3600000
} }
+10 -1
View File
@@ -9,13 +9,22 @@ html #weather-panel,
body #weather-panel { body #weather-panel {
border-radius: 50px; border-radius: 50px;
box-shadow: #999a 0 0 25px; box-shadow: #999a 0 0 25px;
color: #fff;
font-family: Verdana, sans-serif; font-family: Verdana, sans-serif;
font-weight: bold;
height: 500px; height: 500px;
left: calc(50% - 250px); left: calc(50% - 250px);
padding: 40px; padding: 40px;
position: absolute; position: absolute;
text-shadow: #fff 0 0 5px, #fff 0 0 5px, #fff 0 0 5px, #fff 0 0 5px; text-shadow: #000 1px 1px, #000 -1px 1px, #000 -1px -1px, #000 1px -1px;
top: calc(50% - 250px); top: calc(50% - 250px);
width: 500px; width: 500px;
z-index: 10; z-index: 10;
} }
@supports (-webkit-text-stroke: 1px #000) {
html #weather-panel,
body #weather-panel {
-webkit-text-stroke: 1px #000;
-webkit-text-fill-color: #fff;
}
}