Live site: WeatherWidget
Weather Widget is a simple single-page web-app that provides daily and hourly weather information based on location.
npm install
npm run start
- Google Maps Geocode API is used to get the latitude and longitude of the address the user inputs.
- Dark Sky API is used to retrieve the weather information from the latitude and longitude obtained by the Google Maps Geocode API.
- Chart.js is used to render the interactive/responsive bar chart.
Upon the user's submission of the address, getLatLong()
is called to find the latitude/longitude and call getWeather()
to find the weather information from the latitude/longitude.
getLatLong(e){
e.preventDefault();
fetch(`https://maps.googleapis.com/maps/api/geocode/json?address=${this.state.location}&key=${process.env.REACT_APP_GOOGLE_API_KEY}`)
.then(response => {
return response.json();
})
.then(data => {
const lat = data.results[0].geometry.location.lat;
const lng = data.results[0].geometry.location.lng;
this.setState({
lat,
lng,
weatherLocation: data.results[0].formatted_address
}, this.getWeather)
})
}
getWeather(){
fetch(`https://cors-anywhere.herokuapp.com/https://api.darksky.net/forecast/${process.env.REACT_APP_WEATHER_API_KEY}/${this.state.lat},${this.state.lng}`)
.then(response => response.json())
.then(data => {
this.setState({ weather: data })
})
}
To allow users to filter through the data sent from the Dark Sky API, dataIdx
is used in the main Weather Component. When user presses the right arrow, it increments the dataIdx and when user presses the left arrow, it decrements the dataIdx.
decrementIdx() {
let { dataIdx } = this.state;
dataIdx -= 6;
if (dataIdx <= 0) dataIdx = 0;
this.setState({ dataIdx });
}
incrementIdx() {
let { dataIdx } = this.state;
const maxIdx = this.state.weather[this.state.frame].data.length - 1;
dataIdx += 6;
if (dataIdx >= maxIdx) dataIdx = dataIdx -= 6;
this.setState({ dataIdx });
}
Later, the dataIdx
is used to slice the array data when creating data table (createTable()
), getting chart lables (createLabels()
), and getting chart data (createData()
)
//Creates a table based on the frame and dataIdx
const createTable = () => {
const dataIdx = props.weatherInfo.dataIdx;
//diaplayData is used to selected the weather data that will be represented on the table. Upto 6 data sets.
const displayData = props.weatherInfo.weather[props.weatherInfo.frame].data.slice(dataIdx, dataIdx + 6);
if (props.weatherInfo.frame === "hourly") {
return displayData.map(weatherData => (
<div
key={weatherData.time}
className="Weather-Table-individual-data"
>
{/* Gets each hour's temperature*/}
<p>{new Date(weatherData.time * 1000).toGMTString().slice(5, 22)}</p>
<p>{Math.round(Number(weatherData.apparentTemperature))}°F</p>
</div>
))
}
With Chart.js, with every render, the old chart is destroyed and a new chart is created.
if (window.myBarChart && window.myBarChart !== null) {
window.myBarChart.destroy();
}
Labels and the dataset matching the labels are created using createLabels()
and createData()
methods which use dataIdx to slice the fetched weather data.
const labels = createLabels();
const data = createData();
Styling properties are used to style the chart and make it responsive. Chart.js documentation can be found here: https://www.chartjs.org/docs/latest/
window.myBarChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: `${props.weatherInfo.frame[0].toLocaleUpperCase()}${props.weatherInfo.frame.slice(1)} Weather`,
backgroundColor: 'white',
fontColor: 'white',
data: data
}]
},
options: {
scales: {
yAxes: [{
display: true,
ticks: {
min: 1
},
gridLines: {
color: '#ffffff66'
}
}]
},
xAxes: [{
gridLines: {
color: '#ffffff66'
}
}]
},
responsive: true
});
Chart.defaults.global.defaultFontColor = 'white';
Chart.defaults.global.defaultColor = 'white';
Josh Choi