Search code examples
nuxt.jsamchartsamcharts4

How to dynamically interact with an AmCharts Map using Nuxt.js?


I would like to add an interactive map to my Nuxt.js website. I simply created a component that consists of the world map with AmCharts lib. My goal is to change the color of some countries (France in my example) if a button is clicked. Here is what my file looks like:

// components/Map.vue

<template>
  <div>
    <div id="chartdiv"/>
    <button @click="colorMe()">Click me!</button>
  </div>
</template>

<script>
import * as am4core from "@amcharts/amcharts4/core";
import * as am4maps from "@amcharts/amcharts4/maps";
import am4geodata_worldUltra from "@amcharts/amcharts4-geodata/worldUltra";

export default {
  methods: {
    colorMe() {
      worldPolygonSeries.getPolygonById("FR").fill = am4core.color("#f00");
    }
  },
  mounted() {
    // Create map instance
    let map = am4core.create("chartdiv", am4maps.MapChart);
        
    // Set map definition
    map.geodata = am4geodata_worldUltra;
        
    // Set projection
    map.projection = new am4maps.projections.Miller();
    
    // Zoom control
    map.zoomControl = new am4maps.ZoomControl();
        
    // The world
    let worldPolygonSeries = map.series.push(new am4maps.MapPolygonSeries());    
    worldPolygonSeries.useGeodata = true;
  }      
}
</script>

<style scoped>
#chartdiv {
  width: 100%;
  height: 350px;
}
</style>

The error I get when I click the button is worldPolygonSeries is not defined. So I tried to create map and worldPolygonSeries directly inside the data part and to pass it as parameters but this isn't working...

Something like this:

export default {
  data() {
    return {
      map: am4core.create("chartdiv", am4maps.MapChart),
      worldPolygonSeries: map.series.push(new am4maps.MapPolygonSeries())
    }
  },
  methods: {
    colorMe(worldPolygonSeries) {
      worldPolygonSeries.getPolygonById("FR").fill = am4core.color("#f00");
    }
  },
  mounted(map, worldPolygonSeries) {        
    // Set map definition
    map.geodata = am4geodata_worldUltra;
        
    // Set projection
    map.projection = new am4maps.projections.Miller();
    
    // Zoom control
    map.zoomControl = new am4maps.ZoomControl();
        
    // The world
    worldPolygonSeries.useGeodata = true;
  }
}

So now the error I get is Cannot set property 'geodata' of undefined. Is someone has any idea of how I can manage my code to reach my goal?


Solution

  • Ok I got it! I just change my variables to undefined on the data part, then I could access it from mounted and methods.

    // components/Map.vue
    
    <template>
      <div>
        <div id="chartdiv" class="h-96"/>
        <button @click="colorMe(worldPolygonSeries)">Click me!</button>
      </div>
    </template>
    
    <script>
    import * as am4core from "@amcharts/amcharts4/core";
    import * as am4maps from "@amcharts/amcharts4/maps";
    import am4geodata_worldUltra from "@amcharts/amcharts4-geodata/worldUltra";
    
    export default {
      data() {
        return {
          map: undefined,
          worldPolygonSeries: undefined
        }
      },
      methods: {
        colorMe(worldPolygonSeries) {
          worldPolygonSeries.getPolygonById("FR").fill = am4core.color("#f00");
        }
      },
      mounted() {
        // Create map instance
        this.map = am4core.create("chartdiv", am4maps.MapChart);
            
        // Set map definition
        this.map.geodata = am4geodata_worldUltra;
            
        // Set projection
        this.map.projection = new am4maps.projections.Miller();
        
        // Zoom control
        this.map.zoomControl = new am4maps.ZoomControl();
            
        // The world
        this.worldPolygonSeries = this.map.series.push(new am4maps.MapPolygonSeries());    
        this.worldPolygonSeries.useGeodata = true;
      }
    }     
    </script>
    
    <style scoped>
    #chartdiv {
      width: 100%;
      height: 350px;
    }
    </style>
    

    Thanks for your help Iman ;)