modifying the legend widget and ImageryLayer

802
1
Jump to solution
07-17-2019 06:53 AM
LizEidsness
New Contributor III

Problem: I have a situation where I have a raster from an ImageService.  I have applied a client side colormap.  I'd like the legend to reflect the colormap.  I'd like to know if my approach is ok.  When I put all the pieces together they fail, so I don't know if it's ok, or a bug.  

Also: In investigating this, I think I have found a bug or something. (I've e-mailed ESRI)

I have figured out how to modify the legend by changing activeLayerInfos / legendElements object.  This works fine on a click event.  You'll see the labels for the first two legend items change on a click on the map.  https://codepen.io/lizeidsness/pen/GbVvKp

This is going to be a little piece of a big pie, so I'd like to hook it up to an event/watch that's appropriate, and I'm having trouble finding the right one.  I have tried this.  https://codepen.io/lizeidsness/pen/xvKpje

Seems to work - EXCEPT  not with my ImageryLayer.  It reverts when you do anything.  

https://codepen.io/lizeidsness/pen/zgOpBL It's using the click handler, to better isolate the events.  If you drag the map around, the changes stay.  If you zoom, they are gone.  I haven't even attempted to put this together with my custom renderer because it's not working well yet.

Tags (2)
0 Kudos
1 Solution

Accepted Solutions
LizEidsness
New Contributor III

I resolved this one on my own, though ESRI did also provide a solution.  Both here.

Revised codepen:

https://codepen.io/lizeidsness/pen/zgOpBL

My problem was the watch wasn't set on the right thing.  So there's an initial watch on the activeLayerInfos.length property.  If there's a legend it will be > 0. 

New: If there's a layer in the legend, set a watch on it's legendElements object.  If this changes, it will update accordingly.

watchUtils.when(legend, "activeLayerInfos.length", setWatch);

function updateLegend(layer) {
    var activeLayer = legend.activeLayerInfos.find(e => {
        return e.layer.title == layer.title;
    });
    if (activeLayer.legendElements.length < 1) {
        return false;
    }
    var element = activeLayer.legendElements.find(e => {
        return e.type == "symbol-table"; //add additional support
    });
    element.infos.forEach(e => {
        lookup.forEach(item => {
            if (e.label == item[0]) {
                e.label = item[1];
            }
        });
    });
}
function setWatch() {
    if (legend.activeLayerInfos.length > 0) {
        legend.activeLayerInfos.forEach(al => {
            watchUtils.when(al, "legendElements", function () {
                updateLegend(al);
            });
        });
    }
} ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

ESRI's solution would intercept the legend response from the service.  It would work well enough, if there isn't an appropriate API property to watch instead (in this case)

esriConfig.request.interceptors.push({
    urls: imageryLayerUrl + "/legend",
    after: function (response) {
        response.data.layers[0].legend.forEach(l => {
            l.label = "not " + l.label;
        });
    }
});

View solution in original post

0 Kudos
1 Reply
LizEidsness
New Contributor III

I resolved this one on my own, though ESRI did also provide a solution.  Both here.

Revised codepen:

https://codepen.io/lizeidsness/pen/zgOpBL

My problem was the watch wasn't set on the right thing.  So there's an initial watch on the activeLayerInfos.length property.  If there's a legend it will be > 0. 

New: If there's a layer in the legend, set a watch on it's legendElements object.  If this changes, it will update accordingly.

watchUtils.when(legend, "activeLayerInfos.length", setWatch);

function updateLegend(layer) {
    var activeLayer = legend.activeLayerInfos.find(e => {
        return e.layer.title == layer.title;
    });
    if (activeLayer.legendElements.length < 1) {
        return false;
    }
    var element = activeLayer.legendElements.find(e => {
        return e.type == "symbol-table"; //add additional support
    });
    element.infos.forEach(e => {
        lookup.forEach(item => {
            if (e.label == item[0]) {
                e.label = item[1];
            }
        });
    });
}
function setWatch() {
    if (legend.activeLayerInfos.length > 0) {
        legend.activeLayerInfos.forEach(al => {
            watchUtils.when(al, "legendElements", function () {
                updateLegend(al);
            });
        });
    }
} ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

ESRI's solution would intercept the legend response from the service.  It would work well enough, if there isn't an appropriate API property to watch instead (in this case)

esriConfig.request.interceptors.push({
    urls: imageryLayerUrl + "/legend",
    after: function (response) {
        response.data.layers[0].legend.forEach(l => {
            l.label = "not " + l.label;
        });
    }
});
0 Kudos