Select to view content in your preferred language

Javascript 4.x legend refresh

1907
24
Jump to solution
11-15-2024 02:51 PM
Mr_Kirkwood
Regular Contributor

I am using JS 4.30. I would like ot figure out how to get the legend to update the symbology of what is in the map when zoomed in. The legend for one of my layers has over 200 symbols. I have a fucntion to zoom into a specific building and floor. That building and floor does not have all 200 symbols it only has 10. I would like the legedn to update and show only the 10 symbols in the map.

The print funtion does this see attached. 

I appreciate any help Thank you! 

Tags (3)
0 Kudos
24 Replies
JoelBennett
MVP Regular Contributor

I see...yes, this approach will not work with MODE_SELECTION since the graphics array won't be populated unless something is selected, and even then, only the selected features will be present in the graphics array.

Based on the info provided, a suitable workaround might be to use a MODE_ONDEMAND layer, with the definition expression set to only show rooms for the current floor.  See also getDefinitionExpression and setDefinitionExpression.

0 Kudos
Mr_Kirkwood
Regular Contributor

Thank you for your help. This gives me a good start.  Here is my zoomTo function that I need to figure out the  getDefinitionExpression and setDefinitionExpression.  

 

unction zoomRoomUse (ids)
{
    require ([
        "esri/tasks/query",
        "esri/geometry/Extent",
        "esri/layers/FeatureLayer"
    ],
            function (Query, Extent, FeatureLayer)
            {
                console.log ("zoomRoomUse");
                var query = new Query ();
                query.objectIds = ids;
                roomUseLayer.setDefinitionExpression = query.objectIds
                query.where = roomUseLayer.setDefinitionExpression;
                console.log ("zoomRoomUse + id" + ids)
                 console.log ("zoomRoomUse + ids" + roomUseLayer.setDefinitionExpression)
                roomUseLayer.selectFeatures (query, FeatureLayer.SELECTION_NEW, function (features)
                {
                    var newExtent = new Extent ();
                    newExtent = features[0].geometry.getExtent ();
                    for (var k = 0; k < features.length; k++) {
                        newExtent = newExtent.union (features[k].geometry.getExtent ().expand (15));
                    }
                    manageDynamicSymbology (roomUseLayer, map)
                    labelRoom ();
                });
            });
}

 

Any ideas? 

0 Kudos
JoelBennett
MVP Regular Contributor

Instead of:

roomUseLayer.setDefinitionExpression = query.objectIds

 

You probably want:

roomUseLayer.setDefinitionExpression(roomUserLayer.objectIdField + " IN(" + ids.join(",") + ")");
0 Kudos
Mr_Kirkwood
Regular Contributor

Thanks! I will test this out in the morning.    

0 Kudos
Mr_Kirkwood
Regular Contributor

Joel,

I have noticed that the code above gives me this error:

Uncaught (in promise) TypeError: Cannot read properties of null (reading 'clone')

Line 35:

" defaultSymbol = originalRenderer.defaultSymbol.clone ();"

The error continues to infinity sometimes. It happens when i use the zoom to feature and sometimes it happens when i click identify on the map. I am not sure what is happening. The zoom fucntion looks like this:

function zoomRoomUse (ids)
{
    require ([
        "esri/rest/query",
        "esri/rest/support/Query",
        "esri/layers/FeatureLayer",
        "esri/views/layers/LayerView"
    ],
            function (query, Query, FeatureLayer, LayerView)
            {
                roomsUseLayer.definitionExpression = roomsUseLayer.objectIdField + " IN(" + ids.join (",") + ")";
//                console.log (roomsUseLayer.definitionExpression)
                view.whenLayerView (roomsUseLayer).then (function (layerView)
                {
                    var query = roomsUseLayer.createQuery ();
                    query.objectIds = [ids];
                    query.where = roomsUseLayer.definitionExpression;
                    roomsUseLayer.queryFeatures (query).then (function (results)
                    {
                        const features = results.features;
                        var geometry = features[0].geometry.extent.clone ();
                        for (var k = 0; k < features.length; k++) {
                            geometry = geometry.union (features[k].geometry.extent.clone ());
                            view.goTo (geometry).then (function ()
                            {
                                roomsUseLayer.visible = true;
                                manageDynamicSymbology (roomsUseLayer, view);
                            }).catch (function (error)
                            {
                                if (error.name != "view:goto-interrupted") {
                                    console.error (error);
                                } else {
                                    console.log ("Drawing");
                                }
                            });
                        }
                    });
                });
            });
}

 

