Feature layer (dictionary renderer)

View inC++QMLView on GitHubSample viewer app

Convert features into graphics to show them with mil2525d symbols.

screenshot

Use case

A dictionary renderer uses a style file along with a rule engine to display advanced symbology. This is useful for displaying features using precise military symbology.

How to use the sample

Pan and zoom around the map. Observe the displayed military symbology on the map.

How it works

  1. Create a Geodatabase with a given path.
  2. Wait for geodatabase to completely load by connecting to the loadStatusChanged signal and checking the loadStatus.
  3. Cycle through each GeodatabaseFeatureTable from the geodatabase using Geodatabase.geodatabaseFeatureTables().
  4. Create a FeatureLayer from each table within the geodatabase.
  5. Wait for each layer to load by connecting to the layer's loadStatusChanged signal and checking the loadStatus.
  6. After the last layer has loaded, then create a new Envelope from a union of the extents of all layers.
    • Set the envelope to be the Viewpoint of the map view using MapView.setViewpoint(new Viewpoint(Envelope)).
  7. Add the feature layer to map using Map.operationalLayers.append(FeatureLayer).
  8. Create DictionaryRenderer and attach to the feature layer by setting FeatureLayer.renderer.

Relevant API

  • DictionaryRenderer
  • DictionarySymbolStyle
  • Geodatabase

Offline Data

To set up the sample's offline data, see the Use offline data in the samples section of the Qt Samples repository overview.

Link Local Location
Mil2525d Stylx File <userhome>/ArcGIS/Runtime/Data/styles/arcade_style/mil2525d.stylx
Military Overlay geodatabase <userhome>/ArcGIS/Runtime/Data/geodatabase/militaryoverlay.geodatabase

Tags

military, symbol

Sample Code

FeatureLayer_DictionaryRenderer.qml
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// [WriteFile Name=FeatureLayer_DictionaryRenderer, Category=Features]
// [Legal]
// Copyright 2016 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
import Esri.ArcGISExtras

Rectangle {
    width: 800
    height: 600

    readonly property url dataPath: {
        Qt.platform.os === "ios" ?
                    System.writableLocationUrl(System.StandardPathsDocumentsLocation) + "/ArcGIS/Runtime/Data" :
                    System.writableLocationUrl(System.StandardPathsHomeLocation) + "/ArcGIS/Runtime/Data"
    }

    // Create MapView that contains a Map with the Topographic Basemap
    MapView {
        id: mapView
        anchors {
            fill: parent
        }

        Component.onCompleted: {
            // Set the focus on MapView to initially enable keyboard navigation
            forceActiveFocus();
        }

        Map {
            id: map
            Basemap {
                initStyle: Enums.BasemapStyleArcGISTopographic
            }
        }
    }

    ProgressBar {
        id: progressBar_loading
        anchors {
            horizontalCenter: parent.horizontalCenter
            bottom: parent.bottom
            margins: 5
        }
        indeterminate: true
    }

    Geodatabase {
        property var gdbLayers: []

        id: geodatabase_militaryOverlay
        path: dataPath + "/geodatabase/militaryoverlay.geodatabase"

        onLoadStatusChanged: {
            if (Enums.LoadStatusLoaded === geodatabase_militaryOverlay.loadStatus) {
                const tables = geodatabase_militaryOverlay.geodatabaseFeatureTables;

                // Create a layer for each table
                for (let i = tables.length - 1; i >= 0; i--) {
                    //! [Apply Dictionary Renderer Feature Layer QML]
                    // Create a layer and set the feature table
                    const layer = ArcGISRuntimeEnvironment.createObject("FeatureLayer");
                    layer.featureTable = tables[i];

                    // Create a dictionary renderer and apply to the layer
                    const renderer = ArcGISRuntimeEnvironment.createObject("DictionaryRenderer",{
                                                                               dictionarySymbolStyle:
                                                                               //! [Create Dictionary Symbol Style QML]
                                                                               Factory.DictionarySymbolStyle.createFromFile(dataPath + "/styles/arcade_style/mil2525d.stylx")
                                                                               //! [Create Dictionary Symbol Style QML]
                                                                           });
                    layer.renderer = renderer;
                    //! [Apply Dictionary Renderer Feature Layer QML]

                    /**
                     * If the field names in your data don't match the contents of DictionarySymbolStyle::symbologyFieldNames(),
                     * you must set DictionaryRenderer::symbologyFieldOverrides to a map of key-value pairs like this:
                     * {
                     *   "dictionaryFieldName1": "myFieldName1",
                     *   "dictionaryFieldName2": "myFieldName2"
                     * }
                     * The following commented-out code demonstrates one way to do it, in a scenario where the dictionary
                     * expects the field name "identity" but the database table contains the field "affiliation" instead.
                     */
                    /**
                    let fieldOverrides = {
                        identity: "affiliation"
                    };
                    renderer.symbologyFieldOverrides = fieldOverrides;
                    */

                    gdbLayers.push(layer);

                    // Connect the layer's loadStatusChanged signal
                    layer.loadStatusChanged.connect(()=> {

                        // See if all the layers have loaded.
                        for (let j = 0; j < gdbLayers.length; j++) {
                            if (Enums.LoadStatusLoaded !== gdbLayers[j].loadStatus) {
                                return;
                            }
                        }

                        /**
                         * If we get here, all the layers loaded. Union the extents and set
                         * the viewpoint.
                         */
                        let bbox = gdbLayers[0].fullExtent;
                        for (let j = 1; j < gdbLayers.length; j++) {
                            bbox = GeometryEngine.unionOf(bbox, gdbLayers[j].fullExtent);
                        }
                        mapView.setViewpointGeometry(bbox);
                        progressBar_loading.visible = false;
                    });

                    // Add the layer to the map
                    map.operationalLayers.append(layer);
                }
            }
        }
    }
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.