From b23739edf10b2c29cbbd0e714841ee666bd42181 Mon Sep 17 00:00:00 2001 From: Zak Timson Date: Fri, 7 Dec 2018 17:55:54 -0500 Subject: [PATCH] New weather layout --- src/app/app.component.html | 2 +- src/app/app.module.ts | 4 +- src/app/battery/battery.component.html | 64 ++--- src/app/round.pipe.ts | 11 + src/app/weather/weather.component.html | 127 +++++++-- src/app/weather/weather.component.ts | 86 +++++- src/app/weather/weather.service.ts | 74 ++--- src/app/weather/weatherCodes.json | 367 ------------------------- src/app/weather/weatherIcons.ts | 16 ++ src/index.html | 4 +- src/styles.scss | 1 + 11 files changed, 267 insertions(+), 489 deletions(-) create mode 100644 src/app/round.pipe.ts delete mode 100644 src/app/weather/weatherCodes.json create mode 100644 src/app/weather/weatherIcons.ts diff --git a/src/app/app.component.html b/src/app/app.component.html index b908d4f..a89ea4d 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -24,7 +24,7 @@ - +
diff --git a/src/app/app.module.ts b/src/app/app.module.ts index ca59a13..c99b399 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -25,6 +25,7 @@ import {environment} from '../environments/environment'; import * as firebase from 'firebase/app'; import { ServiceWorkerModule } from '@angular/service-worker'; import {LineChartModule, NgxChartsModule} from '@swimlane/ngx-charts'; +import { RoundPipe } from './round.pipe'; export const firebaseApp = firebase.initializeApp(environment.firebase); @@ -36,7 +37,8 @@ export const firebaseApp = firebase.initializeApp(environment.firebase); WeatherComponent, SecurityComponent, SettingsComponent, - LoginComponent + LoginComponent, + RoundPipe ], imports: [ AppRoutingModule, diff --git a/src/app/battery/battery.component.html b/src/app/battery/battery.component.html index 204e877..b58185d 100644 --- a/src/app/battery/battery.component.html +++ b/src/app/battery/battery.component.html @@ -1,32 +1,34 @@ -

- {{batteryService.icon}} - Powerwall: - {{batteryService.average * 100}}% - UNKNOWN -

-
- -
-
- +
+

+ {{batteryService.icon}} + Powerwall: + {{batteryService.average * 100}}% + UNKNOWN +

+
+ +
+
+ +
diff --git a/src/app/round.pipe.ts b/src/app/round.pipe.ts new file mode 100644 index 0000000..aa47f33 --- /dev/null +++ b/src/app/round.pipe.ts @@ -0,0 +1,11 @@ +import {Pipe, PipeTransform} from '@angular/core'; + +@Pipe({ + name: 'round' +}) +export class RoundPipe implements PipeTransform { + transform(value: number, decimalPlaces: number = 0): any { + const shift = Math.pow(10, decimalPlaces); + return Math.round(value * shift) / shift; + } +} diff --git a/src/app/weather/weather.component.html b/src/app/weather/weather.component.html index 3484357..6ad4551 100644 --- a/src/app/weather/weather.component.html +++ b/src/app/weather/weather.component.html @@ -1,30 +1,111 @@ -
-
- -
-

{{weatherService.temp}} °C

-

{{weatherService.weather}}

+
+ +
+
+

{{weatherService.weather?.currently.summary}}

+
+
+
+ +
+
+
+
+

{{weatherService.weather?.currently.temperature | round: 1}} °C

+
+
+ Feels Like: {{weatherService.weather?.currently.apparentTemperature | round}} °C +
+
+
+
+ arrow_upward + {{weatherService.weather?.daily.data[0].temperatureHigh | round}} °C +
+
+ arrow_downward + {{weatherService.weather?.daily.data[0].temperatureLow | round}} °C +
+
+ {{weatherService.weather?.daily.data[0].precipProbability * 100 | round}}% +
+
+
-
-
- {{weatherService.pop}} mm + + +
+
+ {{day.time.toString().slice(0, 4).toUpperCase()}} + +
{{day.temperatureHigh | round}} °C
+
{{day.temperatureLow | round}} °C
+
-
- {{weatherService.cloudCover}} % + + + +
Sunlight
+
+
+ {{weatherService.weather?.daily.data[0].sunriseTime | date: 'shortTime'}} +
+
+ {{weatherService.weather?.currently.cloudCover * 100 | round}}% +
+
+ {{weatherService.weather?.daily.data[0].sunsetTime | date: 'shortTime'}} +
-
- {{weatherService.wind[1]}} KM/H + + + + +
Wind
+
+
+ {{weatherService.weather?.currently.windSpeed | round}} km/h +
+
+ {{weatherService.weather?.currently.windBearing}}° +
+
+ {{weatherService.weather?.currently.windGust | round}} km/h +
-
- -
-
- {{w.day}} - -
{{w.max}} °C
-
{{w.min}} °C
+
+ +
-
- + + + +
Atmospheric
+
+
+
+ {{weatherService.weather?.currently.pressure / 10 | round: 1}} kPa +
+
+ UV Index: {{weatherService.weather?.currently.uvIndex}} +
+
+ remove_red_eye {{weatherService.weather?.currently.visibility | round}} km +
+
+
+
+ {{weatherService.weather?.currently.humidity * 100 | round}}% Humidity +
+
+ {{weatherService.weather?.daily.data[0].precipProbability * 100 | round}}% +
+
+ {{weatherService.weather?.daily.data[0].precipAccumulation | round: 1}} cm {{weatherService.weather?.daily.data[0].precipType}} +
+
+
+ +
diff --git a/src/app/weather/weather.component.ts b/src/app/weather/weather.component.ts index db4ce4c..ea72d4b 100644 --- a/src/app/weather/weather.component.ts +++ b/src/app/weather/weather.component.ts @@ -1,15 +1,89 @@ -import { Component, OnInit } from '@angular/core'; +import {Component, OnInit} from '@angular/core'; import {WeatherService} from './weather.service'; +import {timer} from 'rxjs'; +import {filter} from 'rxjs/operators'; @Component({ - selector: 'app-weather', - templateUrl: './weather.component.html' + selector: 'app-weather', + templateUrl: './weather.component.html' }) export class WeatherComponent implements OnInit { + day = false; - constructor(public weatherService: WeatherService) { } + constructor(public weatherService: WeatherService) { } - ngOnInit() { - } + ngOnInit() { + timer(0, 1000).pipe(filter(() => this.weatherService.weather)).subscribe(() => { + const now = new Date().getTime(); + const sunrise = this.weatherService.weather.daily.data[0].sunriseTime.getTime(); + const sunset = this.weatherService.weather.daily.data[0].sunsetTime.getTime(); + this.day = now > sunrise && now < sunset; + let diff = sunset - sunrise; + let current = new Date().getTime() - sunrise; + this.drawSunChart(current / diff); + }); + } + + drawSunChart(progress: number) { + const c = document.getElementById('myCanvas'); + if (c) { + const ctx = c.getContext('2d'); + + // All the points in 2D space we care about + const width = c.width; + const height = c.height; + const centerX = width / 2; + const centerY = height - 20; + const radius = height * 0.8; + const pointX = centerX + radius * Math.cos(Math.PI * (1 + progress)); + const pointY = centerY + radius * Math.sin(Math.PI * (1 + progress)); + + // Reset + ctx.clearRect(0, 0, width, height); + + // Path background + ctx.fillStyle = '#aeaeae'; + ctx.beginPath(); + ctx.arc(centerX, centerY, radius, Math.PI, 0); + ctx.fill(); + ctx.stroke(); + + // Path + ctx.lineWidth = 5; + ctx.strokeStyle = '#585858'; + ctx.fillStyle = '#585858'; + ctx.beginPath(); + ctx.arc(centerX, centerY, radius, Math.PI, 0); + ctx.stroke(); + + // Show sun + if(this.day) { + // Stroke background + ctx.lineWidth = 2; + ctx.fillStyle = '#b3ad00'; + ctx.beginPath(); + ctx.arc(centerX, centerY, radius, Math.PI, Math.PI * (1 + progress)); + ctx.lineTo(pointX, centerY); + ctx.fill(); + ctx.stroke(); + + // Stroke + ctx.lineWidth = 6; + ctx.strokeStyle = '#e5df00'; + ctx.fillStyle = '#e5df00'; + ctx.beginPath(); + ctx.arc(centerX, centerY, radius, Math.PI, Math.PI * (1 + progress)); + ctx.stroke(); + + // Stroke end dot + ctx.lineWidth = 1; + ctx.fillStyle = '#e5df00'; + ctx.beginPath(); + ctx.arc(pointX, pointY, 6, 0, 2 * Math.PI); + ctx.fill(); + ctx.stroke(); + } + } + } } diff --git a/src/app/weather/weather.service.ts b/src/app/weather/weather.service.ts index a61e70c..5cb9046 100644 --- a/src/app/weather/weather.service.ts +++ b/src/app/weather/weather.service.ts @@ -1,73 +1,31 @@ import {Injectable} from '@angular/core'; import {HttpClient} from '@angular/common/http'; +import {WeatherIcons} from './weatherIcons'; import {timer} from 'rxjs'; -import {database} from 'firebase'; @Injectable({ providedIn: 'root' }) export class WeatherService { - readonly apiKey = 'e8391af54b6fc09dc82b019fc68b8409'; - readonly city = 'London'; - readonly countryCode = 'CA'; - readonly days = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT']; - readonly weatherCodes = require('./weatherCodes.json'); - - // Weather information - cloudCover = 0; - forecast = []; - humidity = 0; icon: string; - pop = 0; - pressure = 0; - sunrise: Date; - sunset: Date; - temp = 0; - tempMin = 0; - tempMax = 0; - weather: string = ''; - wind: [number, number] = [0, 0]; + lat = 42.9849; + lng = -81.2453; + units = 'ca'; + weather: any; - constructor(httpClient: HttpClient) { + constructor(http: HttpClient) { + // Get weather every 5 minutes timer(0, 5 * 60000).subscribe(async () => { - // Current weather information - httpClient.get(`https://api.openweathermap.org/data/2.5/weather?q=${this.city},${this.countryCode}&APPID=${this.apiKey}&units=metric`).toPromise().then((weather: any) => { - this.cloudCover = weather.clouds.all; - this.humidity = weather.main.humidity; - this.icon = `wi-${this.weatherCodes[weather.weather[0].id].icon}`; - this.pressure = weather.main.pressure; - this.sunrise = new Date(weather.sys.sunrise); - this.sunset = new Date(weather.sys.sunset); - this.temp = Math.round(weather.main.temp); - this.tempMin = Math.round(weather.main.temp_min); - this.tempMax = Math.round(weather.main.temp_max); - this.weather = weather.weather[0].description; - this.wind = [weather.wind.deg, Math.round(weather.wind.speed)]; - }); + this.weather = await http.get(`https://cors-anywhere.herokuapp.com/https://api.darksky.net/forecast/88373fac9e52db6ad33a296f3b30404d/${this.lat},${this.lng}?units=${this.units}`).toPromise(); - // 5 day forecast - httpClient.get(`https://api.openweathermap.org/data/2.5/forecast?q=${this.city},${this.countryCode}&APPID=${this.apiKey}&units=metric`).toPromise().then((weather: any) => { - this.pop = Math.round(weather.list.slice(0, 4).reduce((acc, weather) => { - if(weather['rain']) acc += weather['rain']['3h'] || 0; - if(weather['snow']) acc += weather['snow']['3h'] || 0; - return acc; - }, 0) * 10) / 10; - - let temp = {}; - weather.list.forEach(weather => { - let timestamp = new Date(weather.dt * 1000); - let day = timestamp.getDate(); - console.log(timestamp.getHours()); - if(!temp[day]) temp[day] = {}; - if(!temp[day].max || weather.main.temp_max > temp[day].max) temp[day].max = Math.round(weather.main.temp_max); - if(!temp[day].min || weather.main.temp_min < temp[day].min) temp[day].min = Math.round(weather.main.temp_min); - if(!temp[day].day || timestamp.getHours() == 13) { - temp[day].day = timestamp.toString().substring(0, 4); - temp[day].icon = `wi-${this.weatherCodes[weather.weather[0].id].icon}`; - } - }); - this.forecast = Object.values(temp); - }); + // Format data + this.weather.daily.data.map(day => Object.assign(day, { + icon: WeatherIcons[day.icon], + time: new Date(day.time * 1000), + sunsetTime: new Date(day.sunsetTime * 1000), + sunriseTime: new Date(day.sunriseTime * 1000), + })); + this.icon = WeatherIcons[this.weather.currently.icon]; }); } } diff --git a/src/app/weather/weatherCodes.json b/src/app/weather/weatherCodes.json deleted file mode 100644 index 3dac9f4..0000000 --- a/src/app/weather/weatherCodes.json +++ /dev/null @@ -1,367 +0,0 @@ -{ - "200": { - "label": "thunderstorm with light rain", - "icon": "storm-showers" - }, - - "201": { - "label": "thunderstorm with rain", - "icon": "storm-showers" - }, - - "202": { - "label": "thunderstorm with heavy rain", - "icon": "storm-showers" - }, - - "210": { - "label": "light thunderstorm", - "icon": "storm-showers" - }, - - "211": { - "label": "thunderstorm", - "icon": "thunderstorm" - }, - - "212": { - "label": "heavy thunderstorm", - "icon": "thunderstorm" - }, - - "221": { - "label": "ragged thunderstorm", - "icon": "thunderstorm" - }, - - "230": { - "label": "thunderstorm with light drizzle", - "icon": "storm-showers" - }, - - "231": { - "label": "thunderstorm with drizzle", - "icon": "storm-showers" - }, - - "232": { - "label": "thunderstorm with heavy drizzle", - "icon": "storm-showers" - }, - - "300": { - "label": "light intensity drizzle", - "icon": "sprinkle" - }, - - "301": { - "label": "drizzle", - "icon": "sprinkle" - }, - - "302": { - "label": "heavy intensity drizzle", - "icon": "sprinkle" - }, - - "310": { - "label": "light intensity drizzle rain", - "icon": "sprinkle" - }, - - "311": { - "label": "drizzle rain", - "icon": "sprinkle" - }, - - "312": { - "label": "heavy intensity drizzle rain", - "icon": "sprinkle" - }, - - "313": { - "label": "shower rain and drizzle", - "icon": "sprinkle" - }, - - "314": { - "label": "heavy shower rain and drizzle", - "icon": "sprinkle" - }, - - "321": { - "label": "shower drizzle", - "icon": "sprinkle" - }, - - "500": { - "label": "light rain", - "icon": "rain" - }, - - "501": { - "label": "moderate rain", - "icon": "rain" - }, - - "502": { - "label": "heavy intensity rain", - "icon": "rain" - }, - - "503": { - "label": "very heavy rain", - "icon": "rain" - }, - - "504": { - "label": "extreme rain", - "icon": "rain" - }, - - "511": { - "label": "freezing rain", - "icon": "rain-mix" - }, - - "520": { - "label": "light intensity shower rain", - "icon": "showers" - }, - - "521": { - "label": "shower rain", - "icon": "showers" - }, - - "522": { - "label": "heavy intensity shower rain", - "icon": "showers" - }, - - "531": { - "label": "ragged shower rain", - "icon": "showers" - }, - - "600": { - "label": "light snow", - "icon": "snow" - }, - - "601": { - "label": "snow", - "icon": "snow" - }, - - "602": { - "label": "heavy snow", - "icon": "snow" - }, - - "611": { - "label": "sleet", - "icon": "sleet" - }, - - "612": { - "label": "shower sleet", - "icon": "sleet" - }, - - "615": { - "label": "light rain and snow", - "icon": "rain-mix" - }, - - "616": { - "label": "rain and snow", - "icon": "rain-mix" - }, - - "620": { - "label": "light shower snow", - "icon": "rain-mix" - }, - - "621": { - "label": "shower snow", - "icon": "rain-mix" - }, - - "622": { - "label": "heavy shower snow", - "icon": "rain-mix" - }, - - "701": { - "label": "mist", - "icon": "sprinkle" - }, - - "711": { - "label": "smoke", - "icon": "smoke" - }, - - "721": { - "label": "haze", - "icon": "day-haze" - }, - - "731": { - "label": "sand, dust whirls", - "icon": "cloudy-gusts" - }, - - "741": { - "label": "fog", - "icon": "fog" - }, - - "751": { - "label": "sand", - "icon": "cloudy-gusts" - }, - - "761": { - "label": "dust", - "icon": "dust" - }, - - "762": { - "label": "volcanic ash", - "icon": "smog" - }, - - "771": { - "label": "squalls", - "icon": "day-windy" - }, - - "781": { - "label": "tornado", - "icon": "tornado" - }, - - "800": { - "label": "clear sky", - "icon": "day-sunny" - }, - - "801": { - "label": "few clouds", - "icon": "cloudy" - }, - - "802": { - "label": "scattered clouds", - "icon": "cloudy" - }, - - "803": { - "label": "broken clouds", - "icon": "cloudy" - }, - - "804": { - "label": "overcast clouds", - "icon": "cloudy" - }, - - - "900": { - "label": "tornado", - "icon": "tornado" - }, - - "901": { - "label": "tropical storm", - "icon": "hurricane" - }, - - "902": { - "label": "hurricane", - "icon": "hurricane" - }, - - "903": { - "label": "cold", - "icon": "snowflake-cold" - }, - - "904": { - "label": "hot", - "icon": "hot" - }, - - "905": { - "label": "windy", - "icon": "windy" - }, - - "906": { - "label": "hail", - "icon": "hail" - }, - - "951": { - "label": "calm", - "icon": "day-sunny" - }, - - "952": { - "label": "light breeze", - "icon": "cloudy-gusts" - }, - - "953": { - "label": "gentle breeze", - "icon": "cloudy-gusts" - }, - - "954": { - "label": "moderate breeze", - "icon": "cloudy-gusts" - }, - - "955": { - "label": "fresh breeze", - "icon": "cloudy-gusts" - }, - - "956": { - "label": "strong breeze", - "icon": "cloudy-gusts" - }, - - "957": { - "label": "high wind, near gale", - "icon": "cloudy-gusts" - }, - - "958": { - "label": "gale", - "icon": "cloudy-gusts" - }, - - "959": { - "label": "severe gale", - "icon": "cloudy-gusts" - }, - - "960": { - "label": "storm", - "icon": "thunderstorm" - }, - - "961": { - "label": "violent storm", - "icon": "thunderstorm" - }, - - "962": { - "label": "hurricane", - "icon": "cloudy-gusts" - } -} diff --git a/src/app/weather/weatherIcons.ts b/src/app/weather/weatherIcons.ts new file mode 100644 index 0000000..7b5e658 --- /dev/null +++ b/src/app/weather/weatherIcons.ts @@ -0,0 +1,16 @@ +export enum WeatherIcons { + 'clear-day' = 'wi-day-sunny', + 'clear-night' = 'wi-night-clear', + 'cloudy' = 'wi-cloudy', + 'default' = '', + 'fog' = 'wi-fog', + 'hail' = 'wi-hail', + 'partly-cloudy-day' = 'wi-day-cloudy', + 'partly-cloudy-night' = 'wi-night-alt-cloudy', + 'rain' = 'wi-rain', + 'sleet' = 'wi-sleet', + 'snow' = 'wi-snow', + 'thunderstorm' = 'wi-thunderstorm', + 'tornado' = 'wi-tornado', + 'wind' = 'wi-strong-wind', +} diff --git a/src/index.html b/src/index.html index 4f1fdec..ad7ecfe 100644 --- a/src/index.html +++ b/src/index.html @@ -12,9 +12,9 @@ - + -
+

Home Front

diff --git a/src/styles.scss b/src/styles.scss index 890406f..38acccc 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -2,6 +2,7 @@ @import url('https://fonts.googleapis.com/css?family=Archivo|Material+Icons'); @import "~@angular/material/prebuilt-themes/indigo-pink.css"; @import url('https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.9/css/weather-icons.min.css'); +@import url('https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.9/css/weather-icons-wind.min.css'); ::-webkit-scrollbar-track { border-radius: 10px;