You can configure a 2D WebGLMap with a cylindrical projection, like a Mercator projection or an equidistant cylindrical projection, to wrap around the date line. This article tells you how.

What’s date line wrapping?

With date line wrapping, the 2D map wraps around back to the other side of the world at the date line. It makes it easier to work with data around the date line, because users can just pan across the date line. Without it, the user has to pan back and forth to the other side of the map.

Date line wrapping off
Figure 1. A map without date line wrapping. The date line splits the cloud coverage image into 2 parts. To inspect it, the user needs to pan back and forth across the map.
Date line wrapping on
Figure 2. A map with date line wrapping. The user can pan across the date line to inspect the cloud coverage.

How do I enable date line wrapping?

You enable date line wrapping by specifying wrapAroundWorld: true as an option when you’re constructing a WebGLMap.

Program: Creating a map with date line wrapping enabled
const map = new WebGLMap("map", {
  reference: getReference("EPSG:3857"), // Web Mercator projection
  wrapAroundWorld: true
});

Date line wrapping is supported on a WebGLMap with a cylindrical projection only. Examples of cylindrical projections are Mercator projections or equidistant cylindrical projections. The cylindrical projection must also have a central meridian of 0.

Limiting the number of worlds visible at once

By default, you can only see one world at a time. You can configure this limit with the MapNavigator.constraints API.

Program: Configuring the maximum number of visible worlds on a wrapAroundWorld map
map.mapNavigator.constraints.wrapAroundWorld = {
  maxNumberOfWorlds: 3
};

If you allow only one world at a time, users can pan across the date line, but they can see any point of the world on their screen only once. The map part that falls off at one end becomes visible on the other side. Users can’t zoom out beyond a single world width on the screen.

If you allow more than one world, users can zoom out as far as they want. This configuration duplicates all information on all visible worlds, and might affect map performance.

What to consider when working with these maps?

Most things work out-of-the-box on this type of map. However, inspect your codebase for these API uses:

  • Pay attention when you are creating a transformation from map reference to model reference, CRS:84 for example, when using a map that is wrapped around the dateline. The map’s X coordinate might need special attention to normalize it to projection bounds. This problem is handled for you if you create your transformation using createTransformation method and by passing CreateTransformationOptions.normalizeWrapAround: map.wrapAroundWorld as option to it.

    Program: Transforming view points to the map reference without taking date line wrapping into account
    const map2LLH = createTransformation(map.reference, getReference("CRS:84"));
    const centerViewPoint = createPoint(null, [map.viewSize[0] / 2, map.viewSize[1] / 2]);
    const viewToMap = map.getViewToMapTransformation();
    const centerMapPoint = viewToMap.transform(centerViewPoint);
    const centerLLHPoint = map2LLH.transform(centerMapPoint);
    Program: Transforming view points to the map reference, taking date line wrapping into account
    const map2LLH = createTransformation(map.reference, getReference("CRS:84"), {normalizeWrapAround: map.wrapAroundWorld});
    let centerViewPoint = createPoint(null, [map.viewSize[0] / 2, map.viewSize[1] / 2]);
    const viewToMap = map.getViewToMapTransformation(LocationMode.TERRAIN);
    const centerMapPoint = viewToMap.transform(centerViewPoint);
    // the wrapAround normalization might've caused the point to be normalized to a different location on-screen
    // go back to view again, to make sure centerMapPoint matches centerViewPoint
    centerViewPoint = map.mapToViewTransformation.transform(centerMapPoint);
    const centerLLHPoint = map2LLH.transform(centerMapPoint);
  • Use of Map.mapToViewTransformation. Map.mapToViewTransformation takes multiple wrap-around worlds into account. The transformation returns a point in view if it exists. If more than one full world is visible, the returned view point is only for one of the worlds, typically the most central one.

    Map.mapToViewTransformation usage
    Figure 3. A map showing in green the pixel returned by a call to Map.mapToViewTransformation for map coordinates corresponding to Belgium. The map shows in red the pixels corresponding to Belgium on other worlds not returned by Map.mapToViewTransformation.
  • Use of Map.mapBounds. Map.mapBounds returned a bounds instance representing the visible part of the map. If the map can visualize more than one world at once, a single bounds might not be enough. Because of this, Map.mapBounds has been depecrated. Replace usages of Map.mapBounds with its newer counterpart: Map.getMapBounds(). This method returns an array of bounds instead of a single bounds instance. Additionally, it takes options to transform bounds to a target (model) reference.

    map.getMapBounds() usage
    Figure 4. The bounds in red and blue are the two distinct bounds returned by a call to Map.getMapBounds(). If Map.mapBounds had been used instead, only one of the bounds would have been returned.

Known limitations

  • The animation of MapNavigator.fit might take an unexpected detour when fitting on bounds on the other side of the dateline.

  • Clustering around the date line works as expected only when at most one world is visible.