Create a COVID Map with Vue & Google Maps

Create a COVID Map with Vue & Google Maps

  • 1390

Create a COVID Map with Vue & Google Maps .So I’ve been using coronavirus-map for my daily update; but I’ve also been making my own Vue plugin for Google Maps and thought I’d test it out. It’s a great example for someone who is either learning Vue (intermediate) or wanting a starting point for their own (COVID) map.

So I’ve been using coronavirus-map for my daily update; but I’ve also been making my own Vue plugin for Google Maps and thought I’d test it out. It’s a great example for someone who is either learning Vue (intermediate) or wanting a starting point for their own (COVID) map.

This is the result: Repository (code) | Live Demo

Setup

Very basic setup using the Vue CLI and default preset (Babel and ESLint).

We’re just using the App.vue file with components so we don’t need the generated Views folder or the HelloWorld.vue component. We also don’t have assets so you can delete the Assets folder too.

x5-gmaps (Google Maps plugin for Vue)

  1. Install via npm install x5-gmaps
  2. To make it work in Edge and IE, add a vue.config.js file and include:
    module.exports = { transpileDependencies: ['x5-gmaps'] }
  3. Get a Google API Key
  4. Import and install the plugin in your main.js file :
import x5GMaps from 'x5-gmaps'
Vue.use(x5GMaps, { key: GOOGLE_KEY, libraries: ['visualization'] }

Event Bus

To pass data between components we will use an EventBus rather than Vuex (which you would use for any project larger than this). I’ve called it bus.js and all it contains is:

import Vue from 'vue'
export const EventBus = new Vue()

Components

We will only have one “view” (App.vue), but it will be made from two components: WorldMap.vue and MapOptions.vue.

HeatMap

To simplify things, we will separate out the map overlay from WorldMap.vue. This overlay is the heatmap component that ships with x5-gmaps, and we’ll call it HeatMap.vue.

We start with two Vue data properties: covidDataRaw (raw data we download) and type (what type of data we’re mapping).

data: () => ({
  covidDataRaw: [],
  type: 'active'
}),

When the component is created() we’ll get our COVID data using fetch() on Muhammad Mustadi’s covid-19-api. We’re also going to use the EventBus to listen and respond to “type” changes (coming from MapOptions.vue).

created() {
  // Get data
  fetch('https://covid19.mathdro.id/api/confirmed')
    .then(response => response.json())
    .then(data => (this.covidDataRaw = data))
    .catch(e => console.error(e))
  // Listen for type change
  EventBus.$on('changeType', type => (this.type = type))
}

*Note: In the repository code I have a backup data set that’s called if it can’t connect to the primary one, and resolves as an empty array if there’s a problem with that one too.

The COVID data set downloaded is almost perfect, but needs a little change before we can use it in the heatmap component; so we make a computed property items that returns a modified (and smaller) array.
We can also set heatmap color gradients depending on what type is selected.

computed: {
  items() {
    return this.covidDataRaw.map(e => ({
      lat: e.lat,
      lng: e.long,
      active: e.active,
      confirmed: e.confirmed,
      deaths: e.deaths,
      recovered: e.recovered
    }))
  },
  colors() {
    if (this.type === 'recovered') return ['white', 'blue']
    if (this.type === 'deaths') return ['red', 'black']
    return ['green', 'yellow', 'red']
  }
}

Finally, we can add all of this into the heatmap component with a few extra props to get it looking good:

<gmaps-heatmap :items="items"
               :weightProp="type"
               :dissipating="false"
               :colors="colors"
               :maxIntensity="20000" />

WorldMap

Nothing special in WorldMap.vue, just the x5-gmaps map component with the heatmap we just created inside. The options center the map, set the zoom, and turn off all of Google Map’s controls and buttons.

MapOptions

Similarly, MapOptions.vue is very basic. A group of radio buttons fixed in the top left corner that allow the selection of which type of data you map.

The one interesting thing is the use of the EventBus. The Vue data property type is what the radio button group is connected to, so we add a watcher for type and $emit the event the heatmap component is listening for, giving it our new value for type.

data: () => ({
  type: 'active'
}),
watch: {
  type(newVal) {
    EventBus.$emit('changeType', newVal)
  }
}

App

All the components are now ready, so we can put them in App.vue. It’s extremely basic and all we do is add the WorldMap component and MapOptions component inside a wrapper div that is fixed to full-screen.

Run

You should be able to run npm run serve and see our goal realised.

Conclusion

This is of course an extremely basic map. Improvements include:

  • Numbers of cases on map (x5-gmaps popup may help)
  • Graphs (e.g. a different dataset and vue-chartjs)
  • Heatmap re-evaluating when zooming in (e.g. filter data from map bounds)
  • Indication of data freshness (e.g. dates for each country)

… But those things are for another tutorial — or even better, for you to create and share!

I am still developing my x5-gmaps plugin; but it’s been built in a way you can add your own components so you don’t have to wait for me! If you do use it, please give it a star 🌟 and say what you’d like to see or share a component you’ve made for/with it.

Oh and claps 👏. I love claps.

Any questions, please ask here, Github, or contact me at chisnall.io.