Restrict web map navigation extent in Enterprise 10.9.1 or Experience Builder Developer 1.13

374
2
Jump to solution
11-17-2023 08:28 AM
Yuhash
by
Occasional Contributor

I understand we can restrict a web map's navigation extent as a configurable option in ArcGIS Online, but there aren't any such options in Enterprise 10.9.1 with which I'm working. 

Does anyone have any direction on how I might achieve restricting the pan and zoom options within my Experience Builder Developer (v1.13) app to the area of interest?

Many thanks in advance!

0 Kudos
2 Solutions

Accepted Solutions
Yuhash
by
Occasional Contributor

There are two approaches:

  1. In ArcGIS Pro, publish the web map setting a Map frame constraint 
  2. In ExB Dev there is a custom 'map-view' widget in the Sample Code repository. With the ArcGIS API for JavaScript you can modify the map view property (code example) to the intial default extent of the web map and set a minZoomScale property. 

This video provides a great demo: https://www.youtube.com/watch?v=aVjtFKkF9q8

View solution in original post

0 Kudos
Yuhash
by
Occasional Contributor

ExB Dev 1.13. Here is the widget.tsx code for a custom widget that restricts the map view

/**
  Licensing
  Copyright 2022 Esri
  Modified from 'map-view' sample code widget (JR, YH)

  Map view widget that will restrict the map view to the minZoomScale specified and restrict panning to the original extent of the map
*/
import { React, jimuHistory, DataSourceComponent, type AllWidgetProps, type IMState, type IMUrlParameters } from 'jimu-core'
import MapView from 'esri/views/MapView'
import type WebMap from 'esri/WebMap'
import Extent from 'esri/geometry/Extent'
import Point from "@arcgis/core/geometry/Point.js";
import { MapViewManager, type WebMapDataSource } from 'jimu-arcgis'
// Bring the 'Home' and 'Scalebar' properties into the map
import Home from '@arcgis/core/widgets/Home';
import ScaleBar from '@arcgis/core/widgets/ScaleBar';
import Popup from "@arcgis/core/widgets/Popup.js";


// Alert component state
interface State {
  isValidCenter: boolean;
}

// Not sure what the following does from the sample 'map-view' widget from which this code was modified queries the URL REST parameters for a mapview extent
interface ExtraProps {
  queryObject: IMUrlParameters
}

// Set a minimum zoom scale to prevent user from zooming out beyond the valid extent
const minZoomScale = 6


export default class Widget extends React.PureComponent<AllWidgetProps<unknown> & ExtraProps, State> {
  mapContainer = React.createRef<HTMLDivElement>()
  mapView: MapView
  webMap: WebMap
  extentWatch: __esri.WatchHandle

  mvManager: MapViewManager = MapViewManager.getInstance();

  constructor(props) {
    super(props);
    this.state = {
      isValidCenter: true, // Initialize state with default value
    };
  }

  static mapExtraStateProps = (state: IMState): ExtraProps => {
    return {
      queryObject: state.queryObject
    }
  }

  onDsCreated = (webmapDs: WebMapDataSource) => {
    console.log("Webmap loaded")
    if (!webmapDs) {
      console.log("Webmap not initialized")
      return
    }

    if (!this.mvManager.getJimuMapViewById(this.props.id)) {
      const options: __esri.MapViewProperties = {
        map: webmapDs.map,
        container: this.mapContainer.current,
        constraints:{
          minZoom: minZoomScale,
          snapToZoom: false
        }
        
      }
      console.log("minZoom set:", minZoomScale)

      this.mvManager.createJimuMapView({
        mapWidgetId: this.props.id,
        view: new MapView(options),
        dataSourceId: webmapDs.id,
        isActive: true,
        mapViewManager: this.mvManager
      }).then(jimuMapView => {

        // Create and add the Home widget to the map view
        const homeWidget = new Home({ view: jimuMapView.view });
        jimuMapView.view.ui.add(homeWidget, 'top-left');
        
        // Need to explictly cast the view to --esri.MapViewProperties
        // to ensure type compatibility with the scalebar  
        const mapView = jimuMapView.view as __esri.MapViewProperties;
        // Create and add the Scalebar widget to the map view
        const scaleBarWidget = new ScaleBar({ view: mapView });
        jimuMapView.view.ui.add(scaleBarWidget,'bottom-left')
        
        //console.log(mapView.extent)
        const view = jimuMapView.view as __esri.MapView;
        const extentLimit = view.extent.clone();
        view.constraints.geometry = extentLimit

      })
    }
  }

  mapNode = <div className="widget-map" style={{ width: '100%', height: '100%' }} ref={this.mapContainer}></div>
  
