Deliverables - Class Assignments

HTML5 Weather App

Due Date

Due before 6:00 pm on Friday October 1, 2021.

Using two third-party API services (OpenWeather (opens new window) and LocationIQ (opens new window)) create a simple HTML5 app to allow the user to look up weather forecasts for various locations.

Some starter code for accessing the two API services is provided.

index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Weather | C1</title>
  </head>
  <body>
    <div id="root"></div>

    <script src="index.js" type="module"></script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
index.js
import { getForecast, createWeatherIcon } from './weather.service.js';
import { getGeolocation } from './map.service.js';

main();

// This is a demo of how to use the two API services.
// You should replace this with your own application logic.
async function main() {
  const location = 'Algonquin College, Nepean, ON, CA';
  try {
    const coord = await getGeolocation(location);
    const forecast = await getForecast({ coord });
    console.log(forecast);
  } catch (error) {
    console.log(error.message);
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
map.service.js
const API_TOKEN = 'THIS_NEEDS_TO_BE_YOUR_API_KEY';
const BASE_URL = 'https://us1.locationiq.com/v1';

export async function getGeolocation(location) {
  const url = `${BASE_URL}/search.php?key=${API_TOKEN}&q=${location}&format=json`;

  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(response.statusText);
  }
  const data = await response.json();
  return { lat: data[0].lat, lon: data[0].lon };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
weather.service.js
'use strict';
const BASE_URL = 'https://api.openweathermap.org/data/2.5/onecall';
const API_KEY = 'THIS_NEEDS_TO_BE_YOUR_API_KEY';
const DEFAULT_OPTIONS = {
  coord: { lon: -75.76, lat: 45.35 }, // Algonquin College
  units: 'metric',
};
const cache = new Map();

/**
 * @typedef {Object} APIOptions
 * @property {string} units [metric, imperial, standard]
 * @property {Object} coord Location coordinates
 * @property {number} coord.lon Longitude
 * @property {number} coord.lat Latitude
 */

/**
 * Get the latest weather forecast for the given location.
 * Results are cached for 10 minutes.
 * @param {APIOptions} options
 * @returns {Object} Forecast results
 * @see https://openweathermap.org/api/one-call-api#data
 */
export async function getForecast(options) {
  const { coord, units } = Object.assign({}, DEFAULT_OPTIONS, options);
  const cacheItem = cache.get(coord);
  if (cacheItem && !isExpired(cacheItem.current.dt)) {
    return cacheItem;
  }
  const forecast = await fetchForecast({ units, coord });
  cache.set(coord, forecast);
  return forecast;

  /**
   * Helper function to check cache expiry
   * @param {number} cacheTime UNIX timestamp in seconds
   */
  function isExpired(cacheTime) {
    const TEN_MINUTES = 600; // seconds
    const currentTime = Math.floor(Date.now() / 1000); // convert from ms to s
    const elapsedTime = currentTime - cacheTime;
    return elapsedTime > TEN_MINUTES;
  }
}

/**
 * Private function to make the actual `fetch()` call to the API
 * @param {APIOptions} options
 */
async function fetchForecast({ coord: { lat, lon }, units }) {
  const url = `${BASE_URL}?lat=${lat}&lon=${lon}&units=${units}&appid=${API_KEY}`;
  const response = await fetch(url);
  if (!response.ok) throw new Error(response.statusText);
  return response.json();
}

/**
 * Returns an <img> HTMLElement with the correct URL to display
 * the OpenWeather image corresponding to the given `iconCode`.
 * @param {string} iconCode
 */
export function createWeatherIcon(iconCode) {
  let img = document.createElement('img');
  img.setAttribute(
    'src',
    'https://openweathermap.org/img/w/' + iconCode + '.png'
  );
  img.setAttribute('alt', '');
  return img;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

# Requirements

# Open Weather Map

# LocationIQ

  • You will need to register for your own API Key (opens new window) — there is a free usage tier.

  • The user should be prompted for their target location.
    They should be able to type in a place name e.g. 'Kanata, ON, CA'.

  • The user should also have the option to allow the browser to access the Geolocation API (opens new window) and calculate the current longitude and latitude position. Note that in Chrome, this requires the page be running over https. If you are testing your page through GitHub Pages then you will have https.

  • If entering the location by name, you will need to call the LocationIQ API to get the longitude and latitude coordinates for the given location.

# User Interface

The user interface should be mobile first, responsive and accessible.

In addition to the user input elements ...

  • The forecast data should display the current stats most prominently and have the two future forecast views below.

  • Allow the user to switch between an hourly forecast for the next 6 hours or a daily forecast for the next 6 days.

  • The forecast display should incorporate the iconography from OpenWeather service. Here is the Icon Reference page (opens new window)

  • The exact layout and stats to include or exclude in the display is up to you. Make it useful and make it look professional.

  • You may choose to use a CSS library like Bootstrap, Materialize, Foundation, or Bulma, or you may choose to create all of the CSS by hand.

  • The display should be dynamically refreshed when the forecast is updated, or the location is changed. setInterval() can be used to look at the data for the next hour or day or to make a fresh geolocation call to check the position.

# localStorage

  • Store the most recent location and forecast data in localStorage. Display this data by default when the user first opens (or refreshes) the page.
  • LocalStorage can also be used for things like saving a timestamp for the last time data was retrieved. Events like a user click or page load can be used for as trigger to check the timestamp.
  • There are also Storage events that you can write listeners for. If the data in LocalStorage was updated on a different tab then you can know that you need to update the current tab.

# Submission

  • Create a private repo on GitHub with the name mad9135-c1-html5-weather.
  • Be sure to enable GitHub Pages on the repo.
  • Invite GitHub user prof3ssorSt3v3 as a collaborator on your private repo.
  • Submit the URLs for both the code repo and GitHub Pages to BS LMS.

Remember

Make commits as you complete each requirement. They should be atomic and have a meaningfully descriptive message.

You want to be seen as a professional developer?

via GIPHY

This is how you get seen as a professional developer. Employers like to look through your repos.

# References

Open Weather App API

Location IQ API

LocalStorage

Last Updated: : 9/17/2021, 10:30:36 AM