UNPKG

tils-first-weather-widget

Version:

An example development EXB widget (Grant Caroll, spatial-innovation.co.nz)

545 lines (516 loc) 15.2 kB
import Accessor from "@arcgis/core/core/Accessor.js"; import { property } from "@arcgis/core/core/accessorSupport/decorators.js"; import WeatherResponse from "../model/weather-response"; import esriRequest from "@arcgis/core/request.js"; //Interface for the parameters export interface IWeatherWidgetParameters { weatherAPI: string | undefined; weatherURL: string | undefined; view: __esri.MapView | __esri.SceneView | undefined; } //constant for weather types in Esri JSAPI export const weatherType = { SUNNY: 'sunny', FOGGY: 'foggy', CLOUDY: 'cloudy', RAINY: 'rainy', SNOWY: 'snowy' } //interface for conditions returned from weatherAPI.com interface IWeatherCondition { code: number, day: string, night: string, icon: number, esriCode: string } //Constant that matches result codes from weatherAPI.com to esri weather type //rainy,snowy,foggy,sunny,cloudy export const weatherMatch: Array<IWeatherCondition> = [ { "code": 1000, "day": "Sunny", "night": "Clear", "icon": 113, "esriCode": weatherType.SUNNY }, { "code": 1003, "day": "Partly cloudy", "night": "Partly cloudy", "icon": 116, "esriCode": weatherType.SUNNY }, { "code": 1006, "day": "Cloudy", "night": "Cloudy", "icon": 119, "esriCode": weatherType.CLOUDY }, { "code": 1009, "day": "Overcast", "night": "Overcast", "icon": 122, "esriCode": weatherType.CLOUDY }, { "code": 1030, "day": "Mist", "night": "Mist", "icon": 143, "esriCode": weatherType.FOGGY }, { "code": 1063, "day": "Patchy rain possible", "night": "Patchy rain possible", "icon": 176, "esriCode": weatherType.RAINY }, { "code": 1066, "day": "Patchy snow possible", "night": "Patchy snow possible", "icon": 179, "esriCode": weatherType.SNOWY }, { "code": 1069, "day": "Patchy sleet possible", "night": "Patchy sleet possible", "icon": 182, "esriCode": weatherType.SNOWY }, { "code": 1072, "day": "Patchy freezing drizzle possible", "night": "Patchy freezing drizzle possible", "icon": 185, "esriCode": weatherType.SNOWY }, { "code": 1087, "day": "Thundery outbreaks possible", "night": "Thundery outbreaks possible", "icon": 200, "esriCode": weatherType.RAINY }, { "code": 1114, "day": "Blowing snow", "night": "Blowing snow", "icon": 227, "esriCode": weatherType.SNOWY }, { "code": 1117, "day": "Blizzard", "night": "Blizzard", "icon": 230, "esriCode": weatherType.SNOWY }, { "code": 1135, "day": "Fog", "night": "Fog", "icon": 248, "esriCode": weatherType.FOGGY }, { "code": 1147, "day": "Freezing fog", "night": "Freezing fog", "icon": 260, "esriCode": weatherType.FOGGY }, { "code": 1150, "day": "Patchy light drizzle", "night": "Patchy light drizzle", "icon": 263, "esriCode": weatherType.RAINY }, { "code": 1153, "day": "Light drizzle", "night": "Light drizzle", "icon": 266, "esriCode": weatherType.RAINY }, { "code": 1168, "day": "Freezing drizzle", "night": "Freezing drizzle", "icon": 281, "esriCode": weatherType.SNOWY }, { "code": 1171, "day": "Heavy freezing drizzle", "night": "Heavy freezing drizzle", "icon": 284, "esriCode": weatherType.SNOWY }, { "code": 1180, "day": "Patchy light rain", "night": "Patchy light rain", "icon": 293, "esriCode": weatherType.RAINY }, { "code": 1183, "day": "Light rain", "night": "Light rain", "icon": 296, "esriCode": weatherType.RAINY }, { "code": 1186, "day": "Moderate rain at times", "night": "Moderate rain at times", "icon": 299, "esriCode": weatherType.RAINY }, { "code": 1189, "day": "Moderate rain", "night": "Moderate rain", "icon": 302, "esriCode": weatherType.RAINY }, { "code": 1192, "day": "Heavy rain at times", "night": "Heavy rain at times", "icon": 305, "esriCode": weatherType.RAINY }, { "code": 1195, "day": "Heavy rain", "night": "Heavy rain", "icon": 308, "esriCode": weatherType.RAINY }, { "code": 1198, "day": "Light freezing rain", "night": "Light freezing rain", "icon": 311, "esriCode": weatherType.RAINY }, { "code": 1201, "day": "Moderate or heavy freezing rain", "night": "Moderate or heavy freezing rain", "icon": 314, "esriCode": weatherType.RAINY }, { "code": 1204, "day": "Light sleet", "night": "Light sleet", "icon": 317, "esriCode": weatherType.SNOWY }, { "code": 1207, "day": "Moderate or heavy sleet", "night": "Moderate or heavy sleet", "icon": 320, "esriCode": weatherType.SNOWY }, { "code": 1210, "day": "Patchy light snow", "night": "Patchy light snow", "icon": 323, "esriCode": weatherType.SNOWY }, { "code": 1213, "day": "Light snow", "night": "Light snow", "icon": 326, "esriCode": weatherType.SNOWY }, { "code": 1216, "day": "Patchy moderate snow", "night": "Patchy moderate snow", "icon": 329, "esriCode": weatherType.SNOWY }, { "code": 1219, "day": "Moderate snow", "night": "Moderate snow", "icon": 332, "esriCode": weatherType.SNOWY }, { "code": 1222, "day": "Patchy heavy snow", "night": "Patchy heavy snow", "icon": 335, "esriCode": weatherType.SNOWY }, { "code": 1225, "day": "Heavy snow", "night": "Heavy snow", "icon": 338, "esriCode": weatherType.SNOWY }, { "code": 1237, "day": "Ice pellets", "night": "Ice pellets", "icon": 350, "esriCode": weatherType.SNOWY }, { "code": 1240, "day": "Light rain shower", "night": "Light rain shower", "icon": 353, "esriCode": weatherType.RAINY }, { "code": 1243, "day": "Moderate or heavy rain shower", "night": "Moderate or heavy rain shower", "icon": 356, "esriCode": weatherType.RAINY }, { "code": 1246, "day": "Torrential rain shower", "night": "Torrential rain shower", "icon": 359, "esriCode": weatherType.RAINY }, { "code": 1249, "day": "Light sleet showers", "night": "Light sleet showers", "icon": 362, "esriCode": weatherType.RAINY }, { "code": 1252, "day": "Moderate or heavy sleet showers", "night": "Moderate or heavy sleet showers", "icon": 365, "esriCode": weatherType.RAINY }, { "code": 1255, "day": "Light snow showers", "night": "Light snow showers", "icon": 368, "esriCode": weatherType.RAINY }, { "code": 1258, "day": "Moderate or heavy snow showers", "night": "Moderate or heavy snow showers", "icon": 371, "esriCode": weatherType.RAINY }, { "code": 1261, "day": "Light showers of ice pellets", "night": "Light showers of ice pellets", "icon": 374, "esriCode": weatherType.RAINY }, { "code": 1264, "day": "Moderate or heavy showers of ice pellets", "night": "Moderate or heavy showers of ice pellets", "icon": 377, "esriCode": weatherType.RAINY }, { "code": 1273, "day": "Patchy light rain with thunder", "night": "Patchy light rain with thunder", "icon": 386, "esriCode": weatherType.RAINY }, { "code": 1276, "day": "Moderate or heavy rain with thunder", "night": "Moderate or heavy rain with thunder", "icon": 389, "esriCode": weatherType.SNOWY }, { "code": 1279, "day": "Patchy light snow with thunder", "night": "Patchy light snow with thunder", "icon": 392, "esriCode": weatherType.SNOWY }, { "code": 1282, "day": "Moderate or heavy snow with thunder", "night": "Moderate or heavy snow with thunder", "icon": 395, "esriCode": weatherType.SNOWY } ] //The viewmodel, extends from Accessor export default class WeatherWidgetViewModel extends Accessor { @property() currentWeather: WeatherResponse | undefined; @property() weatherAPI: string | undefined; @property() weatherURL: string | undefined; @property() environment: {} | undefined; @property() view: __esri.MapView | __esri.SceneView | undefined; @property() time: string; constructor(params?: IWeatherWidgetParameters) { super(); this.currentWeather = undefined; this.weatherAPI = params?.weatherAPI; this.weatherURL = params?.weatherURL; this.view = params?.view; this.time = ""; } //Set the environment, only available on a web scene setEnvironment = () => { //Use the current time to set the lighting condtions let lighting = { type: "sun", date: this.currentWeather ? new Date(this.currentWeather.location.localtime_epoch * 1000) : new Date(), directShadowsEnabled: true }; //set the environment based on the weather. this.environment = { lighting: lighting, weather: this.getWeather() } //we can only set the environment on a scene. if (this.view?.type === "3d") { let sceneView = this.view as __esri.SceneView; sceneView.environment = this.environment; } } //Get the percentage of cloud cover getCloud = () => { if (this.currentWeather?.current.cloud) { return this.currentWeather?.current.cloud / 100 } return 0; } getFogCover = () => { //TODO translate visibility in to a percentage... return 0.50 } //get the level of rainfall based on the result from the weatherAPI call. getPrecipitation = (weatherCondition: IWeatherCondition) => { if (weatherCondition.day.toLowerCase().indexOf('torrential') > -1 || weatherCondition.night.toLowerCase().indexOf('torrential') > -1) { return 100; } if (weatherCondition.day.toLowerCase().indexOf('heavy') > -1 || weatherCondition.night.toLowerCase().indexOf('heavy') > -1) { return 90; } if (weatherCondition.day.toLowerCase().indexOf('moderate') > -1 || weatherCondition.night.toLowerCase().indexOf('moderate') > -1) { return 60; } if (weatherCondition.day.toLowerCase().indexOf('light') > -1 || weatherCondition.night.toLowerCase().indexOf('light') > -1) { return 30; } if (weatherCondition.day.toLowerCase().indexOf('patchy') > -1 || weatherCondition.night.toLowerCase().indexOf('patchy') > -1) { return 30; } if (weatherCondition.day.toLowerCase().indexOf('drizzle') > -1 || weatherCondition.night.toLowerCase().indexOf('drizzle') > -1) { return 30; } if (weatherCondition.day.toLowerCase().indexOf('thundery') > -1 || weatherCondition.night.toLowerCase().indexOf('thundery') > -1) { return 30; } if (weatherCondition.day.toLowerCase().indexOf('blizzard') > -1 || weatherCondition.night.toLowerCase().indexOf('blizzard') > -1) { return 100; } if (weatherCondition.day.toLowerCase().indexOf('blowing') > -1 || weatherCondition.night.toLowerCase().indexOf('blowing') > -1) { return 30; } if (weatherCondition.day.toLowerCase().indexOf('pellets') > -1 || weatherCondition.night.toLowerCase().indexOf('pellets') > -1) { return 30; } return 0; } //get the weather conditons based on the current weather getWeather = () => { let weatherCondition = weatherMatch.find(f => { if (this.currentWeather?.current.condition.code === f.code) { return f; } return undefined; }); if (!weatherCondition) { return { type: weatherType.SUNNY, cloudCover: this.getCloud() } } switch (weatherCondition.esriCode) { case weatherType.CLOUDY: return { type: weatherType.CLOUDY, cloudCover: this.getCloud() } case weatherType.FOGGY: return { type: weatherType.FOGGY, fogStrength: this.getFogCover() } case weatherType.RAINY: return { type: weatherType.RAINY, cloudCover: this.getCloud(), precipitation: this.getPrecipitation(weatherCondition) } case weatherType.SNOWY: return { type: weatherType.SNOWY, snowCover: "enabled", cloudCover: this.getCloud(), precipitation: this.getPrecipitation(weatherCondition) } case weatherType.SUNNY: return { type: weatherType.SUNNY, cloudCover: this.getCloud() } default: return { type: weatherType.SUNNY, cloudCover: this.getCloud() } } } //call the weather api to get the latest weather getLatestWeather = (lat: number, long: number): Promise<boolean> => { let request = `${this.weatherURL}/forecast.json?key=${this.weatherAPI}&q=${lat},${long}&aqi=yes`; return esriRequest(request, { responseType: "json" }).then(response => { this.currentWeather = new WeatherResponse(response.data); this.time = this.currentWeather.location.localtime.split(' ')[1]; this.setEnvironment(); return true; }).catch(error => { console.error(error) return false; }) } }