Skip to content

Commit ef70ffc

Browse files
authored
Merge pull request #253 from Esri/map-image-layer-tables
map image layer tables sample
2 parents aefe1a4 + c1d6724 commit ef70ffc

File tree

3 files changed

+286
-0
lines changed

3 files changed

+286
-0
lines changed
238 KB
Loading
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
/*
2+
* Copyright 2018 Esri.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
17+
package com.esri.samples.imagelayers.map_image_layer_tables;
18+
19+
import java.util.List;
20+
import java.util.concurrent.ExecutionException;
21+
22+
import javafx.application.Application;
23+
import javafx.geometry.Insets;
24+
import javafx.geometry.Pos;
25+
import javafx.scene.Scene;
26+
import javafx.scene.control.Alert;
27+
import javafx.scene.control.ListCell;
28+
import javafx.scene.control.ListView;
29+
import javafx.scene.layout.StackPane;
30+
import javafx.stage.Stage;
31+
32+
import com.esri.arcgisruntime.arcgisservices.RelationshipInfo;
33+
import com.esri.arcgisruntime.concurrent.ListenableFuture;
34+
import com.esri.arcgisruntime.data.ArcGISFeature;
35+
import com.esri.arcgisruntime.data.Feature;
36+
import com.esri.arcgisruntime.data.FeatureQueryResult;
37+
import com.esri.arcgisruntime.data.QueryParameters;
38+
import com.esri.arcgisruntime.data.RelatedFeatureQueryResult;
39+
import com.esri.arcgisruntime.data.RelatedQueryParameters;
40+
import com.esri.arcgisruntime.data.ServiceFeatureTable;
41+
import com.esri.arcgisruntime.geometry.Point;
42+
import com.esri.arcgisruntime.layers.ArcGISMapImageLayer;
43+
import com.esri.arcgisruntime.loadable.LoadStatus;
44+
import com.esri.arcgisruntime.mapping.ArcGISMap;
45+
import com.esri.arcgisruntime.mapping.Basemap;
46+
import com.esri.arcgisruntime.mapping.Viewpoint;
47+
import com.esri.arcgisruntime.mapping.view.Graphic;
48+
import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
49+
import com.esri.arcgisruntime.mapping.view.MapView;
50+
import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
51+
import com.esri.arcgisruntime.symbology.SimpleRenderer;
52+
53+
public class MapImageLayerTablesSample extends Application {
54+
55+
private MapView mapView;
56+
private GraphicsOverlay graphicsOverlay;
57+
private ServiceFeatureTable commentsTable;
58+
private ListView<Feature> commentsListView;
59+
60+
/**
61+
* Starting point of this application.
62+
*
63+
* @param args arguments to this application.
64+
*/
65+
public static void main(String[] args) {
66+
67+
Application.launch(args);
68+
}
69+
70+
@Override
71+
public void start(Stage stage) throws Exception {
72+
73+
try {
74+
// create a stack pane and application scene
75+
StackPane stackPane = new StackPane();
76+
Scene scene = new Scene(stackPane);
77+
scene.getStylesheets().add(getClass().getResource("/css/style.css").toExternalForm());
78+
79+
// size the stage and add a title
80+
stage.setTitle("Map Image Layer Tables Sample");
81+
stage.setWidth(800);
82+
stage.setHeight(700);
83+
stage.setScene(scene);
84+
stage.show();
85+
86+
// create a map with a basemap
87+
ArcGISMap map = new ArcGISMap(Basemap.createStreetsVector());
88+
89+
// create and add a map image layer to the map
90+
// the map image layer contains a feature table with related spatial and non-spatial comment features
91+
ArcGISMapImageLayer imageLayer = new ArcGISMapImageLayer(
92+
"https://sampleserver6.arcgisonline.com/arcgis/rest/services/ServiceRequest/MapServer");
93+
map.getOperationalLayers().add(imageLayer);
94+
95+
// create a map view and set the map to it
96+
mapView = new MapView();
97+
mapView.setMap(map);
98+
99+
// create a graphics overlay to show the related spatial features in
100+
graphicsOverlay = new GraphicsOverlay();
101+
mapView.getGraphicsOverlays().add(graphicsOverlay);
102+
103+
// show the related graphics as cyan circles
104+
SimpleRenderer renderer = new SimpleRenderer();
105+
renderer.setSymbol(new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, 0xFF00FFFF, 14));
106+
graphicsOverlay.setRenderer(renderer);
107+
108+
// create a list view to show the non-spatial comment features
109+
commentsListView = new ListView<>();
110+
commentsListView.setMaxSize(200.0, 150.0);
111+
// show the comments attribute of the feature in the list
112+
commentsListView.setCellFactory(listView -> new ListCell<>() {
113+
@Override
114+
protected void updateItem(Feature item, boolean empty) {
115+
super.updateItem(item, empty);
116+
if (item != null) {
117+
ArcGISFeature feature = (ArcGISFeature) item;
118+
setText((String) feature.getAttributes().get("comments"));
119+
}
120+
}
121+
});
122+
123+
// when a comment is selected, query its related spatial features and show the first result on the map
124+
commentsListView.getSelectionModel().selectedItemProperty().addListener(observable -> showRelatedRequests());
125+
126+
// when the layer is loaded, get the comment features
127+
imageLayer.addDoneLoadingListener(() -> {
128+
if (imageLayer.getLoadStatus() == LoadStatus.LOADED) {
129+
// zoom to the layer's extent
130+
mapView.setViewpoint(new Viewpoint(imageLayer.getFullExtent()));
131+
132+
// get the comments feature table
133+
commentsTable = imageLayer.getTables().get(0);
134+
135+
// create query parameters to get features that have non-empty comments
136+
QueryParameters queryParameters = new QueryParameters();
137+
queryParameters.setWhereClause("requestid <> '' AND comments <> ''");
138+
139+
// query the comments table for features
140+
ListenableFuture<FeatureQueryResult> featureQuery = commentsTable.queryFeaturesAsync(queryParameters);
141+
featureQuery.addDoneListener(() -> {
142+
try {
143+
// add the returned features to the list view
144+
FeatureQueryResult results = featureQuery.get();
145+
for (Feature f : results) {
146+
commentsListView.getItems().addAll(f);
147+
}
148+
} catch (InterruptedException | ExecutionException ex) {
149+
new Alert(Alert.AlertType.ERROR, "Error querying comment features");
150+
}
151+
});
152+
} else {
153+
new Alert(Alert.AlertType.ERROR, imageLayer.getLoadError().getMessage()).show();
154+
}
155+
});
156+
157+
// add the mapview and controls to the stack pane
158+
stackPane.getChildren().addAll(mapView, commentsListView);
159+
StackPane.setAlignment(commentsListView, Pos.TOP_LEFT);
160+
StackPane.setMargin(commentsListView, new Insets(10, 0, 0, 10));
161+
162+
} catch (Exception e) {
163+
// on any error, display the stack trace.
164+
e.printStackTrace();
165+
}
166+
}
167+
168+
/**
169+
* Queries for spatial features related to the selected comment in the list view and shows the first result on the
170+
* map as a graphic.
171+
*/
172+
private void showRelatedRequests() {
173+
// clear any previous results
174+
graphicsOverlay.getGraphics().clear();
175+
176+
// get the selected comment feature from the list view
177+
Feature selectedCommentFeature = commentsListView.getSelectionModel().getSelectedItem();
178+
if (selectedCommentFeature != null) {
179+
180+
// get the relationships info between layers in the table
181+
ArcGISFeature feature = (ArcGISFeature) selectedCommentFeature;
182+
List<RelationshipInfo> relationshipInfos = commentsTable.getLayerInfo().getRelationshipInfos();
183+
if (!relationshipInfos.isEmpty()) {
184+
185+
// use the first relationship for the related query parameters
186+
RelationshipInfo commentsRelationshipInfo = relationshipInfos.get(0);
187+
RelatedQueryParameters relatedQueryParameters = new RelatedQueryParameters(commentsRelationshipInfo);
188+
relatedQueryParameters.setReturnGeometry(true);
189+
190+
// query the table for related features using the parameters
191+
ListenableFuture<List<RelatedFeatureQueryResult>> relatedFeaturesRequest = commentsTable
192+
.queryRelatedFeaturesAsync(feature, relatedQueryParameters);
193+
relatedFeaturesRequest.addDoneListener(() -> {
194+
try {
195+
// loop through the returned related features
196+
List<RelatedFeatureQueryResult> results = relatedFeaturesRequest.get();
197+
if (!results.isEmpty()) {
198+
RelatedFeatureQueryResult relatedResult = results.get(0);
199+
if (relatedResult.iterator().hasNext()) {
200+
// get the first related feature
201+
ArcGISFeature relatedFeature = (ArcGISFeature) relatedResult.iterator().next();
202+
// load the feature and get its geometry to show as a graphic on the map
203+
relatedFeature.loadAsync();
204+
relatedFeature.addDoneLoadingListener(() -> {
205+
if (relatedFeature.getLoadStatus() == LoadStatus.LOADED) {
206+
Point point = (Point) relatedFeature.getGeometry();
207+
Graphic graphic = new Graphic(point);
208+
graphicsOverlay.getGraphics().add(graphic);
209+
// zoom to the graphic
210+
mapView.setViewpointCenterAsync(point, 40000);
211+
}
212+
});
213+
}
214+
} else {
215+
new Alert(Alert.AlertType.INFORMATION, "No related features found").show();
216+
}
217+
} catch (InterruptedException | ExecutionException ex) {
218+
new Alert(Alert.AlertType.ERROR, "Failed to query relationships").show();
219+
}
220+
});
221+
}
222+
}
223+
224+
}
225+
226+
@Override
227+
public void stop() {
228+
229+
// releases resources when the application closes
230+
if (mapView != null) {
231+
mapView.dispose();
232+
}
233+
}
234+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<h1>Map Image Layer Tables</h1>
2+
3+
<p>This sample demonstrates how to get a non-spatial table from an ArcGIS map image layer. It shows how to query such a table, as well as how to find related features in another table.</p>
4+
5+
<p>The non-spatial tables contained by a map service may contain additional information about sublayer features. Such information can be accessed by traversing table relationships defined in the service.</p>
6+
7+
<p><img src="MapImageLayerTables.png"></a></p>
8+
9+
<h2>How to use the sample</h2>
10+
11+
<p>Once the map image layer loads, a list view will be populated with comment data from non-spatial features. Click on
12+
one of the comments to query related spatial features and display the first result on the map.</p>
13+
14+
<h2>How it works</h2>
15+
16+
<p>To query a map image layer's tables and find related features:</p>
17+
18+
<ol>
19+
<li>Create an <code>ArcGISMapImageLayer</code> with the URL of a map image service.</li>
20+
<li>Load the layer and get one of it's tables with <code>imageLayer.getTables().get(index)</code>.</li>
21+
<li>To query the table, create <code>QueryParameters</code>. You can use <code>queryParameters.setWhereClause
22+
(sqlQuery)</code> to filter the features returned. Use <code>table.queryFeaturesAsync(parameters)</code> to get a
23+
<code>FeatureQueryResult</code>.</li>
24+
<li>The <code>FeatureQueryResult</code> is an iterable, so simply loop through it to get each result
25+
<code>Feature</code>.</li>
26+
<li>To query for related features, get the table's relationship info with <code>table.getLayerInfo()
27+
.getRelationshipInfos()</code>. This returns a list of <code>RelationshipInfo</code>s. Choose which one to
28+
base your query on.</li>
29+
<li>Now create <code>RelatedQueryParameters</code> passing in the <code>RelationshipInfo</code>. To query
30+
related features use <code>table.queryRelatedFeaturesAsync(feature, relatedQueryParameters)</code>.</li>
31+
<li>This returns a list of <code>RelatedFeatureQueryResult</code>s, each containing a set of related
32+
features</code>.</li>
33+
</ol>
34+
35+
<h2>Features</h2>
36+
37+
<ul>
38+
<li>ArcGISFeature</li>
39+
<li>ArcGISMapImageLayer</li>
40+
<li>Feature</li>
41+
<li>FeatureQueryResult</li>
42+
<li>QueryParameters</li>
43+
<li>RelatedFeatureQueryResult</li>
44+
<li>RelatedQueryParameters</li>
45+
<li>RelationshipInfo</li>
46+
<li>ServiceFeatureTable</li>
47+
</ul>
48+
49+
<h2>Additional information</h2>
50+
51+
<p>You can use <code>ArcGISMapImageLayer.LoadTablesAndLayersAsync()</code> to recursively load all sublayers and tables
52+
associated with a map image layer.</p>

0 commit comments

Comments
 (0)