Prevent continious wrap v4.15

2068
9
06-02-2020 08:16 AM
samuelgirardin
New Contributor II

Hi  everyone, I'm quite new to esri js api. I'm using esri js api 4.15. I can't figure out how doing that : 

I try to display only a single world, I don't want to be able to continious wrap around.

I 've seen this jsfiddle using 3.3, it seems that setting wrapAround180 to false, display only a single world and prevent continious wrapping.

jsfiddle demo no continious wrap v3.3

Unfortunately wrapAround180  is no more used in v4.15, doc is talking about SpatialReference.isWrappable . I can't get this working.

Maybe someone solves that before ? Is there any solution ?

Thanks, sam

0 Kudos
9 Replies
samuelgirardin
New Contributor II

Maybe, my explanation is not clear enough. I'm looking for something like this  : https://developers.arcgis.com/net/latest/ios/guide/wraparound-maps.htm  . This doc is fromm .net framework, do we have something similar with js api 4.15 ?

this._esriView.WrapAroundMode = false ; 
0 Kudos
samuelgirardin
New Contributor II

I'm still stuck in this really simple problem... I found a 'not too bad' solution. This method is called by an  'update' in a : scheduling.frametask . I'm sure I'm missing something, and you have @esri already implemented something like :  this._esriView.WrapAroundMode = false ;  in 4.15, can someone can confirm or not that  ?  It would be really nice.

sam

my not too bad method  (ok when momentum anim or dragging)

 private warpLimit() {  
    const left = this._view.toMap({ x: 0y: 0 }).x;
    const mid = this._view.viewpoint.targetGeometry.x;
    const dist = Math.abs(mid - left);
    const right = left + 2 * dist ;
    const earthCircumHalf = 20037508 ; 

    const opts = {
      duration: 0
    };
    if (left < -earthCircumHalf) {
      this._view.goTo({}, opts).catch((error=> { });
      this._view.viewpoint.targetGeometry.x = -earthCircumHalf + dist;

    } else if (right > Prop.EarthCircumHalf) {
      this._view.goTo({}, opts).catch((error=> { });
      this._view.viewpoint.targetGeometry.x = earthCircumHalf - dist;
    }
  }
0 Kudos
ChristianBischof
Esri Contributor
view.when(function () {
   limitMapView(view);
});

function limitMapView(view) {
     var initialExtent = view.extent;
     var initialLon = view.extent.center.longitude;
     var initialLat = view.extent.center.latitude;
     var initialZoom = view.zoom;
     view.watch("stationary", function (event) {
       if (!event) {
         return;
       }
       // If the center of the map has moved outside the initial extent,
       // then move back to the initial map position (i.e. initial zoom and extent
       var currentCenter = view.extent.center;
       var currentLon = view.extent.center.longitude;
       var currentLat = view.extent.center.latitude;
       if (!initialExtent.contains(currentCenter)) {
         view.goTo({
           target: initialExtent,
           zoom: initialZoom,
         });
       }
     });
}

I don't know what the exact usecase of your app is but this code snippet should "bring you back" to the inital extent. Maybe it's helpful, maybe it's not. Or should your map be kinda "blocked" when it comes to it's west/east end?

0 Kudos
ChristianBischof
Esri Contributor
<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <!--
  ArcGIS API for JavaScript, https://js.arcgis.com
  For more information about the intro-mapview sample, read the original sample description at developers.arcgis.com.
  https://developers.arcgis.com/javascript/latest/sample-code/intro-mapview/index.html
  -->
<title>Intro to MapView - Create a 2D map - 4.15</title>
    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }
    </style>

    <link
      rel="stylesheet"
      href="https://js.arcgis.com/4.15/esri/themes/light/main.css"
    />
    <script src="https://js.arcgis.com/4.15/"></script>

    <script>
      require(["esri/Map", "esri/views/MapView"], function(Map, MapView) {
        var map = new Map({
          basemap: "streets"
        });

        var view = new MapView({
          container: "viewDiv",
          map: map,
          zoom: 4,
          center: [15, 65] // longitude, latitude
        });
        
        view.when(disableZooming);
        function disableZooming(view) {
          view.popup.dockEnabled = true;

          // Removes the zoom action on the popup
          view.popup.actions = [];

          // stops propagation of default behavior when an event fires
          function stopEvtPropagation(event) {
            event.stopPropagation();
          }

          // disables pinch-zoom and panning on the view
          view.on("drag", stopEvtPropagation);

          // disable the view's zoom box to prevent the Shift + drag
          // and Shift + Control + drag zoom gestures.
          view.on("drag", ["Shift"], stopEvtPropagation);
          view.on("drag", ["Shift", "Control"], stopEvtPropagation);

          // prevents zooming with the + and - keys
          view.on("key-down", function (event) {
            var prohibitedKeys = ["+", "-", "Shift", "_", "="];
            var keyPressed = event.key;
            if (prohibitedKeys.indexOf(keyPressed) !== -1) {
              event.stopPropagation();
            }
          });

          return view;
        }
      });
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
  </body>
</html>

Another suggestion is to navigate the map only by zooming functionality and prevent the paning from happening.

0 Kudos
samuelgirardin
New Contributor II

@christian bischof, thanks for your 2 answers, but I really need to diplay only one world (the what I want img). Do you think this is possible ? or not  ?

Esri js api know which world is displayed at center, I found this : 

this._view.frameTask.graphicsView.container.children[XXX]?.key?.world.

world is set at 0 (the first ), world-- on the left and world ++ on the right. I'm trying to disable tiles rendering when world!==0 with no luck for the moment, any idea ? 

Thanks. sam.

ChristianBischof
Esri Contributor

Right off the cuff I can't come up with a ready to use solution, but I guess your suggestion is a good start. The faster one of us could simply post the solution below. I'll try it myself.

0 Kudos
samuelgirardin
New Contributor II

I succeed to prevent tiles rendering when they belong to a different world. As my only ''''sources''''' is the view object console printed, maybe that s a really bad way to achieve this. It works. In this code below, I'm  not sure that the j loop is necessary. The code is called each new frame

 const prelen = this._view._stage?.children.length ; 
      for (let j = 0j < prelenj++) {
        const len1 = this._view._stage?.children[j]?.children?.length;
        for (let i = 0i < len1i++) {
          if (this._view._stage?.children[j]?.children[i]) {        
            if (this._view._stage.children[j].children[i].key.world !== 0) {
             this._view._stage.children[j].children[i].visible = false;  
            }  
          }
        }
      }    
    }

 All is ok but I still have this unwanted blue color under discarded tiles. Any idea ? 

thx , sam

0 Kudos
Noah-Sager
Esri Regular Contributor

For that background, we'll expose a configurable property on the view to modify. It should be available on `next` and will release with 4.16 in a month or so.

feedback-js-api-next/CHANGELOG.md at master · Esri/feedback-js-api-next · GitHub 

example:

var view = new MapView({
   container: "viewDiv",
   map: map,
   background: { // autocasts as new ColorBackground()
      color: "gray" // autocasts as new Color()
   }
});

samuelgirardin
New Contributor II

Thanks Noah for your answer, and this futur background color property. Any chance to get  constraint pan/drag and momentum to a given xminmax, yminmax extent  ? All I try is just 'not too bad' , but my project manager like perfection (-: .

thx sam

0 Kudos