Skip to content

Display content of utility network container

View on GitHubSample viewer app

A utility network container allows a dense collection of features to be represented by a single feature, which can be used to reduce map clutter.

Image of display content of utility network container

Use case

Offering a container view for features aids in the review for valid structural attachment and containment relationships and helps determine if a dataset has an association role set. Container views often model a cluster of electrical devices on a pole top or inside a cabinet or vault.

How to use the sample

Click on a container feature to show all features inside the container (the container view bounding box is marked by a yellow dashed line). The container is shown with the content features contained within. The viewpoint and scale of the map are also changed to the container's extent. Connectivity and attachment associations inside the container are shown as red and blue dotted lines respectively.

How it works

  1. Load a web map that includes ArcGIS Pro Subtype Group Layers with only container features visible (i.e. fuse bank, switch bank, transformer bank, hand hole and junction box).
  2. Create a GraphicsOverlay for displaying a container view.
  3. Create and load a UtilityNetwork with the same feature service URL as the layers in the web map (Naperville electric network feature service in this sample).
  4. Add an event handler for the onMouseClicked event of the MapView.
  5. Identify a feature and create a UtilityElement from it.
  6. Get the associations for this element using getAssociationsAsync(UtilityElement, UtilityAssociationType.Containment).
  7. Turn off the visibility of all the map's operational layers.
  8. Get the features for the UtilityElement(s) from the associations using fetchFeaturesForElementsAsync(List<UtilityElement>).
  9. Add a Graphic with the same geometry and symbol as these features.
  10. Add another Graphic that represents this extent and zoom to this extent with a buffer.
  11. Get associations for this extent using getAssociationsAsync(Envelope).
  12. Add a Graphic to represent the association geometry between them using a symbol that distinguishes between association types (attachment and connectivity in this sample data).
  13. Turn on the visibility of all the map's operational layers, clear the graphics in the graphics overlay, and zoom out to the previous extent to exit the container view.

Relevant API

  • SubtypeFeatureLayer
  • UtilityAssociation
  • UtilityAssociationType
  • UtilityElement
  • UtilityNetwork
  • UtilityNetworkDefinition

About the data

The Naperville electric network feature service, hosted on ArcGIS Online, contains a utility network used to find associations shown in this sample and a web map portal item, Naperville electric containers, that use the same feature service endpoint and displays only container features.

Tags

associations, connectivity association, containment association, structural attachment associations, utility network

Sample Code

