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.
Solved! Go to Solution.
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;
});
}
});
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;
});
}
});