Rob
Rob

Reputation: 7717

Display GeoJSON with leaflet that spans the 180th meridian

I am trying to display a geoJSON object (outline of Russia, in this case) that spans the 180th meridian. Currently this displays with part of the country on the left side of the map and part on the right:

russia and the 180th meridian

Looking at leaflet, it seems there is a fix for this but that doesn't seem to work: https://github.com/Leaflet/Leaflet/issues/82. I have also tried adding a coordsToLatLng function but can't seem to get that to work either. Tile layers have a continuousWorld option which I do not think works with a geoJSON object.

This data is here: https://dl.dropboxusercontent.com/u/12085570/RUS.json. The data was generated from a shapefile to geojson and finally to topojson. Converting the topojson I used the --no-stitch-poles option which lets this display "nicely" on the map meaning it doesn't connect the points on the right to the left side of the map.

Is there a way to get this to display as a continuous object without splitting around the meridian?

Upvotes: 12

Views: 2364

Answers (2)

Mykola Tokariev
Mykola Tokariev

Reputation: 41

Solution in ReactJS

import React from "react";
import * as GeoJson from "./data/RUS_simple.json";

function Process180Meredian() {
  function download(content, fileName, contentType) {
    var a = document.createElement("a");
    var file = new Blob([content], { type: contentType });
    a.href = URL.createObjectURL(file);
    a.download = fileName;
    a.click();
  }

  function process(obj) {
    const coordinates = obj.features[0].geometry.coordinates;

    //loop through all coordinates and add 360 to all negative values
    for (let i = 0; i < coordinates.length; i++) {
      for (let j = 0; j < coordinates[i].length; j++) {
        for (let k = 0; k < coordinates[i][j].length; k++) {
          if (coordinates[i][j][k][0] < 0) {
            coordinates[i][j][k][0] += 360;
          }
        }
      }
    }

    //download the new file
    download(JSON.stringify(obj), "RUS_simple_processed.json", "text/plain");
  }

  return (
    <div>
      <button onClick={() => process(GeoJson)}>Process</button>
    </div>
  );
}

export default Process180Meredian;

Before enter image description here

After enter image description here

Upvotes: 0

jcarapia
jcarapia

Reputation: 640

I ran into this same issue and my solution involved taking advantage of a couple of things: 1) Leaflet allows you to place elements beyond the 180/-180 longitudes. 2) Geographic bodies that cross the antimeridian contain mostly all negative or positive longitude coordinates.

My solution was to use a recursive function to traverse the coordinates array within the geoJSON object and, in the case of Russia, convert the negative coordinate values to equivalent positive values. For example, a value of -175 would be converted to 185.

Below is the function I used to process the coordinates array. I used it for locations in the Eastern hemisphere - you'd have to modify the conversion in order to work with locations in the Western hemisphere.

  antimeridian(elem: any) {
   if (Array.isArray(elem)) {
     for (var i = 0; i < elem.length; i++) {
       if (Array.isArray(elem[i][0])) {
         this.antimeridian(elem[i]);
       } else {
         if (elem[i][0] < 0) {
           elem[i][0] = 180 + (180 + elem[i][0]);
         }
       }
     }
   }
 };

Upvotes: 3

Related Questions