This exercise walks you through the following:
- Get the user to click a point
- Display the clicked point and a buffer around it
- Query for features within the buffer
Prerequisites:
- Complete Exercise 3, or get the Exercise 3 code solution compiling and running properly in Qt Creator.
If you need some help, you can refer to the solution to this exercise, available in this repository.
You can use ArcGIS Runtime to detect when and where the user interacts with the map or scene, either with the mouse or with a touchscreen. In this exercise, you just need the user to click or tap a point. You could detect every user click, but instead, we will let the user activate and deactivate this capability with a toggle button.
-
In your QML file, add a button to your app to enable the user to click a point on the map. Make it
checkable
, i.e. make it a toggle button:Button { id: button_bufferAndQuery iconSource: "qrc:///Resources/location.png" anchors.right: mapView.right anchors.rightMargin: 20 anchors.bottom: button_zoomIn.top anchors.bottomMargin: 10 checkable: true }
-
Create a function called
bufferAndQuery
that handles a mouse event. Check to see if it is a left mouse button event; if so, print to the console. Later you will replaceconsole.log
with code that buffers the point and queries for features within that buffer:function bufferAndQuery(event) { if (Qt.LeftButton === event.button) { console.log("Click!"); } }
-
In your
MapView
, add anonMouseClicked
function to listen for a mouse click. If the buffer and query button is toggled on (i.e.checked
), callbufferAndQuery
:onMouseClicked: function (event) { if (button_bufferAndQuery.checked) { bufferAndQuery(event); } }
-
Run your app. Verify that a new toggle button appears and that your
console.log
prints text when and only when the toggle button is toggled on and you click the map:
You need to buffer the clicked point and display both the point and the buffer as graphics on the map.
-
In your QML code, create a marker symbol for the click and a line symbol for the buffer. In the following code, the point symbol is a 10-pixel circle with an orange (FFA500) color, and the buffer symbol is a hollow polygon with a 3-pixel orange (FFA500) solid line border:
SimpleMarkerSymbol { id: clickSymbol style: Enums.SimpleMarkerSymbolStyleCircle color: "#FFA500" size: 10 } SimpleFillSymbol { id: bufferSymbol style: Enums.SimpleFillSymbolStyleNull outline: SimpleLineSymbol { style: Enums.SimpleLineSymbolStyleSolid color: "#FFA500" width: 3 } }
-
Create a
GraphicsOverlay
field:GraphicsOverlay { id: bufferAndQueryMapGraphics }
-
In your
MapView
, add the mapGraphicsOverlay
to yourMapView
:Component.onCompleted: { graphicsOverlays.append(bufferAndQueryMapGraphics) }
-
Create a
getGeoPoint
function to convert a mouse event to aPoint
. This method should use either theMapView
or theSceneView
to convert a screen point to a geographic point, depending on whether the app is currently in 2D mode or 3D mode. You're only going to callgetGeoPoint(MouseEvent)
in one place here in Exercise 4, and you're always using theMapView
, so you don't really have to create a method just for this. But you will thank yourself for writing this method when you get to Exercise 5.function getGeoPoint(event) { var func = threeD ? sceneView.screenToBaseSurface : mapView.screenToLocation; return func(event.x, event.y); }
-
In
bufferAndQuery
, you need to replace yourconsole.out
with code to create a buffer and display the point and buffer as graphics. First, usegetGeoPoint
to convert the mouse event to a geographic point. Next, create a 1000-meter buffer, which is pretty simple with ArcGIS Runtime'sGeometryEngine
class:var geoPoint = getGeoPoint(event); var buffer = GeometryEngine.bufferGeodetic( geoPoint, 1000, Enums.LinearUnitIdMeters, 1, Enums.GeodeticCurveTypeGeodesic);
-
In
bufferAndQuery
, add the point and buffer as graphics. Clear theGraphicsOverlay
's graphics and then add the point and buffer as newGraphic
objects:var graphics = bufferAndQueryMapGraphics.graphics; graphics.clear(); graphics.append(ArcGISRuntimeEnvironment.createObject("Graphic", { geometry: buffer, symbol: bufferSymbol })); graphics.append(ArcGISRuntimeEnvironment.createObject("Graphic", { geometry: geoPoint, symbol: clickSymbol }));
-
Run your app. Verify that if you toggle the buffer and select button and then click the map, the point you clicked and a 1000-meter buffer around it appear on the map:
There are a few different ways to query and/or select features in ArcGIS Runtime. Here we will use FeatureLayer.selectFeaturesWithQuery
, which both highlights selected features on the map and provides a list of the selected features.
-
Create a
QueryParameters
field:QueryParameters { id: query }
-
In
bufferAndQuery
, after creating the buffer and adding graphics, set theQueryParameters
's geometry:query.geometry = buffer;
-
For each of the
FeatureLayer
objects in the operational layers of theMapView
's map, callselectFeaturesWithQuery
. UseEnums.SelectionModeNew
to do a new selection, as opposed to adding to or removing from the current selection. Add this code after instantiating the query object and setting its geometry:var operationalLayers = mapView.map.operationalLayers; operationalLayers.forEach(function (layer) { if (layer.selectFeaturesWithQuery) { layer.selectFeaturesWithQuery(query, Enums.SelectionModeNew); } });
-
Run your app. Verify on the 2D map that features within the clicked buffer are highlighted on the map:
If you have trouble, refer to the solution code, which is linked near the beginning of this exercise. You can also submit an issue in this repo to ask a question or report a problem. If you are participating live with Esri presenters, feel free to ask a question of the presenters.
If you completed the exercise, congratulations! You learned how to get a user's input on the map, buffer a point, display graphics on the map, and select features based on a query.
Ready for more? Choose from the following:
- Exercise 5: Routing
- Bonus
- We selected features but didn't do anything with the selected features' attributes. The call to
selectFeaturesWithQuery
is asynchronous, andFeatureLayer
has aselectFeaturesStatusChanged
signal that can call your code when the select is complete, so that you can iterate through selected features. See if you can look at the feature attributes to get more information about the selected features. - Try setting properties on the
QueryParameters
object to change the query's behavior. For example, maybe you want to select all features that are outside the buffer instead of those that are inside. How would you do that by adding just one line of code? What other interesting things can you do withQueryParameters
?
- We selected features but didn't do anything with the selected features' attributes. The call to