MapGuide Open Source:  Home |  Download |  Internals

Ticket #167 (new defect)

Opened 1 year ago

Last modified 6 months ago

Legend does not refresh correctly, when using the summary parameter

Reported by: ksgeograf Assigned to:
Priority: medium Milestone:
Component: Server Version: 1.2.0
Severity: major Keywords: legend summary refresh
Cc: External ID: 939559

Description

To reproduce, create a new datasource + layer + map + weblayout. On the map, set the layer "Display in legend" to false.

Then, using the .Net API, modify the current map, and call "SetDisplayInLegend?(true)" on the layer. Then on the client, call GetMapFrame?().Refresh().

The layer never shows in the legend. Zoom (eg. change scale) does not make the layer appear. This happens with both DWF viewer and AJAX viewer. The layer contents appear, and as of 1.2, the tooltips appear, and the "Selectability" works correct.

When modifying the legendctrl.templ, line 16, removing the "&SUMMARY=" string, the AJAX viewer now correctly refreshes the legend, obeying the "SetDisplayInLegend?". However the legend label is not displayed. Setting the legend label using the API, makes the label appear.

I cannot modify the call from the DWF, to test the DWF behavior.

I believe that the server has a defect, when it constructs the legend update summary. There is also a defect, when creating the runtime map, as layers that are not displayed in the legend does not get their label transfered.

Change History

05/29/07 10:45:17 changed by ksgeograf

Ok, I found and fixed the problem.

The summary parameter is used in the viewer to minimize the amount of data that is returned.

In file legend.js, the fields for the summary are defined as:

function LayerSummary(name, objectId, layerRes)
{
    this.name = name;
    this.objectId = objectId;
    this.layerRes = layerRes;
    this.isGroup = false;
    this.type = 1;
}

This needs to be expanded to:

function LayerSummary(name, objectId, layerRes, displayInLegend, expanded, legend, visible)
{
    this.name = name;
    this.objectId = objectId;
    this.layerRes = layerRes;
    this.isGroup = false;
    this.type = 1;
    this.displayInLegend = displayInLegend;
    this.expanded = expanded;
    this.legend = legend;
    this.visible = visible;
}

There may be other fields needed.

In legendui.templ the following function resides:

function HasTreeChanged(current, lightTree)
{
    if(current.length != lightTree.length)
        return true;

    for(var i = 0; i < current.length; i++)
    {
        var node1 = current[i], node2 = lightTree[i];
        if(node1.type != node2.type || node1.objectId != node2.objectId)
            return true;
        if(node1.type == 1)
        {
            if(node1.layerRes != node2.layerRes)
                return true;
        }
        else if(node1.type == 0)
        {
            if(node1.children != null)
            {
                if(node2.children == null)
                    return true;
                if(HasTreeChanged(node1.children, node2.children))
                    return true;
            }
        }
    }
    return false;
}

This function needs to check for the new properties as well:

function HasTreeChanged(current, lightTree)
{
    if(current.length != lightTree.length)
        return true;

    for(var i = 0; i < current.length; i++)
    {
        var node1 = current[i], node2 = lightTree[i];
        if(node1.type != node2.type || node1.objectId != node2.objectId)
            return true;
        if(node1.type == 1)
        {
            if(node1.layerRes != node2.layerRes)
                return true;
	    if(node1.legend != node2.legend)
		return true; 
	    if(node1.expanded != node2.expanded)
		return true;
	    if(node1.displayInLegend != node2.displayInLegend)
		return true;
	    if(node1.visible != node2.visible)
		return true;
        }
        else if(node1.type == 0)
        {
            if(node1.children != null)
            {
                if(node2.children == null)
                    return true;
                if(HasTreeChanged(node1.children, node2.children))
                    return true;
            }
        }
    }
    return false;
}

Lastly, the different API's for the viewer must be updated to fill in the data. For the .Net version, the file to modify is legend.aspx, line 362 looks like:

output = output + String.Format("{0}[{1}] = new LayerSummary(\"{2}\", \"{3}\", \"{4}\"\n",
    container,
    i,
    rtLayer.GetName(),
    rtLayer.GetObjectId(),
    rtLayer.GetLayerDefinition().ToString(),
    );

It should be changed to:

output = output + String.Format("{0}[{1}] = new LayerSummary(\"{2}\", \"{3}\", \"{4}\", {5}, {6}, \"{7}\", {8});\n",
    container,
    i,
    rtLayer.GetName(),
    rtLayer.GetObjectId(),
    rtLayer.GetLayerDefinition().ToString(),
    rtLayer.GetDisplayInLegend() ? "true" : "false",
    rtLayer.GetExpandInLegend()? "true": "false",
    rtLayer.GetLegendLabel(),
    rtLayer.GetVisible()? "true": "false"
    );

This will fix the problem with the legend not updating correctly, using the AJAX viewer, the DWF viewer is still broken. I'm guessing it uses the same code internally.

A short term fix, would be to insert/remove layers from the runtime map, as this seems to be detected. Also swapping layers might work.

The above fix needs to be applied for groups as well, and also for the different other viewers.

05/29/07 11:04:28 changed by ksgeograf

The above fix does not solve the problem with the missing legend labels. That one can be fixed by modifying Map.cpp in MapGuideCommon?. In particular line 266 should be changed from:

if(layer->IsShowInLegend())
{
    rtLayer->SetExpandInLegend(layer->IsExpandInLegend());
    rtLayer->SetLegendLabel(layer->GetLegendLabel());
}

To:

rtLayer->SetExpandInLegend(layer->IsExpandInLegend());
rtLayer->SetLegendLabel(layer->GetLegendLabel());

The same goes for the Group part at line 196.

Since this will not be fixed in the Enterprise edition anytime soon, a temporary fix is:

Load the map definition.
Ensure that ALL layers and groups are visible.
Add a bogus layer, with a random resourceid, keep it invisible.
Save map in temporary location, preferably session repository.
Create runtime map from temporary MapDefinition.
Update runtime map, and hide any legends that should not be shown.

Everytime the legend has to update, change the resourceId of the bogus layer, save it and call map.Refresh();

05/29/07 17:15:25 changed by rexszeto

  • external_id set to 939559.

05/31/07 23:35:21 changed by tomfukushima

  • milestone changed from 1.2 to 1.3.

02/28/08 22:59:37 changed by tomfukushima

  • milestone deleted.