Load KML File To Your React Native Maps

React-native-maps library is actually able to load a structured map format but it's limited on geojson only. In a very spesific case, we want our app that using this library load a map data using KML format. The KML format itself is the standard/default exported file from google earth.


Preparation

Of course you need your react native maps working correctly on your react native app. You can setup by create your project, create API Key and then configure the library. Make sure the maps works by create single page and try to use them.

At least it is gonna be look like this:


Make sure you don't have any issue with zooming, panning, moving the maps


Other Library That We Need

We need a couple of library to make it works. Here is the thing, the concept is, we are gonna read the KML file, and then converts to a geojson object. We need to install :

  • axios (i am gonna shows you how to read kml file over internet)
  • xmldom
  • togeojson (a forked version from togeojson by mapbox)
  • react-native-fs  (install if you want to read kml for device storage. Configure it!)
  • react-native-document-picker (install if you want to read kml for device storage. Configure it!)

Read KML From Internet

Well, you need to prepare the kml file first. You can go to google earth and create projects from there. Make some shape or marker and export it as KML file.

Open your KML file using notepad or text editor, copy all of the value, the go to github gist (gists.github.com), create new gist there and make it as public. When create this, make sure you include the file format in a name (write it like this: jakarta.kml, do not do this: jakara)

If you want to know what url to hit, go to your gists github and select of your gist (your kml), clcik 'RAW', you should be redirected to a actual url of the file.

For example, take a look of my github gist here.


Github gist page. If you click the RAW button on right side, it will show you the actual url we need to hit



Here is the url 



The Code

I just want to give you small example here.

First the import will look like this:


import MapView, {PROVIDER_GOOGLE, Geojson} from 'react-native-maps';
import {kml} from '@tmcw/togeojson';
import {DOMParser} from 'xmldom';
import axios from 'axios';
import DocumentPicker from 'react-native-document-picker';
import RNFS from 'react-native-fs';


You need to have one state to store variable changes.

const [myPlace, setMyPlace] = useState();

Create a function to hit our KML url

const check = async () => {
    const url = 'yourGistRawUrl';

    const res = await axios
      .get(url)
      .then(r => {
        return r.data;
      })
      .catch(e => {
        console.log('error' + e);
        return e;
      });

    const theKml = new DOMParser().parseFromString(res);
    const converted = kml(theKml);
    setMyPlace(converted);
  };


We need to hit the url when we enter the app, so create a useEffect to hit the check() function.


useEffect(() => {
  check();
}, []);

Make sure your google maps view consume your state.


 {myPlace && (
   <MapView
      provider={PROVIDER_GOOGLE}
      style={styles.map}
      region={{
        latitude: -6.21462,
        longitude: 106.84513,
        latitudeDelta: 0.5,
        longitudeDelta: 0.5,
      }}>
        <Geojson
          geojson={myPlace}
          strokeColor="red"
          fillColor="green"
          strokeWidth={4}
          onPress={() => {}}
         />
    </MapView>
 )}


You should be able to load KML from internet.



Read KML From Device

You need to create a button or something like that to trigger the "Pick a file" prompt.
The code for pick a file will look like this:

const pickAFile = async () => {
  try {
    const res = await DocumentPicker.pick({
    type: ['application/vnd.google-earth.kml+xml'],
        allowMultiSelection: false,
    });

    const read = await readFile(res[0].uri);
    const theKml = new DOMParser().parseFromString(read);
    const converted = kml(theKml);
    setMyPlace(converted);
    } catch (err) {
      if (DocumentPicker.isCancel(err)) {
        // handle error
      } else {
        throw err;
      }
    }
 }


Notice that we call the readFile() function but we are not created it yet, so make it one like this:

const readFile = async MyPath => {
   try {
      const path = MyPath;
      const contents = await RNFS.readFile(path, 'utf8');
      return '' + contents;
    } catch (e) {
      console.log(e);
    }
}

Done. You just need to add that code to your previous code. Should be works. Of course my error handling is ugly since it is just for example and learning purpose, do not do it in production.


My Notes

I created a video version of this, but it's only read kml file from internet. Hope it useful for you.




Updated notes: I asked my friend to do similar steps on ReactJS, he said it is not applicable 100%, some library didn't work so it needs modification.


Post a Comment

0 Comments