问题
I have successfully been able to filter, for instance shakemaps, by attribute id - I have successfully achieved this multiple ways - but all ending with the same problem.
1.) with the where filter 2.) definition expression 3.) iterating through all attribute ids and bringing them back.
The problem: All exists for only allowing/displaying one per attribute id
at a time.. my goal is to feed the attribute ids
into a checkbox list (which I have done), but allowing for items via attribute id to be added to the map as they are checked, collectively, one at a time - currently I can not seem to get this to work with the aspect of having multiple or more then one appear at a time on the map.
1.) i.e. the below filter (attempted logic 1) & CodePen:
.....
function filterByID(event) {
const selectedID = event.target.getAttribute("data-id");
eqLayerView.filter = {
where: "id = '" + selectedID + "'"
};
}
view.whenLayerView(fl)
.then(function(layerView) {
eqLayerView = layerView;
eqLayerView.filter = {
where: "id = ''"
};
.............
2.) i.e. another attempted logic (adding multiple at a time here, line by line, or via array):
layer.definitionExpression = "id = 'us70008jr5'",
layer.definitionExpression = "id = 'cgi988jr52'",
3.) i.e. 3rd attempt with a suggestion here on GIS exchange: https://gis.stackexchange.com/questions/364578/loop-through-attribute-ids-of-featurelayer
layer
.load()
.then(() => {
// create a query from the layer
const query = layer.createQuery();
query.returnDistinctValues = true;
query.where = "grid_value > 2"; // or 1=1 if you need them all
// the field you want distinct values for
query.outFields = ["id"];
return layer.queryFeatures(query);
})
.then(({ features }) => {
// extract the ids to a list
const ids = features.map(({ attributes }) => attributes.id);
return ids;
})
.then((ids) => {
// You can store them how you want, in this case,
// I put them in a dropdown select menu
const fragment = document.createDocumentFragment();
ids.forEach((id) => {
const option = document.createElement('option');
option.value = id;
option.innerText = id;
fragment.appendChild(option);
});
list.appendChild(fragment);
map.add(layer);
});
All attempted logic above result in the toggling of a shakemap by attribute id
to be displayed only one at a time — by toggling a new on, the previous turns off, I need the ability to have multiple being able to exist on the map at once.
ArcGIS - javascript - 4.15
回答1:
I am pretty sure I answer this question a couple of weeks ago, but I can't find my answer so maybe I just thought I did, in that case sorry about that.
Anyway, with a couple of fixes your code should work. The main issue here I think is that your query is not correct if you are going to use checkboxs. You need to use a set query like IN
. I would be fine if you use radio buttons.
Here you have your example with the fixes I mention,
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<title>Filter features by attribute - 4.15</title>
<link rel='stylesheet' href='https://js.arcgis.com/4.15/esri/themes/light/main.css' />
<script src='https://js.arcgis.com/4.15/'></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 500px;
width: 100%;
}
</style>
<script>
require([
'esri/views/MapView',
'esri/Map',
'esri/layers/FeatureLayer',
'esri/widgets/Expand'
], function (MapView, Map, FeatureLayer, Expand) {
const layer = new FeatureLayer({
url: 'https://services9.arcgis.com/RHVPKKiFTONKtxq3/arcgis/rest/services/USGS_Seismic_Data_v1/FeatureServer/1/',
outFields: ['*']
, definitionExpression: 'eventTime >= CURRENT_TIMESTAMP - 30 AND grid_value > 2'
});
const map = new Map({
basemap: 'gray-vector'
, layers: [layer]
});
const view = new MapView({
map: map,
container: 'viewDiv',
center: [-98, 40],
zoom: 4
});
let eqLayerView;
let selectedIDs = {};
function updatedFilter() {
const ids = [];
for(const [key, value] of Object.entries(selectedIDs)) {
if (value) {
ids.push(`'${key}'`);
}
}
eqLayerView.filter = {
where: `id IN (${ids.join(',')})`
};
console.log(`[updateFilter] ${eqLayerView.filter.where}`);
}
const idElement = document.getElementById('id-filter');
idElement.addEventListener('click', filterByID);
function filterByID(event) {
const chk = event.target;
console.log(`[filterByID] ${chk.getAttribute('data-id')} ${chk.checked}`);
selectedIDs[chk.getAttribute('data-id')] = chk.checked;
updatedFilter();
}
view.whenLayerView(layer).then(function (layerView) {
eqLayerView = layerView;
updatedFilter();
var query = layer.createQuery();
query.outFields = ['id'];
query.returnDistinctValues = true;
query.returnGeometry = false;
layer.queryFeatures(query).then(function (results) {
results.features.map(function (feat) {
let id = feat.attributes['id'];
let opt = document.createElement('input');
opt.type = 'checkbox';
let label = document.createElement('label')
label.innerHTML = id;
opt.className = 'id-item visible-id';
opt.setAttribute('data-id', id);
idElement.appendChild(opt);
idElement.appendChild(label);
selectedIDs[id] = false;
});
});
});
});
</script>
</head>
<body>
<div id='id-filter' class='esri-widget'>
</div>
<div id='viewDiv'></div>
</body>
</html>
BTW, I added some logs for you to see what I consider import info of the events.
Last thing, I use an auxiliary dictionary to keep track of the visible features to filter. Another way to do it would simply to query all the checkbox and add the id
to the filter if it is checked
.
来源:https://stackoverflow.com/questions/62502845/add-items-to-map-collectively-one-at-a-time-per-attribute-id