Guys,
I would like to select multiple features in a FeatureLayer.
I understand you can do this by using the sample (Highlight features by geometry | ArcGIS API for JavaScript 4.13 ).
But, my users would like to use mouse clicks instead of drawing a graphic.
I'm thinking something like SHIFT-CLICK or ALT CLICK for multi selection and releasing the SHIFT OR ALT key would trigger an action (if there are any features selected) like submitting the features selected to a web service.
Hope this all makes sense !
Regards
A
Solved! Go to Solution.
Here is a sample for that. Hold 'Ctrl' button fro multi select.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>Select by Point</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.13/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.13/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<script>
require([
"esri/views/draw/Draw",
"esri/Map",
"esri/Graphic",
"esri/layers/GraphicsLayer",
"esri/layers/FeatureLayer",
"esri/geometry/Point",
"esri/geometry/Multipoint",
"esri/views/MapView",
"dojo/dom",
"dojo/domReady!"
], function (Draw, Map, Graphic, GraphicsLayer, FeatureLayer, Point, Multipoint, MapView, dom) {
const pntGraphics = new GraphicsLayer();
var renderer = {
type: "simple", // autocasts as new SimpleRenderer()
symbol: {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [255, 255, 255, 0.5],
style: "none",
outline: { // autocasts as new SimpleLineSymbol()
color: "white",
width: 2
}
}
};
const statesLyr = new FeatureLayer({
url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer/2',
renderer: renderer,
outFields: ['*']
});
let drawPnt, graphic, ctrlKey = false, highlight, statesLyrView;
const map = new Map({
basemap: "dark-gray",
layers: [pntGraphics, statesLyr]
});
const view = new MapView({
container: "viewDiv",
map: map,
zoom: 5,
center: [-100, 39]
});
statesLyr.when(function(){
view.whenLayerView(statesLyr).then(function(layerView) {
statesLyrView = layerView;
});
})
const draw = new Draw({
view: view
});
var sym = {
type: "simple-marker",
style: "circle",
color: [0, 255, 255, 0.6],
size: "8px",
outline: {
color: [0, 255, 255, 1],
width: 1
}
};
view.ui.add("point-button", "top-left");
document.getElementById("point-button").onclick = drawPoint;
function drawPoint() {
if (highlight) {
highlight.remove();
}
const action = draw.create("point");
// Give a visual feedback to users as they move the pointer over the view
action.on("cursor-update", function (evt) {
view.graphics.removeAll();
drawPnt = new Point({
x: evt.coordinates[0],
y: evt.coordinates[1],
spatialReference: view.spatialReference
});
graphic = new Graphic({
geometry: drawPnt,
symbol: sym
});
view.graphics.add(graphic);
if(ctrlKey && !evt.native.ctrlKey){
draw.reset();
view.graphics.removeAll();
selectStates();
}
});
action.on("draw-complete", function (evt) {
if (evt.native.ctrlKey) {
ctrlKey = true;
}else{
ctrlKey = false;
}
drawPnt = new Point({
x: evt.coordinates[0],
y: evt.coordinates[1],
spatialReference: view.spatialReference
});
graphic = new Graphic({
geometry: drawPnt,
symbol: sym
});
pntGraphics.add(graphic);
if (evt.native.ctrlKey) {
drawPoint();
} else {
view.graphics.removeAll();
selectStates();
}
});
view.focus();
};
function selectStates(){
let mp = new Multipoint({
spatialReference: view.spatialReference
});
let pntArray = pntGraphics.graphics.map(function(gra){
mp.addPoint(gra.geometry);
});
const query = {
geometry: mp,
outFields: ["*"],
outSpatialReference: view.spatialReference,
returnGeometry: true
};
// let query = statesLyr.createQuery();
// query.geometry = mp;
// query.outSpatialReference = view.spatialReference;
// query.returnGeometry = true;
statesLyr.queryFeatures(query)
.then(function(results){
const graphics = results.features;
// remove existing highlighted features
if (highlight) {
highlight.remove();
}
// highlight query results
highlight = statesLyrView.highlight(graphics);
pntGraphics.removeAll();
}).catch(function(err){
console.error(err);
})
}
});
</script>
</head>
<body>
<div id="viewDiv">
<div id="point-button" class="esri-widget esri-widget--button esri-interactive" title="Select Countries">
<span class="esri-icon-map-pin"></span>
</div>
</div>
</body>
</html>
Here is a sample for that. Hold 'Ctrl' button fro multi select.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>Select by Point</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.13/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.13/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<script>
require([
"esri/views/draw/Draw",
"esri/Map",
"esri/Graphic",
"esri/layers/GraphicsLayer",
"esri/layers/FeatureLayer",
"esri/geometry/Point",
"esri/geometry/Multipoint",
"esri/views/MapView",
"dojo/dom",
"dojo/domReady!"
], function (Draw, Map, Graphic, GraphicsLayer, FeatureLayer, Point, Multipoint, MapView, dom) {
const pntGraphics = new GraphicsLayer();
var renderer = {
type: "simple", // autocasts as new SimpleRenderer()
symbol: {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [255, 255, 255, 0.5],
style: "none",
outline: { // autocasts as new SimpleLineSymbol()
color: "white",
width: 2
}
}
};
const statesLyr = new FeatureLayer({
url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer/2',
renderer: renderer,
outFields: ['*']
});
let drawPnt, graphic, ctrlKey = false, highlight, statesLyrView;
const map = new Map({
basemap: "dark-gray",
layers: [pntGraphics, statesLyr]
});
const view = new MapView({
container: "viewDiv",
map: map,
zoom: 5,
center: [-100, 39]
});
statesLyr.when(function(){
view.whenLayerView(statesLyr).then(function(layerView) {
statesLyrView = layerView;
});
})
const draw = new Draw({
view: view
});
var sym = {
type: "simple-marker",
style: "circle",
color: [0, 255, 255, 0.6],
size: "8px",
outline: {
color: [0, 255, 255, 1],
width: 1
}
};
view.ui.add("point-button", "top-left");
document.getElementById("point-button").onclick = drawPoint;
function drawPoint() {
if (highlight) {
highlight.remove();
}
const action = draw.create("point");
// Give a visual feedback to users as they move the pointer over the view
action.on("cursor-update", function (evt) {
view.graphics.removeAll();
drawPnt = new Point({
x: evt.coordinates[0],
y: evt.coordinates[1],
spatialReference: view.spatialReference
});
graphic = new Graphic({
geometry: drawPnt,
symbol: sym
});
view.graphics.add(graphic);
if(ctrlKey && !evt.native.ctrlKey){
draw.reset();
view.graphics.removeAll();
selectStates();
}
});
action.on("draw-complete", function (evt) {
if (evt.native.ctrlKey) {
ctrlKey = true;
}else{
ctrlKey = false;
}
drawPnt = new Point({
x: evt.coordinates[0],
y: evt.coordinates[1],
spatialReference: view.spatialReference
});
graphic = new Graphic({
geometry: drawPnt,
symbol: sym
});
pntGraphics.add(graphic);
if (evt.native.ctrlKey) {
drawPoint();
} else {
view.graphics.removeAll();
selectStates();
}
});
view.focus();
};
function selectStates(){
let mp = new Multipoint({
spatialReference: view.spatialReference
});
let pntArray = pntGraphics.graphics.map(function(gra){
mp.addPoint(gra.geometry);
});
const query = {
geometry: mp,
outFields: ["*"],
outSpatialReference: view.spatialReference,
returnGeometry: true
};
// let query = statesLyr.createQuery();
// query.geometry = mp;
// query.outSpatialReference = view.spatialReference;
// query.returnGeometry = true;
statesLyr.queryFeatures(query)
.then(function(results){
const graphics = results.features;
// remove existing highlighted features
if (highlight) {
highlight.remove();
}
// highlight query results
highlight = statesLyrView.highlight(graphics);
pntGraphics.removeAll();
}).catch(function(err){
console.error(err);
})
}
});
</script>
</head>
<body>
<div id="viewDiv">
<div id="point-button" class="esri-widget esri-widget--button esri-interactive" title="Select Countries">
<span class="esri-icon-map-pin"></span>
</div>
</div>
</body>
</html>
Thanks Robert ! That's exactly what i'm looking for.
A
I am trying to include the solution in my ReactJS app but I'm getting error.
Can you help me in this.
Here is my code,
/* eslint-disable */
import React, { useRef, useEffect } from 'react';
import MapView from '@arcgis/core/views/MapView';
import WebMap from '@arcgis/core/Map';
import FeatureLayer from '@arcgis/core/layers/FeatureLayer';
import Draw from '@arcgis/core/views/draw/Draw';
import Graphic from '@arcgis/core/Graphic';
import GraphicsLayer from '@arcgis/core/layers/GraphicsLayer';
import Point from '@arcgis/core/geometry/Point';
import MultiPoint from '@arcgis/core/geometry/Multipoint';
import '../../assets/css/map.css';
const Map = () => {
const mapDiv = useRef(null);
useEffect(() => {
if (mapDiv.current) {
/**
* Initialize application
*/
const pntGraphics = new GraphicsLayer();
let renderer = {
type: 'simple', // autocasts as new SimpleRenderer()
symbol: {
type: 'simple-fill', // autocasts as new SimpleFillSymbol()
color: [255, 255, 255, 0.5],
style: 'none',
outline: {
// autocasts as new SimpleLineSymbol()
color: 'white',
width: 2,
},
},
};
let drawPnt,
graphic,
ctrlKey = false,
highlight,
statesLyrView;
const webmap = new WebMap({
basemap: 'streets-vector',
});
const view = new MapView({
container: mapDiv.current,
map: webmap,
center: [-98.43750059604514, 38.1986442207947],
scale: 25000000,
ui: {
components: ['zoom', 'compass'],
},
});
const stateFeatureLayer = new FeatureLayer({
url:
'https://services2.arcgis.com/JoecHEvChY6qFe2m/arcgis/rest/services/USA_States/FeatureServer/0',
outFields: ['*'],
});
const cityFeatureLayer = new FeatureLayer({
url:
'https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer/2',
outFields: ['*'],
});
webmap.addMany([stateFeatureLayer, cityFeatureLayer]);
stateFeatureLayer.when(function () {
view.whenLayerView(stateFeatureLayer).then(function (layerView) {
statesLyrView = layerView;
});
});
const draw = new Draw({
view: view,
});
var sym = {
type: 'simple-marker',
style: 'circle',
color: [0, 255, 255, 0.6],
size: '8px',
outline: {
color: [0, 255, 255, 1],
width: 1,
},
};
view.ui.add('point-button', 'top-left');
function drawPoint() {
console.log('in ');
if (highlight) {
highlight.remove();
}
const action = draw.create('point');
action.on('cursor-update', function (evt) {
view.graphics.removeAll();
drawPnt = new Point({
x: evt.coordinates[0],
y: evt.coordinates[1],
spatialReference: view.spatialReference,
});
graphic = new Graphic({
geometry: drawPnt,
symbol: sym,
});
view.graphics.add(graphic);
/*if (ctrlKey && !evt.native.ctrlKey) {
draw.reset();
view.graphics.removeAll();
selectStates();
}*/
});
action.on('draw-complete', function (evt) {
if (evt.native.ctrlKey) {
ctrlKey = true;
} else {
ctrlKey = false;
}
drawPnt = new Point({
x: evt.coordinates[0],
y: evt.coordinates[1],
spatialReference: view.spatialReference,
});
graphic = new Graphic({
geometry: drawPnt,
symbol: sym,
});
pntGraphics.add(graphic);
if (evt.native.ctrlKey) {
drawPoint();
} else {
view.graphics.removeAll();
selectStates();
}
});
view.focus();
}
function selectStates() {
console.log('in selectstate');
}
document.getElementById('point-button').onclick = drawPoint;
// view.on('click', function (event) {
// // only include graphics from hurricanesLayer in the hitTest
// const opts = {
// include: [stateFeatureLayer, cityFeatureLayer],
// };
// view.hitTest(event, opts).then(function (response) {
// // check if a feature is returned from the hurricanesLayer
// if (response.results.length) {
// const graphic = response.results[0].graphic;
// // do something with the graphic
// console.log(graphic.attributes);
// }
// });
// });
}
}, []);
return (
<div className="mapDiv" ref={mapDiv}>
<div
id="point-button"
className="esri-widget esri-widget--button esri-interactive"
title="Select Countries"
>
<span className="esri-icon-map-pin"></span>
</div>
</div>
);
};
export default Map;
When I am trying to multi-select then I'm receiving this error at line 120 [native undefined].
Thank you.
I am seeing the same.
version 4.13, in the first example, is okay.
version 4.24 is NOT okay. The draw-complete event is broken. It does not have the native property.