4

Edit: According to the guideline, there is a method called getMetadata(). How can I use this to return the props?

Description:

Using the React-google-maps package, I've been able to load Google Maps with my own kml file. That KML file contains multiple shapes each with metadata behind it. What I want is that when a user clicks on one of these shapes, he sees the data behind the shape in for example a pop up.

Example

Let's say I have a Google map with a kml file that shows two countries. The user hovers over one of these countries and sees a pop up that shows which country he's over over. He hovers over the second country and gets the same. When he clicks on the kml shape over the country, he receives more information.

This requires me to do know few things:

- How to create a hover effect over the KML shape that shows data based on the shape
- How to create a click event on the KML shape that shows data based on the shape

However, I fail to understand how I can make this KML file interactive.
This is what I have until now:

import React, { Component } from 'react';
import { withScriptjs, withGoogleMap, GoogleMap, Marker, KmlLayer } from "react-google-maps"

const MyMapComponent = withScriptjs(withGoogleMap((props) =>
  <GoogleMap
    defaultZoom={8}
    defaultCenter={{ lat: 50.5010789, lng: 4.4764595 }}
  >
    <KmlLayer 
        url='https://example.be/kmlfile.kml'
        options={{ preserveViewport : false}}
    />
    {props.isMarkerShown && <Marker position={{ lat: 50.5010789, lng: 4.4764595 }} />}
  </GoogleMap>
))


export default class GoogleMaps extends Component {
    render(){
        return( 
            <MyMapComponent
              isMarkerShown
              googleMapURL="https://maps.googleapis.com/maps/api/js?key=MYKEY&v=3.exp&libraries=geometry,drawing,places"
              loadingElement={<div style={{ height: `100%` }} />}
              containerElement={<div style={{ height: `100%` }} />}
              mapElement={<div style={{ height: `100%` }} />}
            />
        )
    }
}
Cédric Bloem
  • 1,447
  • 3
  • 16
  • 34

1 Answers1

3

So I've fixed this my way following a few tutorials. I'm completely ignoring the react-google-maps package and I'm just using plain Javascript. Anyone who's looking for a way to add & switch between KMLayers and to add click and hover actions to it, this is how I did it and is my advice to fellow developers:

TIPS

1: Replace KML by GEOJSON

First of all, I am not using KMLayer but Datalayer now. This allows me more control and has much more documentation on Google. Therefore, you have to convert your KML to a GeoJson. I find that @Mapbox toGeoJSON does a fine job as it also keeps your custom data (which is very important if you want to have more freedom with your data!). Plus they also share their code to integrate in your application so you don't have to convert manually each time.

2: Analyze Google Api Data Layer documentation

Sounds straightforward, but still worth mentioning. As I said, Google shares a lot of information about implementing Data Layer. How to add click and mouseover events, how to style each individual shape and get that specific information, ...
Google doc on Data Layer

3: Replace loadGeoJson() by addGeoJson()

If your applications needs to switch between different Data Layers or simply has to add and remove one, you'll quickly find yourself stuck when using the loadGeoJson(). Hence the addGeoJson(), which will allow you to use map.data.remove() to remove the current Data layer.

Credit: @mensi for his answer on how to remove Data Layer

FINAL CODE

import React, { Component } from 'react';
import { SearchConsumer } from '../App.js';
import Icon from '../library/icons/Icon';

var map = ''
var dataLayer = ''
export default class mapSelection extends Component  {
    constructor(props){
        super(props)
        this.onScriptLoad = this.onScriptLoad.bind(this)
    }
    onScriptLoad() {
        // CREATE YOUR GOOGLE MAPS
        map = new window.google.maps.Map(
          document.getElementById('map'),
           {
                // ADD OPTIONS LIKE STYLE, CENTER, GESTUREHANDLING, ...
                center: { lat: 50.5, lng: 4 },
                zoom: 8,
                gestureHandling: 'greedy',
                disableDefaultUI: true,
            });
    }
    dataHandler = (getJson) => {
        // FIRST I REMOVE THE CURRENT LAYER (IF THERE IS ONE)
        for (var i = 0; i < dataLayer.length; i++) {
            map.data.remove(dataLayer[i])
        }
        // THEN I FETCH MY JSON FILE, IN HERE I'M USING A PROP BECAUSE 
        // I WANT TO USE THIS DATAHANDLER MULTIPLE TIMES & DYNAMICALLY 
        // I CAN NOW DO SOMETHING LIKE THIS: 
        // onClick(this.dataHandler(www.anotherlinktojsonfile.com/yourjsonfile.json))
        // ON EACH BUTTON AND CHOOSE WHICH JSON FILE NEEDS TO BE FETCHED IN MY DATAHANDLER.
        fetch(getJson)
            .then(response => response.json())
            .then(featureCollection => {
                dataLayer = map.data.addGeoJson(featureCollection)
                // ADD SOME NEW STYLE IF YOU WANT TO
                map.data.setStyle({strokeWeight: 0.5, fillOpacity: 0 });
            }
            );
        map.data.addListener('mouseover', (event) => {
            map.data.revertStyle();
            // ADD A STYLE WHEN YOU HOVER OVER A SPECIFIC POLYGON
            map.data.overrideStyle(event.feature, {strokeWeight: 1, fillOpacity: 0.1 });
            // IN CONSOLE LOG, YOU CAN SEE ALL THE DATA YOU CAN RETURN
            console.log(event.feature)
        });
        map.data.addListener('mouseout', (event) => {
            // REVERT THE STYLE TO HOW IT WAS WHEN YOU HOVER OUT
            map.data.revertStyle();
        });
    }
    componentDidMount() {
        // LOADING THE GOOGLE MAPS ITSELF
        if (!window.google) {
          var s = document.createElement('script');
          s.type = 'text/javascript';
          s.src = 'https://maps.google.com/maps/api/js?key=' + process.env.REACT_APP_MAPS_API_KEY;
          var x = document.getElementsByTagName('script')[0];
          x.parentNode.insertBefore(s, x);
          // Below is important. 
          //We cannot access google.maps until it's finished loading
          s.addEventListener('load', e => {
            this.onScriptLoad()
            this.dataHandler('https://linktoyourjson.com/yourjsonfile.json')

          })
        } else {
          this.onScriptLoad()
        }
    }
    render () {
        return (
            <div id='mapContainer'>
                <div style={{ width: '100%', height: '100%' }} id='map' />
            </div>
        );
    }
};

EXTRA CREDITS

I also want to thank cuneyt.aliustaoglu.biz for his wel explained tutorial in using Google Maps wihout any package.

And thanks to everyone who helped me with a minor problem

QUESTIONS OR SUGGESTIONS?

If there are any questions or if I missed something, you can always ask or tell me and I'll edit this post if necessary.

Cédric Bloem
  • 1,447
  • 3
  • 16
  • 34