Hi, I had an idea of hacking the lack of 3D time enabling in the time widget, by using the 2D time enabled layer and filter on intersect to the 3D models.
The example doesn’t really let me understand how to split it a part for the use of own layers:
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<title>Filter features by geometry with SceneLayer - 4.14</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#infoDiv {
background-color: white;
padding: 10px;
width: 260px;
margin: 5px;
position: absolute;
bottom: 15px;
right: 10px;
font-size: 14px;
display: none;
}
.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;
}
.options {
max-width: 260px;
width: 100%;
height: 25px;
}
#bufferNum {
width: 90%;
margin: 2.5em auto 0;
}
</style>
<link
rel="stylesheet"
href="https://js.arcgis.com/4.14/esri/themes/light/main.css"
/>
<script src="https://js.arcgis.com/4.14/"></script>
<script>
require([
"esri/WebScene",
"esri/views/SceneView",
"esri/layers/GraphicsLayer",
"esri/widgets/Sketch/SketchViewModel",
"esri/widgets/Slider",
"esri/views/layers/support/FeatureFilter",
"esri/geometry/geometryEngine",
"esri/Graphic"
], function(
WebScene,
SceneView,
GraphicsLayer,
SketchViewModel,
Slider,
FeatureFilter,
geometryEngine,
Graphic
) {
// Load webscene and display it in a SceneView
const webscene = new WebScene({
portalItem: {
id: "47241277f5c249d6b1c13840192a7cb0"
}
});
// create the SceneView
const view = new SceneView({
container: "viewDiv",
map: webscene
});
// add a GraphicsLayer for the sketches and the buffer
let sketchLayer = new GraphicsLayer();
let bufferLayer = new GraphicsLayer();
view.map.addMany([bufferLayer, sketchLayer]);
// create the layerView's to add the filter
let sceneLayerView = null;
let featureLayerView = null;
view.map.load().then(function() {
// loop through webmap's operational layers
view.map.layers.forEach(function(layer, index) {
view
.whenLayerView(layer)
.then(function(layerView) {
if (layer.type === "feature") {
featureLayerView = layerView;
}
if (layer.type === "scene") {
sceneLayerView = layerView;
}
})
.catch(console.error);
});
});
const bufferNumSlider = new Slider({
container: "bufferNum",
min: 0,
max: 1000,
steps: 1,
labelsVisible: true,
precision: 0,
labelFormatFunction: function(value, type) {
return value.toString() + "m";
},
values: [0]
});
let bufferSize = 0;
bufferNumSlider.on(
["thumb-change", "thumb-drag"],
bufferVariablesChanged
);
function bufferVariablesChanged(event) {
bufferSize = event.value;
updateFilter();
}
// use SketchViewModel to draw polygons that are used as a filter
let sketchGeometry = null;
const sketchViewModel = new SketchViewModel({
layer: sketchLayer,
view: view,
pointSymbol: {
type: "simple-marker",
style: "circle",
size: 10,
color: [255, 255, 255, 0.8],
outline: {
color: [211, 132, 80, 0.7],
size: 10
}
},
polylineSymbol: {
type: "simple-line",
color: [211, 132, 80, 0.7],
width: 6
},
polygonSymbol: {
type: "polygon-3d",
symbolLayers: [
{
type: "fill",
material: {
color: [255, 255, 255, 0.8]
},
outline: {
color: [211, 132, 80, 0.7],
size: "10px"
}
}
]
}
});
sketchViewModel.on(["create"], function(event) {
// update the filter every time the user finishes drawing the filtergeometry
if (event.state == "complete") {
sketchGeometry = event.graphic.geometry;
updateFilter();
}
});
sketchViewModel.on(["update"], function(event) {
const eventInfo = event.toolEventInfo;
// update the filter every time the user moves the filtergeometry
if (eventInfo && eventInfo.type.includes("move")) {
if (eventInfo.type === "move-stop") {
sketchGeometry = event.graphics[0].geometry;
updateFilter();
}
}
// update the filter every time the user changes the vertices of the filtergeometry
if (eventInfo && eventInfo.type.includes("reshape")) {
if (eventInfo.type === "reshape-stop") {
sketchGeometry = event.graphics[0].geometry;
updateFilter();
}
}
});
// select the layer to filter on
let featureLayerViewFilterSelected = true;
document
.getElementById("featureLayerViewFilter")
.addEventListener("change", function(ev) {
featureLayerViewFilterSelected = !!ev.target.checked;
updateFilter();
});
let sceneLayerViewFilterSelected = true;
document
.getElementById("sceneLayerViewFilter")
.addEventListener("change", function(ev) {
sceneLayerViewFilterSelected = !!ev.target.checked;
updateFilter();
});
// draw geometry buttons - use the selected geometry to sktech
document.getElementById(
"point-geometry-button"
).onclick = geometryButtonsClickHandler;
document.getElementById(
"line-geometry-button"
).onclick = geometryButtonsClickHandler;
document.getElementById(
"polygon-geometry-button"
).onclick = geometryButtonsClickHandler;
function geometryButtonsClickHandler(event) {
const geometryType = event.target.value;
clearFilter();
sketchViewModel.create(geometryType);
}
// get the selected spatialRelationship
let selectedFilter = "disjoint";
document
.getElementById("relationship-select")
.addEventListener("change", function(event) {
var select = event.target;
selectedFilter = select.options[select.selectedIndex].value;
updateFilter();
});
// remove the filter
document
.getElementById("clearFilter")
.addEventListener("click", function() {
clearFilter();
});
function clearFilter() {
sketchGeometry = null;
filterGeometry = null;
sketchLayer.removeAll();
bufferLayer.removeAll();
sceneLayerView.filter = null;
featureLayerView.filter = null;
}
// set the geometry filter on the visible FeatureLayerView
function updateFilter() {
updateFilterGeometry();
featureFilter = {
// autocasts to FeatureFilter
geometry: filterGeometry,
spatialRelationship: selectedFilter
};
if (featureLayerView) {
if (featureLayerViewFilterSelected) {
featureLayerView.filter = featureFilter;
} else {
featureLayerView.filter = null;
}
}
if (sceneLayerView) {
if (sceneLayerViewFilterSelected) {
sceneLayerView.filter = featureFilter;
} else {
sceneLayerView.filter = null;
}
}
}
// update the filter geometry depending on bufferSize
let filterGeometry = null;
function updateFilterGeometry() {
// add a polygon graphic for the bufferSize
if (sketchGeometry) {
if (bufferSize > 0) {
var bufferGeometry = geometryEngine.geodesicBuffer(
sketchGeometry,
bufferSize,
"meters"
);
if (bufferLayer.graphics.length === 0) {
bufferLayer.add(
new Graphic({
geometry: bufferGeometry,
symbol: sketchViewModel.polygonSymbol
})
);
} else {
bufferLayer.graphics.getItemAt(0).geometry = bufferGeometry;
}
filterGeometry = bufferGeometry;
} else {
bufferLayer.removeAll();
filterGeometry = sketchGeometry;
}
}
}
document.getElementById("infoDiv").style.display = "block";
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div id="infoDiv" class="esri-widget">
<b>Filter by geometry</b><br /><br />
Select the layers to filter on:<br />
<input id="sceneLayerViewFilter" type="checkbox" checked />
Buildings<br />
<input id="featureLayerViewFilter" type="checkbox" checked /> Trees<br />
<br />Draw a geometry to filter by:
<div class="geometry-options">
<button
class="esri-widget--button esri-icon-map-pin geometry-button"
id="point-geometry-button"
value="point"
title="Filter by point"
></button>
<button
class="esri-widget--button esri-icon-polyline geometry-button"
id="line-geometry-button"
value="polyline"
title="Filter by line"
></button>
<button
class="esri-widget--button esri-icon-polygon geometry-button"
id="polygon-geometry-button"
value="polygon"
title="Filter by polygon"
></button>
</div>
<br />
<label for="relationship-select">Spatial relationship:</label>
<select id="relationship-select" class="options">
<option value="intersects">intersects</option>
<option value="contains">contains</option>
<option value="disjoint" selected>disjoint</option> </select
><br /><br />
<label for="bufferNum">Set a geometry buffer size:</label>
<div id="bufferNum"></div>
<br /><br />
<button class="esri-button" id="clearFilter" type="button">
Clear filter
</button>
</div>
</body>
</html>