简体   繁体   中英

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

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> 

Simplifying HandleDateline so all coordinates are either in the western part of the normal world or the eastern part of the left world seems to fix it (so if the geometry crosses the date line the extent starts in the left world)

 function HandleDateline(array) {
        for (var i = 0; i < array.length ; i++) {
            if (array[i][0] > 0) {
                array[i][0] -= 360;
            }
        }
    }

However in worlds to the right the points west of the dateline then appear to be rendered below to linestring, while those east of the dateline are above it. Moving HandleDateline(datelinecrossing); above datelinecrossing.forEach fixes that.

You might also want to consider using a multipoint geometry for the points (unless you need them to be individually selectable).

HandleDateline(datelinecrossing);
var pdlcrossing = new ol.Feature({
    geometry: new ol.geom.MultiPoint(datelinecrossing).transform('EPSG:4326', 'EPSG:3857')
});
drawingSource.addFeature(pdlcrossing);
var dlcrossing = new ol.Feature({
    geometry: new ol.geom.LineString(datelinecrossing).transform('EPSG:4326', 'EPSG:3857')
});
drawingSource.addFeature(dlcrossing);

There is still a problem zooming in west of the dateline in the worlds on the right, so I think there will need to be two sets of each geometry, one offset to the left and another 360 degrees to the right:

function PlotGeometries(datelinecrossing){
  var pgeom = new ol.geom.MultiPoint(datelinecrossing);
  var pdlcrossing = new ol.Feature({
    geometry: pgeom.clone().transform('EPSG:4326', 'EPSG:3857')
  });
  drawingSource.addFeature(pdlcrossing);
  pgeom.translate(360,0);
  var pdlcrossing2 = new ol.Feature({
    geometry: pgeom.transform('EPSG:4326', 'EPSG:3857')
  });
  drawingSource.addFeature(pdlcrossing2);
  var geom = new ol.geom.LineString(datelinecrossing);
  var dlcrossing = new ol.Feature({
    geometry: geom.clone().transform('EPSG:4326', 'EPSG:3857')
  });
  drawingSource.addFeature(dlcrossing);
  geom.translate(360,0);
  var dlcrossing2 = new ol.Feature({
    geometry: geom.transform('EPSG:4326', 'EPSG:3857')
  });
  drawingSource.addFeature(dlcrossing2);
}

只需为您正在处理的世界的一部分设置地图视图的范围即可。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM