Resizable Split Map Panes

Comparing layers

This example allows comparison of two layers with resizable map panes using the Split.js library.

TypeScript

function initMap(): void {
  const mapOptions = {
    center: { lat: 44.5250489, lng: -110.83819 },
    zoom: 18,
    scaleControl: false,
    streetViewControl: false,
  };

  // instantiate the map on the left with control positioning
  mapLeft = new google.maps.Map(
    document.getElementById("map-left") as HTMLElement,
    {
      ...mapOptions,
      mapTypeId: "satellite",
      tilt: 0, // at high zoom levels we need to maintain the same projection
      fullscreenControlOptions: {
        position: google.maps.ControlPosition.LEFT_BOTTOM,
      },
      mapTypeControlOptions: {
        position: google.maps.ControlPosition.LEFT_TOP,
      },
      zoomControlOptions: {
        position: google.maps.ControlPosition.LEFT_BOTTOM,
      },
    }
  );

  // instantiate the map on the right with control positioning
  mapRight = new google.maps.Map(
    document.getElementById("map-right") as HTMLElement,
    {
      ...mapOptions,
      fullscreenControlOptions: {
        position: google.maps.ControlPosition.RIGHT_BOTTOM,
      },
      mapTypeControlOptions: {
        position: google.maps.ControlPosition.RIGHT_TOP,
      },
      zoomControlOptions: {
        position: google.maps.ControlPosition.RIGHT_BOTTOM,
      },
    }
  );

  // helper function to keep maps in sync
  function sync(...maps: google.maps.Map[]) {
    let center: google.maps.LatLng, zoom: number;

    function update(changedMap) {
      maps.forEach((m) => {
        if (m === changedMap) {
          return;
        }
        m.setCenter(center);
        m.setZoom(zoom);
      });
    }

    maps.forEach((m) => {
      m.addListener("bounds_changed", () => {
        const changedCenter = m.getCenter()!;
        const changedZoom = m.getZoom()!;

        if (changedCenter !== center || changedZoom !== zoom) {
          center = changedCenter;
          zoom = changedZoom;
          update(m);
        }
      });
    });
  }

  sync(mapLeft, mapRight);

  function handleContainerResize() {
    const width = (document.getElementById("container") as HTMLElement)
      .offsetWidth;
    (document.getElementById(
      "map-left"
    ) as HTMLElement).style.width = `${width}px`;
    (document.getElementById(
      "map-right"
    ) as HTMLElement).style.width = `${width}px`;
  }

  // trigger to set map container size since using absolute
  handleContainerResize();
  // add event listener
  window.addEventListener("resize", handleContainerResize);

  //@ts-ignore
  Split(["#left", "#right"], {
    sizes: [50, 50],
  });
}

JavaScript

let mapLeft, mapRight;

function initMap() {
  const mapOptions = {
    center: { lat: 44.5250489, lng: -110.83819 },
    zoom: 18,
    scaleControl: false,
    streetViewControl: false,
  };
  // instantiate the map on the left with control positioning
  mapLeft = new google.maps.Map(document.getElementById("map-left"), {
    ...mapOptions,
    mapTypeId: "satellite",
    tilt: 0,
    fullscreenControlOptions: {
      position: google.maps.ControlPosition.LEFT_BOTTOM,
    },
    mapTypeControlOptions: {
      position: google.maps.ControlPosition.LEFT_TOP,
    },
    zoomControlOptions: {
      position: google.maps.ControlPosition.LEFT_BOTTOM,
    },
  });
  // instantiate the map on the right with control positioning
  mapRight = new google.maps.Map(document.getElementById("map-right"), {
    ...mapOptions,
    fullscreenControlOptions: {
      position: google.maps.ControlPosition.RIGHT_BOTTOM,
    },
    mapTypeControlOptions: {
      position: google.maps.ControlPosition.RIGHT_TOP,
    },
    zoomControlOptions: {
      position: google.maps.ControlPosition.RIGHT_BOTTOM,
    },
  });

  // helper function to keep maps in sync
  function sync(...maps) {
    let center, zoom;

    function update(changedMap) {
      maps.forEach((m) => {
        if (m === changedMap) {
          return;
        }
        m.setCenter(center);
        m.setZoom(zoom);
      });
    }
    maps.forEach((m) => {
      m.addListener("bounds_changed", () => {
        const changedCenter = m.getCenter();
        const changedZoom = m.getZoom();

        if (changedCenter !== center || changedZoom !== zoom) {
          center = changedCenter;
          zoom = changedZoom;
          update(m);
        }
      });
    });
  }
  sync(mapLeft, mapRight);

  function handleContainerResize() {
    const width = document.getElementById("container").offsetWidth;
    document.getElementById("map-left").style.width = `${width}px`;
    document.getElementById("map-right").style.width = `${width}px`;
  }
  // trigger to set map container size since using absolute
  handleContainerResize();
  // add event listener
  window.addEventListener("resize", handleContainerResize);
  //@ts-ignore
  Split(["#left", "#right"], {
    sizes: [50, 50],
  });
}

CSS

/* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
#map {
  height: 100%;
}

/* Optional: Makes the sample page fill the window. */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

#container,
#left,
#right,
.map,
.gutter {
  height: 100%;
}

#left,
#right,
.gutter {
  float: left;
  position: relative;
  overflow: hidden;
}

#map-left {
  position: absolute;
  left: 0;
  top: 0;
}

#map-right {
  position: absolute;
  right: 0;
  top: 0;
}

.gutter {
  background-color: #eee;
  background-repeat: no-repeat;
  background-position: 50%;
}

.gutter.gutter-horizontal {
  cursor: col-resize;
  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==");
}

HTML

<!DOCTYPE html>
<html>
  <head>
    <title>Split Map Panes</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/split.js/1.5.11/split.min.js"></script>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script src="./index.js"></script>
  </head>
  <body>
    <div id="container">
      <div id="left">
        <div id="map-left" class="map"></div>
      </div>
      <div id="right">
        <div id="map-right" class="map"></div>
      </div>
    </div>

    <!-- Async script executes immediately and must be after any DOM elements used in callback. -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap&libraries=&v=weekly"
      async
    ></script>
  </body>
</html>

All

<!DOCTYPE html>
<html>
  <head>
    <title>Split Map Panes</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/split.js/1.5.11/split.min.js"></script>

    <style type="text/css">
      /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
      #map {
        height: 100%;
      }

      /* Optional: Makes the sample page fill the window. */
      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }

      #container,
      #left,
      #right,
      .map,
      .gutter {
        height: 100%;
      }

      #left,
      #right,
      .gutter {
        float: left;
        position: relative;
        overflow: hidden;
      }

      #map-left {
        position: absolute;
        left: 0;
        top: 0;
      }

      #map-right {
        position: absolute;
        right: 0;
        top: 0;
      }

      .gutter {
        background-color: #eee;
        background-repeat: no-repeat;
        background-position: 50%;
      }

      .gutter.gutter-horizontal {
        cursor: col-resize;
        background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==");
      }
    </style>
    <script>
      let mapLeft, mapRight;

      function initMap() {
        const mapOptions = {
          center: { lat: 44.5250489, lng: -110.83819 },
          zoom: 18,
          scaleControl: false,
          streetViewControl: false,
        };
        // instantiate the map on the left with control positioning
        mapLeft = new google.maps.Map(document.getElementById("map-left"), {
          ...mapOptions,
          mapTypeId: "satellite",
          tilt: 0,
          fullscreenControlOptions: {
            position: google.maps.ControlPosition.LEFT_BOTTOM,
          },
          mapTypeControlOptions: {
            position: google.maps.ControlPosition.LEFT_TOP,
          },
          zoomControlOptions: {
            position: google.maps.ControlPosition.LEFT_BOTTOM,
          },
        });
        // instantiate the map on the right with control positioning
        mapRight = new google.maps.Map(document.getElementById("map-right"), {
          ...mapOptions,
          fullscreenControlOptions: {
            position: google.maps.ControlPosition.RIGHT_BOTTOM,
          },
          mapTypeControlOptions: {
            position: google.maps.ControlPosition.RIGHT_TOP,
          },
          zoomControlOptions: {
            position: google.maps.ControlPosition.RIGHT_BOTTOM,
          },
        });

        // helper function to keep maps in sync
        function sync(...maps) {
          let center, zoom;

          function update(changedMap) {
            maps.forEach((m) => {
              if (m === changedMap) {
                return;
              }
              m.setCenter(center);
              m.setZoom(zoom);
            });
          }
          maps.forEach((m) => {
            m.addListener("bounds_changed", () => {
              const changedCenter = m.getCenter();
              const changedZoom = m.getZoom();

              if (changedCenter !== center || changedZoom !== zoom) {
                center = changedCenter;
                zoom = changedZoom;
                update(m);
              }
            });
          });
        }
        sync(mapLeft, mapRight);

        function handleContainerResize() {
          const width = document.getElementById("container").offsetWidth;
          document.getElementById("map-left").style.width = `${width}px`;
          document.getElementById("map-right").style.width = `${width}px`;
        }
        // trigger to set map container size since using absolute
        handleContainerResize();
        // add event listener
        window.addEventListener("resize", handleContainerResize);
        //@ts-ignore
        Split(["#left", "#right"], {
          sizes: [50, 50],
        });
      }
    </script>
  </head>
  <body>
    <div id="container">
      <div id="left">
        <div id="map-left" class="map"></div>
      </div>
      <div id="right">
        <div id="map-right" class="map"></div>
      </div>
    </div>

    <!-- Async script executes immediately and must be after any DOM elements used in callback. -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap&libraries=&v=weekly"
      async
    ></script>
  </body>
</html>
let mapLeft, mapRight; function initMap() { const mapOptions = { center: { lat: 44.5250489, lng: -110.83819 }, zoom: 18, scaleControl: false, streetViewControl: false, }; // instantiate the map on the left with control positioning mapLeft = new google.maps.Map(document.getElementById("map-left"), { ...mapOptions, mapTypeId: "satellite", tilt: 0, fullscreenControlOptions: { position: google.maps.ControlPosition.LEFT_BOTTOM, }, mapTypeControlOptions: { position: google.maps.ControlPosition.LEFT_TOP, }, zoomControlOptions: { position: google.maps.ControlPosition.LEFT_BOTTOM, }, }); // instantiate the map on the right with control positioning mapRight = new google.maps.Map(document.getElementById("map-right"), { ...mapOptions, fullscreenControlOptions: { position: google.maps.ControlPosition.RIGHT_BOTTOM, }, mapTypeControlOptions: { position: google.maps.ControlPosition.RIGHT_TOP, }, zoomControlOptions: { position: google.maps.ControlPosition.RIGHT_BOTTOM, }, }); // helper function to keep maps in sync function sync(...maps) { let center, zoom; function update(changedMap) { maps.forEach((m) => { if (m === changedMap) { return; } m.setCenter(center); m.setZoom(zoom); }); } maps.forEach((m) => { m.addListener("bounds_changed", () => { const changedCenter = m.getCenter(); const changedZoom = m.getZoom(); if (changedCenter !== center || changedZoom !== zoom) { center = changedCenter; zoom = changedZoom; update(m); } }); }); } sync(mapLeft, mapRight); function handleContainerResize() { const width = document.getElementById("container").offsetWidth; document.getElementById("map-left").style.width = `${width}px`; document.getElementById("map-right").style.width = `${width}px`; } // trigger to set map container size since using absolute handleContainerResize(); // add event listener window.addEventListener("resize", handleContainerResize); //@ts-ignore Split(["#left", "#right"], { sizes: [50, 50], }); }
/* Always set the map height explicitly to define the size of the div * element that contains the map. */ #map { height: 100%; } /* Optional: Makes the sample page fill the window. */ html, body { height: 100%; margin: 0; padding: 0; } #container, #left, #right, .map, .gutter { height: 100%; } #left, #right, .gutter { float: left; position: relative; overflow: hidden; } #map-left { position: absolute; left: 0; top: 0; } #map-right { position: absolute; right: 0; top: 0; } .gutter { background-color: #eee; background-repeat: no-repeat; background-position: 50%; } .gutter.gutter-horizontal { cursor: col-resize; background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg=="); }
<!DOCTYPE html> <html> <head> <title>Split Map Panes</title> <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/split.js/1.5.11/split.min.js"></script> <!-- jsFiddle will insert css and js --> </head> <body> <div id="container"> <div id="left"> <div id="map-left" class="map"></div> </div> <div id="right"> <div id="map-right" class="map"></div> </div> </div> <!-- Async script executes immediately and must be after any DOM elements used in callback. --> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&libraries=&v=weekly" async ></script> </body> </html>