Method 1: Trying to select the points within a buffer of 1 mile (circle drawn by user input).
The geometry is saved in buffergeometries variable and the points layer is queried based on the geometry. But all the points in the points layer is selected. Trying to select only the points inside the buffer, any help is appreciated.
Tried other methods such as converting the graphic to feature layer, with the data source created. Query the object id and use contain, intersect but nothing worked.
Thanks in advance. This is done in Expereince Builder developer edition 1.9.
/** @jsx jsx */
// jimu / react
import {
AllWidgetProps,
DataSourceComponent,
FeatureLayerDataSource,
jsx,
React,
QueryResult,
styled,
} from 'jimu-core';
import { JimuMapViewComponent, JimuMapView } from 'jimu-arcgis';
import { Button, TextInput } from 'jimu-ui';
import geometryEngine from 'esri/geometry/geometryEngine';
import Point from 'esri/geometry/Point';
import Circle from 'esri/geometry/Circle';
import Geometry from 'esri/geometry/Geometry';
import Graphic from 'esri/Graphic';
import GraphicsLayer from 'esri/layers/GraphicsLayer';
import MapView from 'esri/views/MapView';
import FeatureLayer from "esri/layers/FeatureLayer";
// custom components
import TRSFormRow from './components/TRSFormRow';
// resources
import { IMConfig } from '../config';
import defaultMessages from './translations/default';
// types
interface State {
selectedBufferRows: Array<string[]>;
}
export default class Widget extends React.PureComponent<
AllWidgetProps<IMConfig>,
State
> {
private mapView: MapView;
private pointsLayer: GraphicsLayer;
private graphicsLayer: GraphicsLayer;
private gwsiSiteDataSource: FeatureLayerDataSource;
private bufferHighlightSymbol = {
type: 'simple-fill',
color: [255, 255, 0, 0.25],
outline: {
style: 'dash-dot',
color: [0, 0, 255],
width: 2,
},
};
public state: State = {
selectedBufferRows: [[]],
};
// store map view when available
onActiveViewChange = (jimuMapView: JimuMapView) => {
if (jimuMapView?.view) {
this.mapView = jimuMapView.view;
// create a graphics layer to show highlighted buffers
this.graphicsLayer = new GraphicsLayer({title: "Buffer Layer"});
this.pointsLayer = this.mapView.map.layers.items[0];
this.mapView.map.add(this.graphicsLayer, 0);
}
};
// store data source when available
onDataSourceCreated = (dataSource: FeatureLayerDataSource, name: string) => {
this[name] = dataSource;
};
// handle Buffer form element change
onBufferRowChange = (id: number, value: string[]) => {
const newSelectedBufferRows = [...this.state.selectedBufferRows];
newSelectedBufferRows[id] = value;
this.setState({ selectedBufferRows: newSelectedBufferRows });
};
clearSearchResults = () => {
this.graphicsLayer?.removeAll();
// clear gwsi selection
this.gwsiSiteDataSource?.selectRecordsByIds([], []);
};
onClear = async () => {
// reset selectons
this.clearSearchResults();
// short-circuit if no values selected
const selectedValues = this.state.selectedBufferRows.flat();
if (selectedValues.length < 1) {
return;
}
const selectedRows = this.state.selectedBufferRows;
selectedRows.forEach((selectedRow, index) => {
selectedRows[index] = [];
});
}
onSearch = async () => {
// reset selectons
this.clearSearchResults();
// short-circuit if no data sources
if (!this.gwsiSiteDataSource) {
return;
}
// short-circuit if no values selected
const selectedValues = this.state.selectedBufferRows.flat();
if (selectedValues.length < 1 || selectedValues[0].length < 3) {
alert('No ids selected');
return;
}
const selectedValue = selectedValues[0];
const selectedValuesSplit = selectedValue.split('_');
const searchId = selectedValuesSplit[0];
const bufferDistance = selectedValuesSplit[1];
const distanceUnits = selectedValuesSplit[2];
const where = `SITE_ID = '${searchId}' OR LOCAL_ID = '${searchId}'`
// query for siteId/localId geometries from gwsisites featue layer gave one result
const gwsiSitePointQueryResult: QueryResult = await this.gwsiSiteDataSource.query({
where,
returnGeometry: true,
});
let pointGeometry: Point;
const gwsiPointGeometries = gwsiSitePointQueryResult.records.map((record) =>
{ pointGeometry = record.getGeometry(); return pointGeometry;}
);
let selectedBufferGeometry;
const bufferGeometries = gwsiPointGeometries.map(
(point) => {
selectedBufferGeometry = geometryEngine.buffer(point, 1, "miles");
return selectedBufferGeometry;
});
/*(point) => new Circle({
center: point,
geodesic: false,
z: null,
//numberOfPoints: 100,
radius: 1,
radiusUnit: "miles"
}));*/
// select/display buffer features
const bufferGraphics = bufferGeometries.map(
(bufferGeometry) =>
new Graphic({
geometry: bufferGeometry,
symbol: this.bufferHighlightSymbol,
})
);
this.graphicsLayer?.addMany(bufferGraphics);
// zoom to buffers
const extent = geometryEngine.union(bufferGeometries).extent;
this.mapView?.goTo(extent);
debugger
// query for gwsi site ids
const gwsiSiteQueryResult: QueryResult[] = await Promise.all(
bufferGeometries.map((geometry) =>
this.gwsiSiteDataSource.query({
geometry
//spatialRel: "contains"
})
)
);
//uses datasource query to query for points in req distance from given point
/*const gwsiSiteQueryResult: QueryResult[] = await Promise.all(
gwsiPointGeometries.map((point) =>
this.gwsiSiteDataSource.query({
geometry: point,
distance: 1,
units: "miles",
//spatialRel: "contains"
}),
),
);*/
const gwsiSiteRecords = gwsiSiteQueryResult
.map((result) => result.records).flat();
const gwsiSiteIds = gwsiSiteRecords.map((record) => record.getId());
//try 2: using buffer and feature layer
/*const bufferFeaturesForFL = bufferGraphics.map(
(bufferGraphic) =>{
return {
graphic: bufferGraphic,
attributes: {
ObjectID: 1
}
};
}
);*/
/*const bufferLayer = new FeatureLayer({
source: bufferFeaturesForFL, // autocast as a Collection of new Graphic()
objectIdField: "ObjectID",
fields:[{
name:"OBJECTID",
type:"oid"
}]
});*/
/*const bufferFLGeometries = bufferLayer.graphics.map(function(graphic){
return graphic.geometry
});*/
/*let query = bufferLayer.createQuery();
query.geometry = pointGeometry; // the point location of the pointer
query.distance = 1;
query.units = "miles";
query.spatialRelationship = "intersects"; // this is the default
query.returnGeometry = true;
this.graphicsLayer.queryFeatures(query)
.then(function(response){
// returns a feature set with features containing the
// POPULATION attribute and each feature's geometry
});*/
/*2 const gwsiSiteQueryResult: QueryResult[] = await Promise.all(
bufferGeometries.map((geometry) =>
this.gwsiSiteDataSource.query({
geometry: geometry,
spatialRelationship: "contains"
}),
),
);
const gwsiSiteRecords = gwsiSiteQueryResult
.map((result) => result.records)
.flat();
const gwsiSiteIds = gwsiSiteRecords
//.filter((point) => geometryEngine.contains(circle, point))
.map((record) => record.getId());
*/
// select gwsi site features
this.gwsiSiteDataSource.selectRecordsByIds(gwsiSiteIds, gwsiSiteRecords);
alert(
`onSearch: ${where} - ${bufferGeometries.length} - sections, ${gwsiSiteIds.length} gwsi sites`,
);
//debugger
//query all points-gets 2000 records
/*const gwsiSiteQueryResult: QueryResult[] = await Promise.all(
bufferGeometries.map((geometry) =>
this.gwsiSiteDataSource.query({
})
)
);*/
/*query all points and filter - error
const gwsiSiteQueryResult: QueryResult[] = await Promise.all(
this.gwsiSiteDataSource.query({})
//.records
//.filter((point) => geometryEngine.contains(circle, point)
//).flat()
);*/
/* from TRS // query for section geometries
const sectionQueryResult: QueryResult = await this.sectionDataSource.query({
where, returnGeometry: true, });
const sectionGeometries = sectionQueryResult.records.map((record) =>
record.getGeometry()
);// query for gwsi site ids
const gwsiSiteQueryResult: QueryResult[] = await Promise.all(
sectionGeometries.map((geometry) =>
this.gwsiSiteDataSource.query({
geometry,
}), ), );
const gwsiSiteRecords = gwsiSiteQueryResult
.map((result) => result.records).flat();
const gwsiSiteIds = gwsiSiteRecords.map((record) => record.getId());
// select gwsi site features
this.gwsiSiteDataSource.selectRecordsByIds(gwsiSiteIds, gwsiSiteRecords); END TRS*/
};
render() {
const CustomDiv = styled.div`
background-color: orange;
height: 0px;
width: 0px;
`;
return (
<div className="widget-BufferSelect jimu-widget m-2">
<p>
<b>
{this.props.intl.formatMessage({
id: 'widgetLabel',
defaultMessage: defaultMessages._widgetLabel,
})}
</b>
</p>
<b>LocalId or SiteId Selection</b>
<div style={{ width: 50 }}>
<form>
<div style={{ width: 200 }}>
{this.state.selectedBufferRows.map((values, id) => (
<TRSFormRow
key={id}
values={values}
onChange={(newValues: string[]) =>
this.onBufferRowChange(id, newValues)
}
/>
))}
<Button htmlType="button" onClick={() => this.onSearch()}>
Search
</Button>
<Button htmlType="reset" onClick={() => this.onClear()}>
Clear
</Button>
</div>
</form>
</div>
{/* Retrieve map view, if configured */}
{this.props.useMapWidgetIds?.length === 1 && !this.mapView && (
<JimuMapViewComponent
useMapWidgetId={this.props.useMapWidgetIds?.[0]}
onActiveViewChange={this.onActiveViewChange}
/>
)}
{/* Retrieve data sources, if configured */}
{this.props.useDataSources?.length >= 1 && !this.gwsiSiteDataSource && (
<DataSourceComponent
useDataSource={this.props.useDataSources[0]}
widgetId={this.props.id}
onDataSourceCreated={(dataSource) =>
this.onDataSourceCreated(
dataSource as FeatureLayerDataSource,
'gwsiSiteDataSource',
)
}
/>
)}
</div>
);
}
}
Solved! Go to Solution.
Hi there,
Based on the image you provided, you seem to be querying features within one mile of the circle itself? This is just a guess! I looked at the code you provided but it was hard to follow with lots of lines. Can you please provide a simple repro case or at least remove the irrelevant lines from your code?
This is a really simple test app that shows point features being selected within 200 miles of the clicked location: https://codepen.io/U_B_U/pen/yLjbwXj?editors=1000
Hi there,
Based on the image you provided, you seem to be querying features within one mile of the circle itself? This is just a guess! I looked at the code you provided but it was hard to follow with lots of lines. Can you please provide a simple repro case or at least remove the irrelevant lines from your code?
This is a really simple test app that shows point features being selected within 200 miles of the clicked location: https://codepen.io/U_B_U/pen/yLjbwXj?editors=1000
Hi,
Thank you for the reply.
Yes, that is right. I am querying the features within one mile of the circle. Below is the edited code.
The code for now selects the points, within 1 mile of the site id (given by the user) from the points layer. It is not highlighting the selected points. Trying to select the datasource of the points layer so the points /features in the map are highlighted.
I am trying to query the datasource to get id using selectRecordsByids method, so that the points are highlighted and selected in the table widget.
line 12, 13, 14 are not working and not querying the records from the datasource.
Any help is very much appreciated.
Thank you,
Sara
Hi there,
Have you looked at this sample? This sample allows users select features on the map by drawing rectangles: https://developers.arcgis.com/javascript/latest/sample-code/sandbox/?sample=highlight-features-by-ge...
The sample sets the FeatureTable.highlightOnRowSelectEnabled to false. You can comment out this line in the FeatureTable constructor. It also sets the LayerView.featureEffect and you can remove that logic. Other than that it does what you are looking for.
Hi,
I am able to run the code successfully now and get the points highlighted inside the buffer.
https://codepen.io/U_B_U/pen/yLjbwXj?editors=1000, the code from this sample made it work. Thank you for prompt response and saving me from spending lot of time and effort.
I had few issues(solved for now) after making the code run as a separate widget itself it ran successfully, when I added as widgets in Widget Controller(Expereince Builder), it failed again, after removing the reference to the controller it ran successfully. I am able to access it now from Widget Controller.
It is not able to zoom to certain points now, works for most of the point features in the layer. Trying to troubleshoot it and I am thinking it should do something with the web map.
I will check and update the results here.
I could not post the reply sooner as I was still looking into the above issues.
I am attaching the code below for both widget.tsx and settings.tsx, for reference.
widget.tsx code: