Display data from an ArcGIS stream service using a dynamic entity layer.
Use case
A stream service is a type of service provided by ArcGIS Velocity and GeoEvent Server that allows clients to receive a stream of data observations via a web socket. ArcGIS Maps SDK for Qt allows you to connect to a stream service and manage the information as dynamic entities and display them in a dynamic entity layer. Displaying information from feeds such as a stream service is important in applications like dashboards where users need to visualize and track updates of real-world objects in real-time.
Use ArcGISStreamService
to manage the connection to the stream service and purge options to manage how much data is stored and maintained by the application. The dynamic entity layer will display the latest received observation, and you can set track display properties to determine how to display historical information for each dynamic entity. This includes the number of previous observations to show, whether to display track lines in-between previous observations, and setting renderers.
How to use the sample
Use the controls to connect to or disconnect from the stream service, modify display properties in the dynamic entity layer, and purge all observations from the application.
How it works
- Add a
DynamicEntityLayer
to theMap
. - Add a
ArcGISStreamService
with a URL to the layer'sdataSource
. - Set an
ArcGISStreamServiceFilter
on the stream service to limit the amount of data coming from the server. - Configure the
DynamicEntityDataSourcePurgeOptions
on the stream service to limit the amount of data managed by the application. - Add a
Renderer
to the layer to customize the appearance of the latest dynamic entity observations - Update the values in the layer's
TrackDisplayProperties
to customize the appearance of previous observations
Relevant API
- ArcGISStreamService
- ArcGISStreamServiceFilter
- ConnectionStatus
- DynamicEntity
- DynamicEntityLayer
- DynamicEntityPurgeOptions
- TrackDisplayProperties
About the data
This sample uses a stream service that simulates live data coming from snowplows near Sandy, Utah. There are multiple vehicle types and multiple agencies operating the snowplows.
Additional information
More information about dynamic entities can be found in the [guide documentation](link goes here).
Tags
data, dynamic, entity, live, purge, real-time, service, stream, track
Sample Code
// [WriteFile Name=AddDynamicEntityLayer, Category=Layers]
// [Legal]
// Copyright 2023 Esri.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// [Legal]
import QtQuick
import QtQuick.Controls
import Esri.ArcGISRuntime
Rectangle {
id: rootRectangle
clip: true
width: 800
height: 600
MapView {
id: mapView
anchors.fill: parent
Component.onCompleted: {
// Set and keep the focus on MapView to enable keyboard navigation
forceActiveFocus();
}
Map {
initBasemapStyle: Enums.BasemapStyleArcGISDarkGray
initialViewpoint: ViewpointExtent {
extent: sandyUtahEnvelope
}
// A layer that displays dynamic entities from real time services
DynamicEntityLayer {
id: dynamicEntityLayer
dataSource: ArcGISStreamService {
id: dynamicEntityDataSource
url: "https://realtimegis2016.esri.com:6443/arcgis/rest/services/SandyVehicles/StreamServer"
filter: ArcGISStreamServiceFilter {
// This filters what information is received from the server
whereClause: "speed > 0"
geometry: sandyUtahEnvelope
}
// Set the time in seconds after which observations will be removed from the cache
purgeOptions.maximumDuration: 300
}
// Set the renderer for the most recent observations
renderer: UniqueValueRenderer {
fieldNames: ["agency"]
UniqueValue {
values: [3]
symbol: SimpleMarkerSymbol {
style: Enums.SimpleMarkerSymbolStyleCircle
color: "magenta"
size: 8
}
}
UniqueValue {
values: [4]
symbol: SimpleMarkerSymbol {
style: Enums.SimpleMarkerSymbolStyleCircle
color: "green"
size: 8
}
}
defaultSymbol: SimpleMarkerSymbol {
style: Enums.SimpleMarkerSymbolStyleCircle
color: "blue"
size: 8
}
}
// Set the display properties for previous observations and the trackline
trackDisplayProperties {
showTrackLine: true
showPreviousObservations: true
previousObservationRenderer: UniqueValueRenderer {
fieldNames: ["agency"]
UniqueValue {
values: [3]
symbol: SimpleMarkerSymbol {
style: Enums.SimpleMarkerSymbolStyleCircle
color: "magenta"
size: 3
}
}
UniqueValue {
values: [4]
symbol: SimpleMarkerSymbol {
style: Enums.SimpleMarkerSymbolStyleCircle
color: "green"
size: 3
}
}
defaultSymbol: SimpleMarkerSymbol {
style: Enums.SimpleMarkerSymbolStyleCircle
color: "blue"
size: 3
}
}
trackLineRenderer: SimpleRenderer {
symbol: SimpleLineSymbol {
style: Enums.SimpleLineSymbolStyleSolid
color: "lightGray"
width: 2
}
}
}
}
}
GraphicsOverlay {
id: sandyBorderOverlay
Graphic {
id: sandyBorderGraphic
geometry: Envelope {
id: sandyUtahEnvelope
xMin: -112.110052
xMax: -111.814782
yMin: 40.535247
yMax: 40.718083
spatialReference: Factory.SpatialReference.createWgs84()
}
symbol: SimpleLineSymbol {
style: Enums.SimpleLineSymbolStyleDash
color: "red"
width: 2
}
}
}
}
Rectangle {
id: dynamicEntityLayerOptions
anchors {
top: parent.top
right: parent.right
margins: 10
}
width: (300 < parent.width - 20) ? 300 : parent.width - 20
height: column.height + 20
border.width: 1
// Catch mouse signals so they don't propagate to the map
MouseArea {
anchors.fill: parent
onClicked: mouse => mouse.accepted = true
onWheel: wheel => wheel.accepted = true
}
Column {
id: column
anchors {
top: parent.top
left: parent.left
right: parent.right
margins: 10
}
Text {
id: statusText
anchors.horizontalCenter: parent.horizontalCenter
// dynamicEntityDataSource.connectionStatus returns a ConnectionStatus enum
text: "Status: " + ["Disconnected","Connecting","Connected"][dynamicEntityDataSource.connectionStatus]
font.pixelSize: 18
horizontalAlignment: Text.AlignHCenter
font.bold: true
}
Switch {
id: statusSwitch
anchors.horizontalCenter: parent.horizontalCenter
checked: dynamicEntityDataSource.connectionStatus !== Enums.ConnectionStatusDisconnected
enabled: dynamicEntityDataSource.connectionStatus !== Enums.ConnectionStatusConnecting
onCheckedChanged: {
checked ? dynamicEntityDataSource.connectDataSource() : dynamicEntityDataSource.disconnectDataSource();
}
}
CheckBox {
id: trackLinesBox
text: "Track lines"
checked: true
onCheckedChanged: {
// Show or hide the lines that connect previous observations
dynamicEntityLayer.trackDisplayProperties.showTrackLine = checked;
}
}
CheckBox {
id: previousObservationsBox
text: "Previous observations"
checked: true
onCheckedChanged: {
// Show or hide previous observations (if maximum observations is greater than 1)
dynamicEntityLayer.trackDisplayProperties.showPreviousObservations = checked;
}
}
Text {
id: observationsSliderText
topPadding: 10
text: "Observations per track (" + observationsSlider.value + ")"
}
Slider {
id: observationsSlider
anchors {
left: parent.left
right: parent.right
}
value: 5
stepSize: 1
from: 1
to: 16
onValueChanged: {
// Update the number of entity observations displayed using the value from the Slider
dynamicEntityLayer.trackDisplayProperties.maximumObservations = value;
}
}
Button {
id: purgeButton
anchors.horizontalCenter: parent.horizontalCenter
text: "Purge all observations"
onClicked: {
// Remove all current observations from the cache
dynamicEntityDataSource.purgeAll();
}
}
}
}
}