I am using client-side feature queries which are useful in situations where the application should deliver immediate results in response to user input. With queries on the LayerView there is no round-trip to the server. Users can draw a polygon, polyline or point geometry which is then used as the spatial geometry parameter in the query.
Before running the query on the the SceneLayerView we define what statistics we want to receive on the matching features. This is achieved assigning a StatisticDefinition array to outStatistics and calling queryFeatures on the SceneLayerView. Below is my approach to achieve this , I am looking for other approaches to do the same.
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<title>
SceneLayerView - query statistics by geometry | Sample | ArcGIS API for
JavaScript 4.21
</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
.esri-ui-top-right {
max-height: 100%;
}
#queryDiv,
#resultDiv {
min-width: 250px;
font-size: 14px;
padding: 10px;
display: none;
overflow-y: auto;
overflow-x: hidden;
}
.geometry-options {
display: flex;
flex-direction: row;
}
.geometry-button {
flex: 1;
border-style: solid;
border-width: 1px;
border-image: none;
}
.geometry-button-selected {
background: #4c4c4c;
color: #fff;
}
#bufferNum {
width: 90%;
margin: 2.5em auto 0;
}
.count {
white-space: nowrap;
font-size: 14px;
font-weight: bold;
display: inline-block;
}
</style>
<!-- Load the Chart.js library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<link
rel="stylesheet"
href="https://js.arcgis.com/4.21/esri/themes/light/main.css"
/>
<script src="https://js.arcgis.com/4.21/"></script>
<script>
require([
"esri/WebScene",
"esri/views/SceneView",
"esri/layers/GraphicsLayer",
"esri/widgets/Sketch/SketchViewModel",
"esri/widgets/Slider",
"esri/geometry/geometryEngine",
"esri/Graphic",
"esri/core/promiseUtils"
], (
WebScene,
SceneView,
GraphicsLayer,
SketchViewModel,
Slider,
geometryEngine,
Graphic,
promiseUtils
) => {
// Load webscene and display it in a SceneView
const webscene = new WebScene({
portalItem: {
id: "fb5948b2bb76439792786000b942e5b7"
}
});
// create the SceneView
const view = new SceneView({
container: "viewDiv",
map: webscene
});
window.view = view;
// add a GraphicsLayer for the sketches and the buffer
const sketchLayer = new GraphicsLayer();
const bufferLayer = new GraphicsLayer();
view.map.addMany([bufferLayer, sketchLayer]);
let sceneLayer = null;
let sceneLayerView = null;
let bufferSize = 0;
// Assign scene layer once webscene is loaded and initialize UI
webscene.load().then(() => {
sceneLayer = webscene.layers.find((layer) => {
return layer.title === "Helsinki textured buildings";
});
sceneLayer.outFields = ["buildingMaterial", "yearCompleted"];
view.whenLayerView(sceneLayer).then((layerView) => {
sceneLayerView = layerView;
queryDiv.style.display = "block";
});
});
view.ui.add([queryDiv], "bottom-left");
view.ui.add([resultDiv], "top-right");
// use SketchViewModel to draw polygons that are used as a query
let sketchGeometry = null;
const sketchViewModel = new SketchViewModel({
layer: sketchLayer,
defaultUpdateOptions: {
tool: "reshape",
toggleToolOnClick: false
},
view: view,
defaultCreateOptions: { hasZ: false }
});
sketchViewModel.on("create", (event) => {
if (event.state === "complete") {
sketchGeometry = event.graphic.geometry;
runQuery();
}
});
sketchViewModel.on("update", (event) => {
if (event.state === "complete") {
sketchGeometry = event.graphics[0].geometry;
runQuery();
}
});
// draw geometry buttons - use the selected geometry to sktech
const pointBtn = document.getElementById("point-geometry-button");
const lineBtn = document.getElementById("line-geometry-button");
const polygonBtn = document.getElementById("polygon-geometry-button");
pointBtn.addEventListener("click", geometryButtonsClickHandler);
lineBtn.addEventListener("click", geometryButtonsClickHandler);
polygonBtn.addEventListener("click", geometryButtonsClickHandler);
function geometryButtonsClickHandler(event) {
const geometryType = event.target.value;
clearGeometry();
sketchViewModel.create(geometryType);
}
const bufferNumSlider = new Slider({
container: "bufferNum",
min: 0,
max: 500,
steps: 1,
visibleElements: {
labels: true
},
precision: 0,
labelFormatFunction: (value, type) => {
return `${value.toString()}m`;
},
values: [0]
});
// get user entered values for buffer
bufferNumSlider.on(
["thumb-change", "thumb-drag"],
bufferVariablesChanged
);
function bufferVariablesChanged(event) {
bufferSize = event.value;
runQuery();
}
// Clear the geometry and set the default renderer
const clearGeometryBtn = document.getElementById("clearGeometry");
clearGeometryBtn.addEventListener("click", clearGeometry);
// Clear the geometry and set the default renderer
function clearGeometry() {
sketchGeometry = null;
sketchViewModel.cancel();
sketchLayer.removeAll();
bufferLayer.removeAll();
clearHighlighting();
clearCharts();
resultDiv.style.display = "none";
}
// set the geometry query on the visible SceneLayerView
const debouncedRunQuery = promiseUtils.debounce(() => {
if (!sketchGeometry) {
return;
}
resultDiv.style.display = "block";
updateBufferGraphic(bufferSize);
return promiseUtils.eachAlways([
queryStatistics(),
updateSceneLayer()
]);
});
function runQuery() {
debouncedRunQuery().catch((error) => {
if (error.name === "AbortError") {
return;
}
console.error(error);
});
}
// Set the renderer with objectIds
let highlightHandle = null;
function clearHighlighting() {
if (highlightHandle) {
highlightHandle.remove();
highlightHandle = null;
}
}
function highlightBuildings(objectIds) {
// Remove any previous highlighting
clearHighlighting();
const objectIdField = sceneLayer.objectIdField;
document.getElementById("count").innerHTML = objectIds.length;
highlightHandle = sceneLayerView.highlight(objectIds);
}
// update the graphic with buffer
function updateBufferGraphic(buffer) {
// add a polygon graphic for the buffer
if (buffer > 0) {
const bufferGeometry = geometryEngine.geodesicBuffer(
sketchGeometry,
buffer,
"meters"
);
if (bufferLayer.graphics.length === 0) {
bufferLayer.add(
new Graphic({
geometry: bufferGeometry,
symbol: sketchViewModel.polygonSymbol
})
);
} else {
bufferLayer.graphics.getItemAt(0).geometry = bufferGeometry;
}
} else {
bufferLayer.removeAll();
}
}
function updateSceneLayer() {
const query = sceneLayerView.createQuery();
query.geometry = sketchGeometry;
query.distance = bufferSize;
return sceneLayerView.queryObjectIds(query).then(highlightBuildings);
}
let yearChart = null;
let materialChart = null;
function queryStatistics() {
const statDefinitions = [
{
onStatisticField:
"CASE WHEN buildingMaterial = 'concrete or lightweight concrete' THEN 1 ELSE 0 END",
outStatisticFieldName: "material_concrete",
statisticType: "sum"
},
{
onStatisticField:
"CASE WHEN buildingMaterial = 'brick' THEN 1 ELSE 0 END",
outStatisticFieldName: "material_brick",
statisticType: "sum"
},
{
onStatisticField:
"CASE WHEN buildingMaterial = 'wood' THEN 1 ELSE 0 END",
outStatisticFieldName: "material_wood",
statisticType: "sum"
},
{
onStatisticField:
"CASE WHEN buildingMaterial = 'steel' THEN 1 ELSE 0 END",
outStatisticFieldName: "material_steel",
statisticType: "sum"
},
{
onStatisticField:
"CASE WHEN buildingMaterial IN ('concrete or lightweight concrete', 'brick', 'wood', 'steel') THEN 0 ELSE 1 END",
outStatisticFieldName: "material_other",
statisticType: "sum"
},
{
onStatisticField:
"CASE WHEN (yearCompleted >= '1850' AND yearCompleted <= '1899') THEN 1 ELSE 0 END",
outStatisticFieldName: "year_1850",
statisticType: "sum"
},
{
onStatisticField:
"CASE WHEN (yearCompleted >= '1900' AND yearCompleted <= '1924') THEN 1 ELSE 0 END",
outStatisticFieldName: "year_1900",
statisticType: "sum"
},
{
onStatisticField:
"CASE WHEN (yearCompleted >= '1925' AND yearCompleted <= '1949') THEN 1 ELSE 0 END",
outStatisticFieldName: "year_1925",
statisticType: "sum"
},
{
onStatisticField:
"CASE WHEN (yearCompleted >= '1950' AND yearCompleted <= '1974') THEN 1 ELSE 0 END",
outStatisticFieldName: "year_1950",
statisticType: "sum"
},
{
onStatisticField:
"CASE WHEN (yearCompleted >= '1975' AND yearCompleted <= '1999') THEN 1 ELSE 0 END",
outStatisticFieldName: "year_1975",
statisticType: "sum"
},
{
onStatisticField:
"CASE WHEN (yearCompleted >= '2000' AND yearCompleted <= '2015') THEN 1 ELSE 0 END",
outStatisticFieldName: "year_2000",
statisticType: "sum"
}
];
const query = sceneLayerView.createQuery();
query.geometry = sketchGeometry;
query.distance = bufferSize;
query.outStatistics = statDefinitions;
return sceneLayerView.queryFeatures(query).then((result) => {
const allStats = result.features[0].attributes;
updateChart(materialChart, [
allStats.material_concrete,
allStats.material_brick,
allStats.material_wood,
allStats.material_steel,
allStats.material_other
]);
updateChart(yearChart, [
allStats.year_1850,
allStats.year_1900,
allStats.year_1925,
allStats.year_1950,
allStats.year_1975,
allStats.year_2000
]);
}, console.error);
}
// Updates the given chart with new data
function updateChart(chart, dataValues) {
chart.data.datasets[0].data = dataValues;
chart.update();
}
function createYearChart() {
const yearCanvas = document.getElementById("year-chart");
yearChart = new Chart(yearCanvas.getContext("2d"), {
type: "horizontalBar",
data: {
labels: [
"1850-1899",
"1900-1924",
"1925-1949",
"1950-1974",
"1975-1999",
"2000-2015"
],
datasets: [
{
label: "Build year",
backgroundColor: "#149dcf",
stack: "Stack 0",
data: [0, 0, 0, 0, 0, 0]
}
]
},
options: {
responsive: false,
legend: {
display: false
},
title: {
display: true,
text: "Build year"
},
scales: {
xAxes: [
{
stacked: true,
ticks: {
beginAtZero: true,
precision: 0
}
}
],
yAxes: [
{
stacked: true
}
]
}
}
});
}
function createMaterialChart() {
const materialCanvas = document.getElementById("material-chart");
materialChart = new Chart(materialCanvas.getContext("2d"), {
type: "doughnut",
data: {
labels: ["Concrete", "Brick", "Wood", "Steel", "Other"],
datasets: [
{
backgroundColor: [
"#FD7F6F",
"#7EB0D5",
"#B2E061",
"#BD7EBE",
"#FFB55A"
],
borderWidth: 0,
data: [0, 0, 0, 0, 0]
}
]
},
options: {
responsive: false,
cutoutPercentage: 35,
legend: {
position: "bottom"
},
title: {
display: true,
text: "Building Material"
}
}
});
}
function clearCharts() {
updateChart(materialChart, [0, 0, 0, 0, 0]);
updateChart(yearChart, [0, 0, 0, 0, 0, 0]);
document.getElementById("count").innerHTML = 0;
}
createYearChart();
createMaterialChart();
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div id="queryDiv" class="esri-widget">
<b>Query by geometry</b><br />
<br />Draw a geometry to query by:
<div class="geometry-options">
<button
class="esri-widget--button esri-icon-map-pin geometry-button"
id="point-geometry-button"
value="point"
title="Query by point"
></button>
<button
class="esri-widget--button esri-icon-polyline geometry-button"
id="line-geometry-button"
value="polyline"
title="Query by line"
></button>
<button
class="esri-widget--button esri-icon-polygon geometry-button"
id="polygon-geometry-button"
value="polygon"
title="Query by polygon"
></button>
</div>
<br />
<div class="tooltip">
<label for="bufferNum">Set a geometry buffer size:</label>
<div id="bufferNum"></div>
</div>
<br />
<button class="esri-button" id="clearGeometry" type="button">
Clear
</button>
</div>
<div id="resultDiv" class="esri-widget">
<div class="count">
Selected Buildings:
<div class="count" id="count">0</div>
</div>
<div class="charts">
<div>
<canvas id="year-chart" height="250" width="260" />
</div>
<div>
<canvas id="material-chart" width="250" height="300" />
</div>
</div>
</div>
</body>
</html>
CodePudding user response:
I am using this sample which shows how a FeatureEffect can be used to highlight features in a CSVLayerView and select the corresponding rows in a FeatureTable. A rectangle can be drawn on the view by clicking on the Select features by rectangle button and drawing a rectangle on the map.
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<link
rel="stylesheet"
href="https://js.arcgis.com/4.21/esri/themes/light/main.css"
/>
<script src="https://js.arcgis.com/4.21/"></script>
<style>
html,
body {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#viewDiv {
height: 50%;
width: 100%;
}
.container {
height: 50%;
width: 100%;
}
</style>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/CSVLayer",
"esri/layers/FeatureLayer",
"esri/layers/GraphicsLayer",
"esri/widgets/Sketch/SketchViewModel",
"esri/Graphic",
"esri/widgets/FeatureTable",
"esri/Basemap",
"esri/geometry/geometryEngineAsync"
], function (
Map,
MapView,
CSVLayer,
FeatureLayer,
GraphicsLayer,
SketchViewModel,
Graphic,
FeatureTable,
Basemap,
geometryEngineAsync
) {
// Use the states featurealayer as a basemap
const states = new FeatureLayer({
url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer/2",
renderer: {
type: "simple",
symbol: {
type: "simple-fill",
color: "#f0ebe4",
outline: {
color: "#DCDCDC",
width: "0.5px"
}
}
},
spatialReference: {
wkid: 102003
},
effect: "drop-shadow(-10px, 10px, 6px gray)"
});
// national parks csv layer
const csvLayer = new CSVLayer({
url: "https://ubatsukh.github.io/arcgis-js-api-demos/devsummit2021/csvLayer-nps/data/nps_establishments.csv",
delimiter: ",",
popupTemplate: {
title: "{unit_name}",
content: "Established on <b>{date_est}</b> <br/><br/> {description}"
},
renderer: setRenderer()
});
let csvLayerView;
csvLayer
.when(() => {
view.whenLayerView(csvLayer).then(function (layerView) {
csvLayerView = layerView;
});
})
.catch(errorCallback);
const map = new Map({
basemap: new Basemap({
baseLayers: [states]
}),
layers: [csvLayer]
});
// initialize the view with USA Contiguous Albers Equal Area Conic
// projection and set the extent to the states
const view = new MapView({
container: "viewDiv",
map: map,
extent: {
type: "extent",
spatialReference: {
wkid: 102003
},
xmax: 2275062,
xmin: -2752064,
ymax: 1676207,
ymin: -1348080
},
constraints: {
snapToZoom: false,
minScale: 50465153
},
spatialReference: {
wkid: 102003
},
background: {
color: "white"
}
});
// create a new instance of a FeatureTable
const featureTable = new FeatureTable({
view: view,
layer: csvLayer,
highlightOnRowSelectEnabled: false,
fieldConfigs: [
{
name: "unit_name",
label: "Name"
},
{
name: "state",
label: "State"
},
{
name: "region",
label: "Region"
},
{
name: "unit_type",
label: "Type"
},
{
name: "created_by",
label: "Created by"
},
{
name: "date_est",
label: "Established date"
},
{
name: "description",
label: "Description"
},
{
name: "caption",
label: "Caption"
}
],
container: document.getElementById("tableDiv")
});
// this array will keep track of selected feature objectIds to
// sync the layerview effects and feature table selection
let features = [];
// Listen for the table's selection-change event
featureTable.on("selection-change", (changes) => {
// if the feature is unselected then remove the objectId
// of the removed feature from the features array
changes.removed.forEach((item) => {
const data = features.find((data) => {
return data === item.objectId;
});
if (data) {
features.splice(features.indexOf(data), 1);
}
});
// If the selection is added, push all added selections to array
changes.added.forEach((item) => {
features.push(item.objectId);
});
// set excluded effect on the features that are not selected in the table
csvLayerView.effect = {
filter: {
objectIds: features
},
excludedEffect: "blur(5px) grayscale(90%) opacity(40%)"
};
});
// polygonGraphicsLayer will be used by the sketchviewmodel
// show the polygon being drawn on the view
const polygonGraphicsLayer = new GraphicsLayer();
map.add(polygonGraphicsLayer);
// add the select by rectangle button the view
view.ui.add("select-by-rectangle", "top-left");
const selectButton = document.getElementById("select-by-rectangle");
// click event for the select by rectangle button
selectButton.addEventListener("click", () => {
view.popup.close();
sketchViewModel.create("rectangle");
});
// add the clear selection button the view
view.ui.add("clear-selection", "top-left");
document
.getElementById("clear-selection")
.addEventListener("click", () => {
featureTable.clearSelection();
featureTable.filterGeometry = null;
polygonGraphicsLayer.removeAll();
});
// create a new sketch view model set its layer
const sketchViewModel = new SketchViewModel({
view: view,
layer: polygonGraphicsLayer
});
// Once user is done drawing a rectangle on the map
// use the rectangle to select features on the map and table
sketchViewModel.on("create", async (event) => {
if (event.state === "complete") {
// this polygon will be used to query features that intersect it
const geometries = polygonGraphicsLayer.graphics.map(function (
graphic
) {
return graphic.geometry;
});
const queryGeometry = await geometryEngineAsync.union(
geometries.toArray()
);
selectFeatures(queryGeometry);
}
});
// This function is called when user completes drawing a rectangle
// on the map. Use the rectangle to select features in the layer and table
function selectFeatures(geometry) {
if (csvLayerView) {
// create a query and set its geometry parameter to the
// rectangle that was drawn on the view
const query = {
geometry: geometry,
outFields: ["*"]
};
// query graphics from the csv layer view. Geometry set for the query
// can be polygon for point features and only intersecting geometries are returned
csvLayerView
.queryFeatures(query)
.then((results) => {
if (results.features.length === 0) {
clearSelection();
} else {
// pass in the query results to the table by calling its selectRows method.
// This will trigger FeatureTable's selection-change event
// where we will be setting the feature effect on the csv layer view
featureTable.filterGeometry = geometry;
featureTable.selectRows(results.features);
}
})
.catch(errorCallback);
}
}
function errorCallback(error) {
console.log("error happened:", error.message);
}
// this is called from CSVLayer constructor
// tree CIM symbol
function setRenderer() {
return {
type: "simple",
symbol: {
type: "cim",
data: {
type: "CIMSymbolReference",
symbol: {
type: "CIMPointSymbol",
symbolLayers: [
{
type: "CIMVectorMarker",
enable: true,
anchorPointUnits: "Relative",
dominantSizeAxis3D: "Y",
size: 15.75,
billboardMode3D: "FaceNearPlane",
frame: {
xmin: 0,
ymin: 0,
xmax: 21,
ymax: 21
},
markerGraphics: [
{
type: "CIMMarkerGraphic",
geometry: {
rings: [
[
[15, 15],
[12, 15],
[16, 10],
[13, 10],
[17, 5],
[11, 5],
[11, 2],
[10, 2],
[10, 5],
[4, 5],
[8, 10],
[5, 10],
[9, 15],
[6, 15],
[10.5, 19],
[15, 15]
]
]
},
symbol: {
type: "CIMPolygonSymbol",
symbolLayers: [
{
type: "CIMSolidStroke",
enable: true,
capStyle: "Round",
joinStyle: "Round",
lineStyle3D: "Strip",
miterLimit: 10,
width: 0,
color: [0, 0, 0, 255]
},
{
type: "CIMSolidFill",
enable: true,
color: [0, 160, 0, 255]
}
]
}
}
],
scaleSymbolsProportionally: true,
respectFrame: true
},
{
type: "CIMVectorMarker",
enable: true,
colorLocked: true,
anchorPointUnits: "Relative",
dominantSizeAxis3D: "Y",
size: 8,
billboardMode3D: "FaceNearPlane",
frame: {
xmin: -5,
ymin: -5,
xmax: 5,
ymax: 5
},
markerGraphics: [
{
type: "CIMMarkerGraphic",
geometry: {
rings: [
[
[0, 5],
[0.87, 4.92],
[1.71, 4.7],
[2.5, 4.33],
[3.21, 3.83],
[3.83, 3.21],
[4.33, 2.5],
[4.7, 1.71],
[4.92, 0.87],
[5, 0],
[4.92, -0.87],
[4.7, -1.71],
[4.33, -2.5],
[3.83, -3.21],
[3.21, -3.83],
[2.5, -4.33],
[1.71, -4.7],
[0.87, -4.92],
[0, -5],
[-0.87, -4.92],
[-1.71, -4.7],
[-2.5, -4.33],
[-3.21, -3.83],
[-3.83, -3.21],
[-4.33, -2.5],
[-4.7, -1.71],
[-4.92, -0.87],
[-5, 0],
[-4.92, 0.87],
[-4.7, 1.71],
[-4.33, 2.5],
[-3.83, 3.21],
[-3.21, 3.83],
[-2.5, 4.33],
[-1.71, 4.7],
[-0.87, 4.92],
[0, 5]
]
]
},
symbol: {
type: "CIMPolygonSymbol",
symbolLayers: [
{
type: "CIMSolidStroke",
enable: true,
capStyle: "Round",
joinStyle: "Round",
lineStyle3D: "Strip",
miterLimit: 10,
width: 0.5,
color: [167, 169, 172, 255]
},
{
type: "CIMSolidFill",
enable: true,
color: [255, 255, 255, 255]
}
]
}
}
],
scaleSymbolsProportionally: true,
respectFrame: true
}
],
haloSize: 1,
scaleX: 1,
angleAlignment: "Display"
}
}
}
};
}
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div
id="select-by-rectangle"
class="esri-widget esri-widget--button esri-widget esri-interactive"
title="Select features by rectangle"
>
<span class="esri-icon-checkbox-unchecked"></span>
</div>
<div
id="clear-selection"
class="esri-widget esri-widget--button esri-widget esri-interactive"
title="Clear selection"
>
<span class="esri-icon-erase"></span>
</div>
<div class="container">
<div id="tableDiv"></div>
</div>
</body>
</html>
CodePudding user response:
The following will be useful , if you want to query all features. It can be convenient and useful for users to zoom to the extent of all features in a FeatureLayer once an app loads, when a layer is added to the map, or when a layer's definitionExpression is updated.
The FeatureLayer API provides a method called queryExtent(), which allows you to calculate the full extent of features at runtime that satisfy a given query. If no query parameters are set, then the method queries for the extent of all features in the layer according to its definitionExpression.
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<link
rel="stylesheet"
href="https://js.arcgis.com/4.21/esri/themes/light/main.css"
/>
<script src="https://js.arcgis.com/4.21/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<script>
require([
"esri/Map",
"esri/views/SceneView",
"esri/layers/FeatureLayer",
"esri/widgets/LayerList",
"esri/core/Collection"
], (Map, SceneView, FeatureLayer, LayerList, Collection) => {
const featureLayer = new FeatureLayer({
outFields: ["STATION_NAME", "COUNTRY", "TEMP"],
portalItem: {
// autocasts as new PortalItem()
id: "3a177da3f6524d61980fb41125b2349c"
},
title: "Temperature on Jan, 4, 2017"
});
// When the layer is loaded, query for the extent
// of all features in the layer that satisfy the
// definitionExpression. Then set the view's
// extent to the returned extent of all features.
featureLayer.when(() => {
featureLayer.definitionExpression = createDefinitionExpression("");
zoomToLayer(featureLayer);
});
const map = new Map({
basemap: "dark-gray-vector",
layers: [featureLayer]
});
const view = new SceneView({
container: "viewDiv",
map: map
});
const layerList = new LayerList({
view: view,
listItemCreatedFunction: createActions
});
view.ui.add(layerList, "top-right");
// definitionExpressions used by each action
// listed in the LayerList
const expressions = new Collection([
{
id: "75 ",
expression: "TEMP > 75"
},
{
id: "50-75",
expression: "TEMP > 50 AND TEMP <=75"
},
{
id: "25-50",
expression: "TEMP > 25 AND TEMP <=50"
},
{
id: "25-",
expression: "TEMP <= 25"
},
{
id: "arctic-circle",
expression: "LATITUDE >= 66.5"
},
{
id: "north-temperate-zone",
expression: "LATITUDE < 66.5 AND LATITUDE >= 23.5"
},
{
id: "torrid-zone",
expression: "LATITUDE < 23.5 AND LATITUDE >= -23.5"
}
]);
// When an action is triggered, the definitionExpression
// is set on the layer and the view's extent updates
// to match the features visible in the layer
layerList.on("trigger-action", (event) => {
const actionId = event.action.id;
const layer = event.item.layer;
const subExpression = expressions.find((item) => {
return item.id === actionId;
}).expression;
const definitionExpression =
createDefinitionExpression(subExpression);
layer.definitionExpression = definitionExpression;
zoomToLayer(layer);
});
function createActions(event) {
const item = event.item;
item.actionsOpen = true;
item.actionsSections = [
[
{
title: "> 75°F",
className: "esri-icon-zoom-out-fixed",
id: "75 "
},
{
title: "50°-75°F",
className: "esri-icon-zoom-out-fixed",
id: "50-75"
},
{
title: "25°-50°F",
className: "esri-icon-zoom-out-fixed",
id: "25-50"
},
{
title: "< 25°F",
className: "esri-icon-zoom-out-fixed",
id: "25-"
}
],
[
{
title: "Above Arctic Circle",
className: "esri-icon-zoom-out-fixed",
id: "arctic-circle"
},
{
title: "North Temperate Zone",
className: "esri-icon-zoom-out-fixed",
id: "north-temperate-zone"
},
{
title: "Torrid Zone",
className: "esri-icon-zoom-out-fixed",
id: "torrid-zone"
}
]
];
}
// Appends a definitionExpression to a base expression
// the base expression only returns freatures in
// Canada, USA, and Mexico. It excludes some US territories
// located on the other side of the dateline
function createDefinitionExpression(subExpression) {
const baseExpression =
"( COUNTRY LIKE '%United States Of America%' OR "
"COUNTRY LIKE '