  render () {
    if (!this.props.useDataSources || this.props.useDataSources.length === 0) {
      return 'Select a webmap in the settings panel'
    }
    return <DataSourceComponent useDataSource={this.props.useDataSources[0]} onDataSourceCreated={this.onDsCreated}>
      {this.mapNode}

    </DataSourceComponent>
  }
}
 

View solution in original post

0 Kudos
2 Replies
Yuhash
by
Occasional Contributor

There are two approaches:

  1. In ArcGIS Pro, publish the web map setting a Map frame constraint 
  2. In ExB Dev there is a custom 'map-view' widget in the Sample Code repository. With the ArcGIS API for JavaScript you can modify the map view property (code example) to the intial default extent of the web map and set a minZoomScale property. 

This video provides a great demo: https://www.youtube.com/watch?v=aVjtFKkF9q8

0 Kudos
Yuhash
by
Occasional Contributor

ExB Dev 1.13. Here is the widget.tsx code for a custom widget that restricts the map view

/**
  Licensing
  Copyright 2022 Esri
  Modified from 'map-view' sample code widget (JR, YH)

  Map view widget that will restrict the map view to the minZoomScale specified and restrict panning to the original extent of the map
*/
import { React, jimuHistory, DataSourceComponent, type AllWidgetProps, type IMState, type IMUrlParameters } from 'jimu-core'
import MapView from 'esri/views/MapView'
import type WebMap from 'esri/WebMap'
import Extent from 'esri/geometry/Extent'
import Point from "@arcgis/core/geometry/Point.js";
import { MapViewManager, type WebMapDataSource } from 'jimu-arcgis'
// Bring the 'Home' and 'Scalebar' properties into the map
import Home from '@arcgis/core/widgets/Home';
import ScaleBar from '@arcgis/core/widgets/ScaleBar';
import Popup from "@arcgis/core/widgets/Popup.js";


// Alert component state
interface State {
  isValidCenter: boolean;
}

// Not sure what the following does from the sample 'map-view' widget from which this code was modified queries the URL REST parameters for a mapview extent
interface ExtraProps {
  queryObject: IMUrlParameters
}

// Set a minimum zoom scale to prevent user from zooming out beyond the valid extent
const minZoomScale = 6


export default class Widget extends React.PureComponent<AllWidgetProps<unknown> & ExtraProps, State> {
  mapContainer = React.createRef<HTMLDivElement>()
  mapView: MapView
  webMap: WebMap
  extentWatch: __esri.WatchHandle

  mvManager: MapViewManager = MapViewManager.getInstance();

  constructor(props) {
    super(props);
    this.state = {
      isValidCenter: true, // Initialize state with default value
    };
  }

  static mapExtraStateProps = (state: IMState): ExtraProps => {
    return {
      queryObject: state.queryObject
    }
  }

  onDsCreated = (webmapDs: WebMapDataSource) => {
    console.log("Webmap loaded")
    if (!webmapDs) {
      console.log("Webmap not initialized")
      return
    }

    if (!this.mvManager.getJimuMapViewById(this.props.id)) {
      const options: __esri.MapViewProperties = {
        map: webmapDs.map,
        container: this.mapContainer.current,
        constraints:{
          minZoom: minZoomScale,
          snapToZoom: false
        }
        
      }
      console.log("minZoom set:", minZoomScale)

      this.mvManager.createJimuMapView({
        mapWidgetId: this.props.id,
        view: new MapView(options),
        dataSourceId: webmapDs.id,
        isActive: true,
        mapViewManager: this.mvManager
      }).then(jimuMapView => {

        // Create and add the Home widget to the map view
        const homeWidget = new Home({ view: jimuMapView.view });
        jimuMapView.view.ui.add(homeWidget, 'top-left');
        
        // Need to explictly cast the view to --esri.MapViewProperties
        // to ensure type compatibility with the scalebar  
        const mapView = jimuMapView.view as __esri.MapViewProperties;
        // Create and add the Scalebar widget to the map view
        const scaleBarWidget = new ScaleBar({ view: mapView });
        jimuMapView.view.ui.add(scaleBarWidget,'bottom-left')
        
        //console.log(mapView.extent)
        const view = jimuMapView.view as __esri.MapView;
        const extentLimit = view.extent.clone();
        view.constraints.geometry = extentLimit

      })
    }
  }

  mapNode = <div className="widget-map" style={{ width: '100%', height: '100%' }} ref={this.mapContainer}></div>
  
  render () {
    if (!this.props.useDataSources || this.props.useDataSources.length === 0) {
      return 'Select a webmap in the settings panel'
    }
    return <DataSourceComponent useDataSource={this.props.useDataSources[0]} onDataSourceCreated={this.onDsCreated}>
      {this.mapNode}

    </DataSourceComponent>
  }
}
 
0 Kudos