Any thoughts? 

0 Kudos
JoelBennett
MVP Regular Contributor

It appears this will happen in cases where (1) a value exists, but no symbol has been defined for it, and (2) there is no default symbol defined.  In this case, the feature wouldn't be rendered at all.  To avoid the error, you could change the statement on line 34 from:

if (defaultSymbol === null) {

to

if ((defaultSymbol === null) && (originalRenderer.defaultSymbol)) {
0 Kudos
Mr_Kirkwood
Regular Contributor

Joel,

There is no error now, but the layer is flickering on and off. 

0 Kudos
Mr_Kirkwood
Regular Contributor

Here is the full code: 

function manageDynamicSymbology (featureLayer, view)
{
    featureLayer.when (function ()
    {
        view.whenLayerView (featureLayer).then (function (layerView)
        {
            var originalRenderer = featureLayer.renderer;
            var ignoreRendererSet = false;

            layerView.watch ("updating", function (newValue, oldValue, propertyName, target)
            {
                if ((!newValue) && (oldValue)) {
                    if (ignoreRendererSet)
                        ignoreRendererSet = false;
                    else {
                        ignoreRendererSet = true;

                        var query = layerView.createQuery ();
                        query.geometry = view.extent;

                        layerView.queryFeatures (query).then (function (featureSet)
                        {
                            if (featureSet.features.length === 0)
                                featureLayer.renderer = originalRenderer;
                            else {
                                var promises = [];

                                featureSet.features.forEach (function (feature)
                                {
                                    promises.push (originalRenderer.getUniqueValueInfo (feature));
                                });

                                Promise.all (promises).then (function (infos)
                                {
                                    var uniqueValueInfos = [];
                                    var defaultSymbol = null;
                                    var defaultLabel = null;

                                    infos.forEach (function (uniqueValueInfo)
                                    {
                                        if (!uniqueValueInfo) {
                                            if ((defaultSymbol === null) && (originalRenderer.defaultSymbol)) {
                                                defaultSymbol = originalRenderer.defaultSymbol.clone ();
                                                defaultLabel = originalRenderer.defaultLabel;
                                            }
                                        } else if (!uniqueValueInfos.includes (uniqueValueInfo))
                                            uniqueValueInfos.push (uniqueValueInfo);
                                    });

                                    var newRenderer = featureLayer.renderer.clone ();
                                    newRenderer.uniqueValueInfos = uniqueValueInfos.sort (function (a, b)
                                    {
                                        return originalRenderer.uniqueValueInfos.indexOf (a) - originalRenderer.uniqueValueInfos.indexOf (b);
                                    });
                                    newRenderer.defaultSymbol = defaultSymbol;
                                    newRenderer.defaultLabel = defaultLabel;

                                    featureLayer.renderer = newRenderer;
                                });
                            }
                        }, function (e)
                        {
                            featureLayer.renderer = originalRenderer;
                        });
                    }
                }
            });
        });
    });
}
0 Kudos
JoelBennett
MVP Regular Contributor

There is a possibility of an infinite loop occurring since setting the renderer will result in the "updating" property being set, and when the "updating" property is set to false, the process starts over again.  However, that's what the "ignoreRendererSet" variable exists to prevent, and I don't see any immediate problem with it not doing its job.  I would recommend using the browser's developer tools to add some breakpoints and step through the code to help determine where the infinite loop is occurring.

0 Kudos
Mr_Kirkwood
Regular Contributor

Joel,

the code loop seems to be around this line:

infos.forEach (function (uniqueValueInfo)

 

It will work for a few buildings then will start to loop. 

0 Kudos