esriarcgis-js-apiesri-maps

ESRI ArcGIS: Pan and Zoom to fit markers


I am new to ESRI ArcGIS. We are considering as a replacement for Google Maps. In this post https://www.esri.com/arcgis-blog/products/js-api-arcgis/announcements/migrating-from-google-maps-javascript-api-to-arcgis-api-for-javascript/ they explain how easy it should be to migrate to ArcGIS, but it seems like beyond the examples they provide, I am stuck.

I loaded a bunch of markers in a map. I am trying to have the map pan and zoom to fit all markers, and I have been unable to find any code that does that.

On Google Maps I'd do something like this:

myMap.options.center = new google.maps.LatLng(0,0);
myMap.options.mapTypeId = google.maps.MapTypeId[myMap.options.mapTypeId];
myMap.bounds = new google.maps.LatLngBounds();
myMap.map = new google.maps.Map(document.getElementById('cat-map'), myMap.options);

google.maps.event.addListenerOnce(myMap.map, 'bounds_changed', function(event){
    myMap.map.fitBounds(myMap.bounds);
    myMap.map.panToBounds(myMap.bounds);
});

for (var i = 0; i < myMap.items.length; i++) {
    var itemLatlng = new google.maps.LatLng(myMap.items[i].lat, myMap.items[i].lng);
    myMap.bounds.extend(itemLatlng);
    new google.maps.Marker({
        position: itemLatlng,
        map: myMap.map,
    });
}

But I have been unable to find the equivalent on ESRI ArcGIS.

Anyone has some guidance?


Solution

  • You have the right idea. In ArcGIS API Extent class has union method that extend the caller to include the geometry extent pass as parameter. Because you are using Point you can't use union method, Point extent is null. But no worries you can achieve this just iterating the graphics and extending the extent yourself.

    Look at this example I made for you using as base the link of your question,

    <html>
    
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>ArcGIS API for JavaScript Hello World App</title>
      <style>
        html,
        body,
        #viewDiv {
          padding: 0;
          margin: 0;
          height: 100%;
          width: 100%;
        }
        #zoomBtn {
          margin: .5rem;
        }
      </style>
    
      <link rel="stylesheet" href="https://js.arcgis.com/4.15/esri/css/main.css">
      <script src="https://js.arcgis.com/4.15/"></script>
    
      <script>
        require([
          "esri/Map",
          "esri/views/MapView",
          'esri/geometry/Extent'
        ], function (Map, MapView, Extent) {
    
          const map = new Map({
            basemap: "streets-navigation-vector"
          });
    
          const view = new MapView({
            container: "viewDiv",
            map: map,
            zoom: 12,
            center: {
              latitude: 32.7353,
              longitude: -117.1490
            }
          });
    
          function popupContent (feature) {
            const div = document.createElement("div");
            div.innerHTML = `Address: ${feature.graphic.attributes.addrs} <br>` +
              `<a href='${feature.graphic.attributes.url}'>Web</a>`;
            return div;
          }
    
          function toGraphic(color, lon, lat, title, addrs, url) {
            return {
              symbol: {
                type: "text",
                color,
                text: "\ue61d",
                font: {
                  size: 30,
                  family: "CalciteWebCoreIcons"
                }
              },
              geometry: {
                type: "point",
                longitude: lon,
                latitude: lat
              },
              attributes: {
                title,
                addrs,
                url
              },
              popupTemplate: {
                title: '{title}',
                outfields: ['*'],
                content: popupContent
              }
            }
          }
    
          const graphics = [
            toGraphic(
              'gray',
              -117.1560632,
              32.727482,
              'Automotive Museum',
              '2080 Pan American Plaza, San Diego, CA 92101, United States',
              'http://sdautomuseum.org/'
            ),
            toGraphic(
              'gray',
              -117.1763293,
              32.7136902,
              'USS Midway Museum',
              '910 N Harbor Dr, San Diego, CA 92101, United States',
              'http://www.midway.org/'
            ),
            toGraphic(
              'blue',
              -117.2284536,
              32.7641112,
              'SeaWorld',
              '500 Sea World Dr, San Diego, CA 92109, United States',
              'https://seaworld.com/san-diego'
            ),
            toGraphic(
              'green',
              -117.1557741,
              32.7360032,
              'Zoo',
              '2920 Zoo Dr, San Diego, CA 92101, United States',
              'https://zoo.sandiegozoo.org/'
            )
          ];
    
          view.graphics.addMany(graphics);
    
          function maxExtent(graphics) {
            const e = graphics
              .map(g => g.geometry)
              .reduce(
                (acc, geom) => (
                  {
                    xmin: Math.min(acc.xmin, geom.longitude),
                    ymin: Math.min(acc.ymin, geom.latitude),
                    xmax: Math.max(acc.xmax, geom.longitude),
                    ymax: Math.max(acc.ymax, geom.latitude)
                  }
                ),
                {
                  xmin: Number.MAX_SAFE_INTEGER,
                  ymin: Number.MAX_SAFE_INTEGER,
                  xmax: Number.MIN_SAFE_INTEGER,
                  ymax: Number.MIN_SAFE_INTEGER
                }
              );
            return new Extent(e);
          }
    
          document.getElementById('zoomBtn')
            .addEventListener(
              'click',
              _ => {
                const ext = maxExtent(graphics);
                console.log(`View Extent: ${JSON.stringify(view.extent)} Graphics Extent:${JSON.stringify(ext)}`);
                view.extent = ext.expand(2); // expand a little so border points shows
              }
            );
    
        });
      </script>
    </head>
    
    <body>
      <div class="esri-widget">
        <button id="zoomBtn" class="esri-button">Zoom To Graphics</button>
      </div>
      <div id="viewDiv"></div>
    </body>
    
    </html>