Search code examples
javascriptopenlayersopenlayers-3openlayers-5angular-openlayers

Openlayers dateline crossing linestring disappears


I am working on openlayers, there is an issue when I try to add a linestring on the map which crosses the dateline several times.

To display the linestring across two worlds in the continuous segment I have added a function HandleDateline() which returns me modified (shifted either to left or right world) coordinates.

However, when you zoom-in on the left world to current settled view the linestring disappears. Also if you try to move the map to left, the line goes away.

The weird thing is if the line crosses more than 1 time, linestring on left worlds disappears otherwise same happens for right worlds. Too observe that, remove either first 3 or last 3 points from datelinecrossing[] which I will be posting down.

I am expecting a continuous linestring crossing the international dateline without any issues like disappearing.

If there is a better approach to this, I am open to all ideas. Here is the bin : ol dateline problem


Solution

  • You have to split the lines crossing the dateline programmatically at the dateline.

    var points = [
      [-170, -10],
      [170, 0],
      [-170, 10]
    ];
    
    var vectorSource = new ol.source.Vector();
    vectorSource.addFeature(createFeature(points));
    
    var vectorLayer = new ol.layer.Vector({
      source: vectorSource,
      style: new ol.style.Style({
        stroke: new ol.style.Stroke({
          width: 2,
          color: "red"
        })
      })
    });
    
    var osmLayer = new ol.layer.Tile({
      source: new ol.source.OSM()
    });
    
    var map = new ol.Map({
      layers: [osmLayer, vectorLayer],
      target: document.getElementById("map"),
      view: new ol.View({
        center: ol.proj.transform([180, 0], "EPSG:4326", "EPSG:3857"),
        zoom: 3
      })
    });
    
    var graticule = new ol.Graticule({
      strokeStyle: new ol.style.Stroke({
        color: "rgba(255,120,0,0.9)",
        width: 1.5,
        lineDash: [0.5, 4]
      }),
      showLabels: true
    });
    graticule.setMap(map);
    
    // -------------------------------------------------
    
    function createFeature(points) {
      var pointsSplitted = [];
      var pointsArray = [];
      pointsSplitted.push(points[0]);
      var lastLambda = points[0][0];
    
      for (var i = 1; i < points.length; i++) {
        var lastPoint = points[i - 1];
        var nextPoint = points[i];
        if (Math.abs(nextPoint[0] - lastLambda) > 180) {
          var deltaX = xToValueRange(nextPoint[0] - lastPoint[0]);
          var deltaY = nextPoint[1] - lastPoint[1];
          var deltaXS = xToValueRange(180 - nextPoint[0]);
          var deltaYS;
          if (deltaX === 0) {
            deltaYS = 0;
          } else {
            deltaYS = deltaY / deltaX * deltaXS;
          }
          var sign = lastPoint[0] < 0 ? -1 : 1;
          pointsSplitted.push([180 * sign, nextPoint[1] + deltaYS]);
          pointsArray.push(pointsSplitted);
          pointsSplitted = [];
          pointsSplitted.push([-180 * sign, nextPoint[1] + deltaYS]);
        }
        pointsSplitted.push(nextPoint);
        lastLambda = nextPoint[0];
      }
    
      pointsArray.push(pointsSplitted);
      var geom = new ol.geom.MultiLineString(pointsArray);
      geom.transform("EPSG:4326", "EPSG:3857");
      var feature = new ol.Feature({
        geometry: geom
      });
      return feature;
    }
    
    function xToValueRange(x) {
      if (Math.abs(x) > 180) {
        var sign = x < 0 ? -1 : 1;
        return x - 2 * 180 * sign;
      } else {
        return x;
      }
    }
    html,
    body,
    #map {
      width: 100%;
      height: 100%;
      overflow: hidden
    }
    <link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
    <script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
    
    <body>
      <div id="map" class="map" tabindex="0"></div>
    </body>