DisplayContentOfUtilityNetworkContainerController.javaDisplayContentOfUtilityNetworkContainerController.javaDisplayContentOfUtilityNetworkContainerSample.java
Use dark colors for code blocksCopy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 /*  * Copyright 2021 Esri.  *  * Licensed under the Apache License, Version 2.0 (the "License");  * you may not use this file except in compliance with the License.  * You may obtain a copy of the License at  *  * http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */  package com.esri.samples.display_content_of_utility_network_container;  import com.esri.arcgisruntime.concurrent.ListenableFuture; import com.esri.arcgisruntime.data.ArcGISFeature; import com.esri.arcgisruntime.geometry.Geometry; import com.esri.arcgisruntime.geometry.GeometryEngine; import com.esri.arcgisruntime.geometry.Point; import com.esri.arcgisruntime.layers.SubtypeFeatureLayer; import com.esri.arcgisruntime.loadable.LoadStatus; import com.esri.arcgisruntime.mapping.ArcGISMap; import com.esri.arcgisruntime.mapping.Viewpoint; import com.esri.arcgisruntime.mapping.view.DrawStatus; import com.esri.arcgisruntime.mapping.view.Graphic; import com.esri.arcgisruntime.mapping.view.GraphicsOverlay; import com.esri.arcgisruntime.mapping.view.IdentifyLayerResult; import com.esri.arcgisruntime.mapping.view.MapView; import com.esri.arcgisruntime.security.AuthenticationChallengeHandler; import com.esri.arcgisruntime.security.AuthenticationChallengeResponse; import com.esri.arcgisruntime.security.AuthenticationManager; import com.esri.arcgisruntime.security.UserCredential; import com.esri.arcgisruntime.symbology.SimpleLineSymbol; import com.esri.arcgisruntime.symbology.Symbol; import com.esri.arcgisruntime.utilitynetworks.UtilityAssociation; import com.esri.arcgisruntime.utilitynetworks.UtilityAssociationType; import com.esri.arcgisruntime.utilitynetworks.UtilityElement; import com.esri.arcgisruntime.utilitynetworks.UtilityNetwork;  import javafx.fxml.FXML; import javafx.geometry.Point2D; import javafx.scene.control.Alert; import javafx.scene.control.ProgressIndicator; import javafx.scene.image.ImageView; import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.VBox; import javafx.scene.paint.Color;  import java.util.ArrayList; import java.util.List;  public class DisplayContentOfUtilityNetworkContainerController {   @FXML private VBox vBox;  @FXML private MapView mapView;  @FXML private ProgressIndicator progressIndicator;  @FXML private ImageView attachmentImageView;  @FXML private ImageView boundingBoxImageView;  @FXML private ImageView connectivityImageView;   private ArcGISFeature selectedContainerFeature;  private GraphicsOverlay graphicsOverlay;  private SimpleLineSymbol boundingBoxSymbol;  private SimpleLineSymbol attachmentSymbol;  private SimpleLineSymbol connectivitySymbol;  private UtilityNetwork utilityNetwork;  private Viewpoint previousViewpoint;   public void initialize() {   try {   // create a new graphics overlay to display container view contents  graphicsOverlay = new GraphicsOverlay();  mapView.getGraphicsOverlays().add(graphicsOverlay);   // create three new simple line symbols for displaying container view features  boundingBoxSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.DASH, Color.YELLOW, 3);  attachmentSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.DOT, Color.CORNFLOWERBLUE, 3);  connectivitySymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.DOT, Color.RED, 3);   // set image views for the association and bounding box symbols to display them in the legend  attachmentImageView.setImage(attachmentSymbol.createSwatchAsync(Color.TRANSPARENT).get());  connectivityImageView.setImage(connectivitySymbol.createSwatchAsync(Color.TRANSPARENT).get());  boundingBoxImageView.setImage(boundingBoxSymbol.createSwatchAsync(Color.TRANSPARENT).get());   // set user credentials to authenticate with the feature service and webmap url  // NOTE: a licensed user is required to perform utility network operations  // NOTE: Never hardcode login information in a production application. This is done solely for the sake of the sample.  var userCredential = new UserCredential("viewer01", "I68VGU^nMurF");  AuthenticationChallengeHandler authenticationChallengeHandler = authenticationChallenge ->  new AuthenticationChallengeResponse(AuthenticationChallengeResponse.Action.CONTINUE_WITH_CREDENTIAL, userCredential);  AuthenticationManager.setAuthenticationChallengeHandler(authenticationChallengeHandler);   // create a new map from the web map URL (includes ArcGIS Pro subtype group layers with only container features visible)  ArcGISMap map = new ArcGISMap("https://sampleserver7.arcgisonline.com/portal/home/item.html?id=813eda749a9444e4a9d833a4db19e1c8");  // the feature service url contains a utility network used to find associations shown in this sample  String featureServiceURL = "https://sampleserver7.arcgisonline.com/server/rest/services/UtilityNetwork/NapervilleElectric/FeatureServer";   // create a utility network, add it to the map's collection of utility networks, and load it  utilityNetwork = new UtilityNetwork(featureServiceURL);  map.getUtilityNetworks().add(utilityNetwork);  utilityNetwork.addDoneLoadingListener(() -> {  // show an error if the utility network did not load  if (utilityNetwork.getLoadStatus() != LoadStatus.LOADED) {  new Alert(Alert.AlertType.ERROR, "Error loading Utility Network.").show();  }  });  utilityNetwork.loadAsync();   // bind progress indicator visibility to map view draw status  progressIndicator.visibleProperty().bind(mapView.drawStatusProperty().isEqualTo(DrawStatus.IN_PROGRESS));   // set the map to the mapview and set the map view's viewpoint  mapView.setMap(map);  mapView.setViewpoint(new Viewpoint(41.801504, -88.163718, 4e3));   } catch (Exception e) {  e.printStackTrace();  }  }   /**  * Identifies the feature clicked on the map, gets their containment associations and elements, and displays the content  * of the elements features in a container view.  *  * @param e event registered when the map view is clicked on  */  @FXML  private void handleMapViewClicked(MouseEvent e) {   if (e.getButton() == MouseButton.PRIMARY && e.isStillSincePress()) {  // get the clicked map point  Point2D screenPoint = new Point2D(e.getX(), e.getY());   // identify the feature clicked on  ListenableFuture<List<IdentifyLayerResult>> identifyLayerResultsFuture =  mapView.identifyLayersAsync(screenPoint, 10, false);  identifyLayerResultsFuture.addDoneListener(() -> {  try {  // get the result of the query  List<IdentifyLayerResult> identifyLayerResults = identifyLayerResultsFuture.get();   // check that results have been returned  if (!identifyLayerResults.isEmpty()) {   identifyLayerResults.forEach(layerResult -> {  // check if the layer result is a subtype feature layer  if (layerResult.getLayerContent() instanceof SubtypeFeatureLayer) {  // loop through each sub layer result  layerResult.getSublayerResults().forEach(sublayerResult -> {  // filter the sublayer result's elements to find the first one which is an ArcGIS feature  sublayerResult.getElements().stream().filter(element -> element instanceof ArcGISFeature)  .findFirst().ifPresent(geoElement -> selectedContainerFeature = (ArcGISFeature) geoElement);  });  }  });   // create a container element using the selected feature  if (selectedContainerFeature != null) {   UtilityElement containerElement = utilityNetwork.createElement(selectedContainerFeature);   // get the containment associations from this element to display its content  ListenableFuture<List<UtilityAssociation>> containmentAssociationsFuture =  utilityNetwork.getAssociationsAsync(containerElement, UtilityAssociationType.CONTAINMENT);   containmentAssociationsFuture.addDoneListener(() -> {  try {  // get and store a list of elements from the result of the query  List<UtilityElement> contentElements = new ArrayList<>();   // get the list of containment associations and loop through them to get their elements  List<UtilityAssociation> containmentAssociations = containmentAssociationsFuture.get();  containmentAssociations.forEach(association -> {  UtilityElement utilityElement = association.getFromElement().getObjectId() ==  containerElement.getObjectId() ? association.getToElement() : association.getFromElement();  contentElements.add(utilityElement);  });   // check the list of elements isn't empty, and store the current viewpoint (this will be used later  // when exiting the container view  if (!contentElements.isEmpty()) {  previousViewpoint = mapView.getCurrentViewpoint(Viewpoint.Type.BOUNDING_GEOMETRY);  mapView.getMap().getOperationalLayers().forEach(layer -> layer.setVisible(false));   // enable container view vbox and disable interaction with the map view to avoid navigating away from container view  vBox.setVisible(true);  mapView.setDisable(true);   // fetch the features from the elements  ListenableFuture<List<ArcGISFeature>> fetchFeaturesFuture = utilityNetwork.fetchFeaturesForElementsAsync(contentElements);  fetchFeaturesFuture.addDoneListener(() -> {  try {  // get the content features and give them each a symbol, and add them as a graphic to the graphics overlay  List<ArcGISFeature> contentFeatures = fetchFeaturesFuture.get();  contentFeatures.forEach(content -> {  Symbol symbol = content.getFeatureTable().getLayerInfo().getDrawingInfo().getRenderer().getSymbol(content);  graphicsOverlay.getGraphics().add(new Graphic(content.getGeometry(), symbol));  });   Geometry firstGraphic = graphicsOverlay.getGraphics().get(0).getGeometry();  double containerViewScale = containerElement.getAssetType().getContainerViewScale();   if (graphicsOverlay.getGraphics().size() == 1 && firstGraphic instanceof Point) {  mapView.setViewpointCenterAsync((Point) firstGraphic, containerViewScale).addDoneListener(() -> {   // the bounding box, which defines the container view, may be computed using the extent of the features  // it contains or centered around its geometry at the container's view scale  Geometry boundingBox = mapView.getCurrentViewpoint(Viewpoint.Type.BOUNDING_GEOMETRY).getTargetGeometry();  identifyAssociationsWithExtent(boundingBox);  new Alert(Alert.AlertType.INFORMATION, "This feature has no associations").show();   });   } else {  Geometry boundingBox = GeometryEngine.buffer(graphicsOverlay.getExtent(), 0.05);  identifyAssociationsWithExtent(boundingBox);  }   } catch (Exception ex) {  new Alert(Alert.AlertType.ERROR, "Error fetching features for elements.").show();  ex.printStackTrace();  }  });   } else {  new Alert(Alert.AlertType.ERROR, "No content elements found").show();  }   } catch (Exception ex) {  new Alert(Alert.AlertType.ERROR, "Error getting containment associations.").show();  ex.printStackTrace();  }  });  } else new Alert(Alert.AlertType.ERROR, "No feature found").show();  }   } catch (Exception ex) {  new Alert(Alert.AlertType.ERROR, "Error getting result of the query.").show();  ex.printStackTrace();  }  });  }  }   /**  * Get associations for the specified geometry and display its associations.  *  * @param boundingBox the geometry from which to get associations.  */  private void identifyAssociationsWithExtent(Geometry boundingBox) {   // adds a graphic representing the bounding box of the associations identified and zooms to its extent  graphicsOverlay.getGraphics().add(new Graphic(boundingBox, boundingBoxSymbol));  mapView.setViewpointGeometryAsync(GeometryEngine.buffer(graphicsOverlay.getExtent(), 0.05));   // get the associations for this extent to display how content features are attached or connected.  ListenableFuture<List<UtilityAssociation>> extentAssociations = utilityNetwork.getAssociationsAsync(graphicsOverlay.getExtent());   extentAssociations.addDoneListener(() -> {  try {  extentAssociations.get().forEach(association -> {  // assign the appropriate symbol if the association is an attachment or connectivity type  Symbol symbol = association.getAssociationType() == UtilityAssociationType.ATTACHMENT ? attachmentSymbol :  connectivitySymbol;  graphicsOverlay.getGraphics().add(new Graphic(association.getGeometry(), symbol));  });   } catch (Exception ex) {  new Alert(Alert.AlertType.ERROR, "Error getting extent associations").show();  ex.printStackTrace();  }  });  }   /**  * Hides the exit container button, clears the graphics that were added to the graphics overlay,  * returns the viewpoint to where it was prior to entering the container view, enables map view interaction,  * and sets all the layers in the map's operational layers to visible, when the container view is exited.  */  @FXML  private void handleExitButtonClicked() {   vBox.setVisible(false);  graphicsOverlay.getGraphics().clear();  mapView.setDisable(false);  mapView.setViewpointAsync(previousViewpoint);  mapView.getMap().getOperationalLayers().forEach(layer -> layer.setVisible(true));   }   /**  * Stops and releases all resources used in application.  */  public void terminate() {   if (mapView != null) {  mapView.dispose();  }  } }

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.