vue-weather-widget
Version:
Weather forecast widget for Vuejs using DarkSky api
254 lines (225 loc) • 6.64 kB
JavaScript
import Utils from "./utils";
import Skycon from "vue-skycons";
export default {
name: "VueWeatherWidget",
components: {
Skycon,
},
props: {
// Pass true to use DarkSky API, otherwise it will use OpenWeatherMap API
useDarkSkyApi: {
type: Boolean,
default: false,
},
// Your Dark Sky / OpenWeatherMap secret key
apiKey: {
type: String,
required: true,
},
// // Address to lookup location.
// address: {
// type: String,
// },
// The latitude of a location (in decimal degrees).
// Positive is north, negative is south.
latitude: {
type: String | Number,
},
// The longitude of a location (in decimal degrees).
// Positive is east, negative is west.
longitude: {
type: String | Number,
},
// Return summary properties in the desired language.
// For list of supported languages, visit https://darksky.net/dev/docs/forecast
language: {
type: String,
default: "en",
},
// Return weather conditions in the requested units.
// For list of supported units, visit https://darksky.net/dev/docs/forecast
units: {
type: String,
default: "us",
},
// Controls whether to show or hide the title bar.
hideHeader: {
type: Boolean,
default: false,
},
// Auto update interval in milliseconds
updateInterval: {
type: Number,
},
// Use static skycons
disableAnimation: {
type: Boolean,
default: false,
},
// Color of the Temparature bar. Default: '#444'
barColor: {
type: String,
default: "#444",
},
// Color of the text. Default: '#333'
textColor: {
type: String,
default: "#333",
},
// // Your positionstack api key for geocoding
// positionstackApi: {
// type: String,
// default: "7f9c71310f410847fceb9537a83f3882",
// },
// Your ipregistry key to get location from ip address
ipregistryKey: {
type: String,
default: "f8n4kqe8pv4kii",
},
},
data() {
return {
loading: true,
weather: null,
error: null,
//location: {},
timeout: null,
};
},
watch: {
apiKey: "hydrate",
// address: "hydrate",
latitude: "hydrate",
longitude: "hydrate",
language: "hydrate",
units: "hydrate",
updateInterval: "hydrate",
},
mounted() {
this.hydrate();
},
destroyed() {
clearTimeout(this.timeout);
},
computed: {
currently() {
return this.weather.currently;
},
isDownward() {
const hourly = this.weather.hourly.data;
const time = new Date().getTime() / 1e3;
for (let i = 0; i < hourly.length; i++) {
if (hourly[i].time <= time) continue;
return hourly[i].temperature < this.currently.temperature;
}
},
windBearing() {
const t = Math.round(this.currently.windBearing / 45);
return ["N", "NE", "E", "SE", "S", "SW", "W", "NW", "N"][t];
},
daily() {
const forecasts = [];
let globalMaxTemp = -Infinity;
let globalMinTemp = Infinity;
const tomorrow = new Date(new Date().toDateString());
const today = tomorrow.getTime() / 1e3 + 24 * 3600 - 1;
const daily = this.weather.daily.data;
for (let i = 0; i < daily.length; i++) {
const day = daily[i];
if (day.temperatureMax > globalMaxTemp) {
globalMaxTemp = day.temperatureMax;
}
if (day.temperatureMin < globalMinTemp) {
globalMinTemp = day.temperatureMin;
}
forecasts.push(Object.assign({}, day));
}
const tempRange = globalMaxTemp - globalMinTemp;
for (let i = 0; i < forecasts.length; ++i) {
const day = forecasts[i];
if (day.time <= today) {
day.weekName = "Today";
} else {
day.weekName = new Date(day.time * 1000).toLocaleDateString(this.language, {
weekday: "short",
});
}
const max = day.temperatureMax;
const min = day.temperatureMin;
day.height = Math.round((100 * (max - min)) / tempRange);
day.top = Math.round((100 * (globalMaxTemp - max)) / tempRange);
day.bottom = 100 - (day.top + day.height);
}
return forecasts;
},
},
methods: {
async loadWeather() {
const fetchWeatherMethod = this.useDarkSkyApi ? Utils.fetchWeather : Utils.fetchOWMWeather;
const data = await fetchWeatherMethod({
apiKey: this.apiKey,
lat: this.latitude,
lng: this.longitude,
units: this.units,
language: this.language,
});
this.$set(this, "weather", data);
},
autoupdate() {
clearTimeout(this.timeout);
const time = Number(this.updateInterval);
if (!time || time < 10 || this.destroyed) {
return;
}
this.timeout = setTimeout(() => this.hydrate(false), time);
},
hydrate(setLoading = true) {
this.$set(this, "loading", setLoading);
return this.$nextTick()
.then(this.processLocation)
.then(this.loadWeather)
.then(() => {
this.$set(this, "error", null);
})
.catch((err) => {
this.$set(this, "error", "" + err);
})
.finally(() => {
this.$set(this, "loading", false);
this.autoupdate();
});
},
processLocation() {
if (!this.latitude || !this.longitude) {
throw new Error("VueWeatherWidget: Latitude or longitude is required");
// if (!this.address) {
// return Utils.fetchLocationByIP(this.ipregistryKey).then((data) => {
// this.$set(this, "location", {
// lat: data.latitude,
// lng: data.longitude,
// name: `${data.city}, ${data.country.name}`,
// });
// });
// } else {
// return Utils.geocode(this.positionstackApi, this.address).then((data) => {
// this.$set(this, "location", {
// lat: data.latitude,
// lng: data.longitude,
// name: `${data.region}, ${data.country}`,
// });
// });
// }
} else {
// return Utils.reverseGeocode(this.positionstackApi, this.latitude, this.longitude).then(
// (data) => {
// this.$set(this, "location", {
// lat: this.latitude,
// lng: this.longitude,
// name: `${data.region}, ${data.country}`,
// });
// }
// );
}
},
},
};