2

My use case is that I have two maps side by side and then a user can move both independently to different regions on both and rotate also if necessary. Then, they press a button which will start synchronize on both maps from that point.

I saw how synchronize can work with the same view object but in my case from what I understand I need different view objects as the center and rotation will change.

How do I share a single view between two maps but have different center and rotation?

dementor
  • 85
  • 6
  • See https://stackoverflow.com/questions/53838791/openlayers-shared-views-side-by-side-how-to-properly-unbind-them Demo at http://mikenunn.16mb.com/demo/sync.html – Mike May 11 '19 at 14:21
  • Sorry if its not clear but the example showing synchronize maps altogether so the positions change when sync is clicked. I want sync from a custom spot on both maps i.e. center and rotation would be different for both maps and on clicking sync, it will sync from exactly that point. Example: Imagine having two maps with different orientation and and position, we rotate and move to make the orientation same and then press sync to sync from that exact state. Instead of resetting the map and sync. Is the question clearer? – dementor May 11 '19 at 21:02
  • I think you would need to listen for `change:center` and `change:rotation` events on each view and make corresponding relative changes to the other view. – Mike May 11 '19 at 22:09

2 Answers2

2

Synchronising changes to the views without synchronising the views can be done by listening for changes, but you need to prevent a change to one map which updates the other causing a further update to the original and an endless loop. Fortunately the animate method has a completion callback option so using that allows further updates to be disabled until the first is complete. http://mikenunn.16mb.com/demo/sync-changes.html

<!doctype html>
<html lang="en">

<head>
  <link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" type="text/css">
  <style>
    html, body, .map {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
    }
    .map1 {
        width: 50%;
        height: 40%;
    }
    .map2 {
        width: 50%;
        height: 40%;
    }
  </style>
  <script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
  <title>OpenLayers example</title>
</head>

<body>
  <div id="map1" class="map1"></div>
  <input type="submit" onclick="setSync()" value="Sync">
  <input type="submit" onclick="unsetSync()" value="Unsync">
  <div id="map2" class="map2"></div>
  <script type="text/javascript">

      var layer = new ol.layer.Tile({
        source: new ol.source.OSM()
      });

      var map1 = new ol.Map({
        target: 'map1',
        layers: [layer],
        view: new ol.View({
          center: [0, 0],
          zoom: 1
        })
      });

      var map2 = new ol.Map({
        target: 'map2',
        layers: [layer],
        view: new ol.View({
          center: [0, 0],
          zoom: 1
        })
      });

      var sync = false;
      var dx, dy, dz, dr;

      map1.getView().on(['change:center','change:resolution','change:rotation'], function() {
        if (sync) {
          var center = map1.getView().getCenter();
          var zoom = map1.getView().getZoom();
          var rotation = map1.getView().getRotation();
          sync = false;
          map2.getView().animate({
            center: [center[0] + dx, center[1] + dy],
            zoom: zoom + dz,
            rotation: rotation + dr,
            duration: 0
          }, function() { sync = true; });
        }
      });

      map2.getView().on(['change:center','change:resolution','change:rotation'], function() {
        if (sync) {
          var center = map2.getView().getCenter();
          var zoom = map2.getView().getZoom();
          var rotation = map2.getView().getRotation();
          sync = false;
          map1.getView().animate({
            center: [center[0] - dx, center[1] - dy],
            zoom: zoom - dz,
            rotation: rotation - dr,
            duration: 0
          }, function() { sync = true; });
        }
      });

      function setSync() {
        sync = true;
        var center1 = map1.getView().getCenter();
        var center2 = map2.getView().getCenter();
        dx = center2[0] - center1[0];
        dy = center2[1] - center1[1];
        var zoom1 = map1.getView().getZoom();
        var zoom2 = map2.getView().getZoom();
        dz = zoom2 - zoom1;
        var rotation1 = map1.getView().getRotation();
        var rotation2 = map2.getView().getRotation();
        dr = rotation2 - rotation1;
      }

      function unsetSync() {
        sync = false;
      }

  </script>
</body>

</html>
Mike
  • 16,042
  • 2
  • 14
  • 30
1

ol-ext has a Synchronize interaction that do the job for you. You just have to add it on the maps when the button is clicked.

See example http://viglino.github.io/ol-ext/examples/misc/map.interaction.synchronize.html

Viglino Jean-Marc
  • 1,371
  • 8
  • 6
  • That seems similar to http://mikenunn.16mb.com/demo/sync.html - once synchronised they have the same center, resolution and rotation. But in http://mikenunn.16mb.com/demo/sync-changes.html they move together relative to the positions they were in when sync is started. – Mike May 15 '19 at 22:25