Skip to content

Commit 4f2f4e4

Browse files
authored
group layers sample (#331)
group layers sample
1 parent d3995bf commit 4f2f4e4

File tree

4 files changed

+247
-0
lines changed

4 files changed

+247
-0
lines changed
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*
2+
* Copyright 2019 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.grouplayers.group_layers;
18+
19+
import java.util.Arrays;
20+
import java.util.List;
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.TreeItem;
27+
import javafx.scene.control.TreeView;
28+
import javafx.scene.layout.StackPane;
29+
import javafx.stage.Stage;
30+
31+
import com.esri.arcgisruntime.data.ServiceFeatureTable;
32+
import com.esri.arcgisruntime.layers.ArcGISSceneLayer;
33+
import com.esri.arcgisruntime.layers.FeatureLayer;
34+
import com.esri.arcgisruntime.layers.GroupLayer;
35+
import com.esri.arcgisruntime.layers.Layer;
36+
import com.esri.arcgisruntime.loadable.LoadStatus;
37+
import com.esri.arcgisruntime.mapping.ArcGISScene;
38+
import com.esri.arcgisruntime.mapping.ArcGISTiledElevationSource;
39+
import com.esri.arcgisruntime.mapping.Basemap;
40+
import com.esri.arcgisruntime.mapping.Surface;
41+
import com.esri.arcgisruntime.mapping.view.Camera;
42+
import com.esri.arcgisruntime.mapping.view.SceneView;
43+
44+
public class GroupLayersSample extends Application {
45+
46+
private SceneView sceneView;
47+
48+
@Override
49+
public void start(Stage stage) {
50+
51+
try {
52+
53+
// set the title and size of the stage and show it
54+
StackPane stackPane = new StackPane();
55+
Scene fxScene = new Scene(stackPane);
56+
stage.setTitle("Group Layers Sample");
57+
stage.setWidth(800);
58+
stage.setHeight(700);
59+
60+
// create a JavaFX scene with a stackpane and set it to the stage
61+
stage.setScene(fxScene);
62+
stage.show();
63+
64+
// create a scene view and add it to the stack pane
65+
sceneView = new SceneView();
66+
stackPane.getChildren().add(sceneView);
67+
68+
// create a scene with a basemap and add it to the scene view
69+
ArcGISScene scene = new ArcGISScene();
70+
scene.setBasemap(Basemap.createImagery());
71+
sceneView.setArcGISScene(scene);
72+
73+
// set the base surface with world elevation
74+
Surface surface = new Surface();
75+
surface.getElevationSources().add(new ArcGISTiledElevationSource("http://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer"));
76+
scene.setBaseSurface(surface);
77+
78+
// create different types of layers
79+
ArcGISSceneLayer devOne = new ArcGISSceneLayer("https://scenesampleserverdev.arcgis.com/arcgis/rest/services/Hosted/DevA_Trees/SceneServer/layers/0");
80+
ArcGISSceneLayer devTwo = new ArcGISSceneLayer("https://scenesampleserverdev.arcgis.com/arcgis/rest/services/Hosted/DevA_Pathways/SceneServer/layers/0");
81+
ArcGISSceneLayer devThree = new ArcGISSceneLayer("https://scenesampleserverdev.arcgis.com/arcgis/rest/services/Hosted/DevA_BuildingShell_Textured/SceneServer/layers/0");
82+
ArcGISSceneLayer nonDevOne = new ArcGISSceneLayer("https://scenesampleserverdev.arcgis.com/arcgis/rest/services/Hosted/PlannedDemo_BuildingShell/SceneServer/layers/0");
83+
FeatureLayer nonDevTwo = new FeatureLayer(new ServiceFeatureTable("https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/DevelopmentProjectArea/FeatureServer/0"));
84+
85+
// create a group layer from scratch by adding the layers as children
86+
GroupLayer groupLayer = new GroupLayer();
87+
groupLayer.setName("Group: Dev A");
88+
groupLayer.getLayers().addAll(Arrays.asList(devOne, devTwo, devThree));
89+
90+
// add the group layer and other layers to the scene as operational layers
91+
scene.getOperationalLayers().addAll(Arrays.asList(groupLayer, nonDevOne, nonDevTwo));
92+
93+
// zoom to the extent of the group layer when the child layers are loaded
94+
groupLayer.getLayers().forEach(childLayer ->
95+
childLayer.addDoneLoadingListener(() -> {
96+
if (childLayer.getLoadStatus() == LoadStatus.LOADED) {
97+
sceneView.setViewpointCamera(new Camera(groupLayer.getFullExtent().getCenter(), 700, 0, 60, 0));
98+
}
99+
})
100+
);
101+
102+
// create a JavaFX tree view to show the layers in the scene
103+
TreeView<Layer> layerTreeView = new TreeView<>();
104+
layerTreeView.setMaxSize(250, 200);
105+
TreeItem<Layer> rootTreeItem = new TreeItem<>();
106+
layerTreeView.setRoot(rootTreeItem);
107+
layerTreeView.setShowRoot(false);
108+
StackPane.setAlignment(layerTreeView, Pos.TOP_RIGHT);
109+
StackPane.setMargin(layerTreeView, new Insets(10));
110+
stackPane.getChildren().add(layerTreeView);
111+
112+
// display each layer with a custom tree cell
113+
layerTreeView.setCellFactory(p -> new LayerTreeCell());
114+
115+
// recursively build the table of contents from the scene's operational layers
116+
buildLayersView(rootTreeItem, scene.getOperationalLayers());
117+
118+
} catch (Exception e) {
119+
// on any error, display the stack trace.
120+
e.printStackTrace();
121+
}
122+
}
123+
124+
/**
125+
* Recursively builds a tree from a parent tree item using a list of operational layers (including group layers).
126+
*
127+
* @param parentItem tree item to build tree from
128+
* @param operationalLayers a list of operational layers
129+
*/
130+
private void buildLayersView(TreeItem<Layer> parentItem, List<Layer> operationalLayers) {
131+
for (Layer layer : operationalLayers) {
132+
// load each layer before adding to ensure all metadata is ready for display
133+
layer.loadAsync();
134+
layer.addDoneLoadingListener(() -> {
135+
// add a tree item for the layer to the parent tree item
136+
if (layer.canShowInLegend()) {
137+
TreeItem<Layer> layerItem = new TreeItem<>(layer);
138+
layerItem.setExpanded(true);
139+
parentItem.getChildren().add(layerItem);
140+
// if the layer is a group layer, continue building with its children
141+
if (layer instanceof GroupLayer && ((GroupLayer) layer).isShowChildrenInLegend()) {
142+
buildLayersView(layerItem, ((GroupLayer) layer).getLayers());
143+
}
144+
}
145+
});
146+
}
147+
}
148+
149+
/**
150+
* Stops and releases all resources used in application.
151+
*/
152+
@Override
153+
public void stop() {
154+
155+
if (sceneView != null) {
156+
sceneView.dispose();
157+
}
158+
}
159+
160+
/**
161+
* Opens and runs application.
162+
*
163+
* @param args arguments passed to this application
164+
*/
165+
public static void main(String[] args) {
166+
167+
Application.launch(args);
168+
}
169+
170+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.esri.samples.grouplayers.group_layers;
2+
3+
import javafx.scene.control.CheckBox;
4+
import javafx.scene.control.TreeCell;
5+
6+
import com.esri.arcgisruntime.layers.Layer;
7+
8+
/**
9+
* A custom tree cell for displaying a layer in a tree view. Includes a check box for toggling the layer's visibility.
10+
*/
11+
public class LayerTreeCell extends TreeCell<Layer> {
12+
13+
@Override
14+
public void updateItem(Layer layer, boolean empty) {
15+
super.updateItem(layer, empty);
16+
if (!empty) {
17+
// use the layer's name for the text
18+
setText(layer.getName());
19+
20+
// add a check box to allow the user to change the visibility of the layer
21+
CheckBox checkBox = new CheckBox();
22+
setGraphic(checkBox);
23+
24+
// toggle the layer's visibility when the check box is toggled
25+
checkBox.setSelected(layer.isVisible());
26+
checkBox.selectedProperty().addListener(e -> layer.setVisible(checkBox.isSelected()));
27+
} else {
28+
setText(null);
29+
setGraphic(null);
30+
}
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<h1>Group layers</h1>
2+
3+
<p>Group a collection of layers together and toggle their visibility as a group.</p>
4+
5+
<p><img src="GroupLayers.png"/></p>
6+
7+
<h2>Use case</h2>
8+
9+
<p>Group layers communicate to the user that layers are related and can be managed together.</p>
10+
11+
<p>In a land development project, you might group layers according to the phase of development.</p>
12+
13+
<h2>How to use the sample</h2>
14+
15+
<p>The layers in the map will be displayed in a table of contents. Toggle the checkbox next to a layer's name to change its visibility.</p>
16+
17+
<h2>How it works</h2>
18+
19+
<ol>
20+
<li>Create an empty <code>GroupLayer</code>.</li>
21+
22+
<li>Add a child layer to the group layer's layers collection.</li>
23+
24+
<li>To toggle the visibility of the group, simply change the group layer's visibility property.</li>
25+
</ol>
26+
27+
<h2>Relevant API</h2>
28+
29+
<ul>
30+
<li>GroupLayer</li>
31+
</ul>
32+
33+
<h2>Additional information</h2>
34+
35+
<p>The full extent of a group layer may change when child layers are added/removed. Group layers do not have a spatial reference, but the full extent will have the spatial reference of the first child layer.</p>
36+
37+
<p>Group layers can be saved to web scenes. In web maps, group layers will be flattened in the web map's operational layers.</p>
38+
39+
<p>The implementation shown here makes use of a custom tree cell for displaying layers in a tree view. In the custom
40+
tree cell, toggling the checkbox of the group layer cell does not also toggle the child cell's checkbox. If you
41+
desire this behavior, use or extend JavaFX's <code>CheckBoxTreeCell</code> and <code>CheckBoxTreeItem</code>.
42+
43+
<h2 id="tags">Tags</h2>
44+
45+
<p>Layers, group layer</p>

0 commit comments

Comments
 (0)