HTML Legends with MapServer

Author:

Jeff McKenna

Contact:

jmckenna at gatewaygeomatics.com

Last Updated:

2022-08-20

Introduction

The HTML legend is an alternative to the traditional GIF legend in MapServer. The following document describes the process for implementing an HTML legend in MapServer CGI applications (NOTE: MapServer version > 3.5 is required).

This document assumes that you are already familiar with certain aspects of MapServer:

  • Setting up MapServer mapfiles and templates.

Implementation

Key components for generating HTML legends are 1) a template parameter in the legend object, 2) a CGI [legend] tag in the HTML file, and 3) an HTML legend template file. So that means that if the HTML page has the CGI [legend] parameter set, and the mapfile has a LEGEND object with its TEMPLATE set to a valid HTML legend file then an HTML legend will be returned. The following sections discuss these components.

Legend Object of Mapfile

The HTML legend is enabled by a new TEMPLATE parameter in the Legend Object of the mapfile. If TEMPLATE is set in the Legend Object, then the HTML legend template file is read and used to generate an HTML legend which will be inserted at the location of the [legend] tag in the main HTML template. Similar to other MapServer templates, the HTML legend template filename MUST end with an “.html” extension.

Example 1. Sample Legend Object with the new TEMPLATE parameter

...
# LEGEND object
LEGEND
  STATUS ON
  KEYSIZE 18 12
  # LABEL object
  LABEL
    TYPE BITMAP
    SIZE MEDIUM
    COLOR 0 0 89
  END
  TEMPLATE "legend.html"  ### HTML template file
END
...

If TEMPLATE is not set, then the [legend] tag produces a regular image in a GIF/PNG image (the traditional behaviour).

CGI [legend] tag

The traditional CGI [legend] tag returns the URL of an image, so it is usually used inside an <IMG SRC=[legend]> tag in the HTML file. The new HTML [legend] tag returns a block of HTML, so when converting an existing application template from using a traditional image legend to the new HTML legend, you have to remove the IMG tag in the main application template. Also note that if legend mode is specified in the URL, then MapServer will return a gif containing the whole legend if no template is specified.

See the CGI Reference doc for more information on CGI parameters.

Example 2. [legend] tag in the main HTML template (with TEMPLATE set)

...
<FONT SIZE=+1><B>Legend</B></FONT><BR><HR>[legend]<HR>
...

Example 3. [legend] tag in the main HTML template (with TEMPLATE not set)

...
<FONT SIZE=+1><B>Legend</B></FONT><BR><HR><IMG SRC="[legend]"><HR>
...

HTML Legend Template File

The HTML legend template file is a separate file that contains 0 or 1 of each of the following tags that define blocks of HTML to use in building the legend:

[leg_group_html] ... [/leg_group_html]
[leg_layer_html <OPTIONAL PARAMS>] ... [/leg_layer_html]
[leg_class_html <OPTIONAL PARAMS>] ... [/leg_class_html]

Note

Any text or HTML tags outside the [leg_*_html] tag pairs in the legend template file are ignored by the template parser.

The following example shows what an HTML legend TEMPLATE file could look like:

Example 4. An HTML legend TEMPLATE file

[leg_group_html]
<tr>
    <td colspan=3 bgcolor=#cccccc><b>[leg_group_name]</b></td>
</tr>
[/leg_group_html]

[leg_layer_html order_metadata=legend_order opt_flag=5]
<tr>
    <td>
        <input type=checkbox name="map_[leg_layer_name]_status"
       value=1 [if name=layer_status oper=eq value=2]CHECKED[/if]>
     </td>
    <td colspan=2>
        <a href="[metadata name=href]">[metadata name=layer_title]</a>
    </td>
</tr >
[/leg_layer_html]

[leg_class_html]
<tr>
    <td width=15> </td>
    <td>
        <img src="[leg_icon width=20 height=10]" width=20 height=10>
    </td>
    <td>
        [leg_class_name]
    </td>
</tr>
[/leg_class_html]

Supported Tags for the TEMPLATE file:

HEADER block

Tag:

[leg_header_html]…[/leg_header_html]

Description:

HTML block to use as the header of the legend.

GROUP block

Tag:

[leg_group_html <OPTIONAL PARAMS>]…[/leg_group_html]

Description:

HTML block to use for layer group headers if layers should be grouped in the legend. If not set then layers are not grouped in the legend.

When the [leg_group_html] tag is used, then layers that don’t belong to any group (i.e. LAYER GROUP not set in the mapfile) and their classes will not show up at all in the legend. The group list is decided by the order_metadata parameter, which is explained later.

SUPPORTED PARAMETERS:

Parameter:

opt_flag=<bit_mask>

Description:

Control the group’s display, by adding the following values (default is 15). The opt_flag is applied on all layers in the group. If at least one layer matches the flag, the group will show up in the legend.

1:

If set, show group even if all layers in group are out of scale (default: hide groups out of scale).

2:

If set, show group even if all layers in group have status OFF (default: hide groups with STATUS OFF).

4:

If set, show group even if all layers in group are of type QUERY (default: hide group of TYPE QUERY)

8:

If set, show group even if all layers in group are of type ANNOTATION (default: hide groups of TYPE ANNOTATION)

Deprecated since version 6.2: Use CLASS->LABEL or CLASS->STYLE in your existing layer instead of a separate ANNOTATION layer

e.g. opt_flag=12 (shown below) means show all layer types, including QUERY and ANNOTATION layers (4 + 8)

[leg_group_html opt_flag=12]
   ...
[/leg_group_html]

SUPPORTED TAGS:

Tag:

[leg_group_name]

Description:

Returns the group’s name.

Tag:

[layer_status]

Description:

Returns the status of the first layer in the group.

Tag:

[leg_icon width=<optional_width> height=<optional_height>]

Description:

In the group context, the [leg_icon] tag returns the URL of a legend icon for the first class in the first layer that’s part of this group.

Tag:

[metadata name=<metadata_field_to_display>]

Description:

Returns specified metadata value from web’s metadata.

e.g. the group block below simply displays the name of the group in the legend:

[leg_group_html]
  <tr><td colspan=2><b>[leg_group_name]</b></td></tr>
[/leg_group_html]

LAYER block

Tag:

[leg_layer_html <OPTIONAL PARAMS>] … [/leg_layer_html]

Description:

HTML block to use for layer header. If not set then no layer headers are displayed (could allow a legend with only classes in it).

SUPPORTED PARAMETERS:

Parameter:

order_metadata=<field_to_order_by>

Description:

Specifies that the value of the layer metadata <field_to_order_by> controls the order and visibility of the layers in the legend.

  • Layers with <field_to_order_by> >= 0 are sorted in order of this value, with multiple layers with same value being accepted, in which case the map layer order applies between those layers.

  • Layers with <field_to_order_by> < 0 are always hidden in the legend.

Parameter:

opt_flag=<bit_mask>

Description:

Control the layer display process. Add the values below to acquire the desired options (default is 15):

1:

If set, show layer even if out of scale (default: hide layers out of scale).

2:

If set, show layer even if status is OFF (default: hide layers with STATUS OFF).

4:

If set, show layer even if type is QUERY (default: hide layers of TYPE QUERY)

8:

If set, show layer even if type is ANNOTATION (default: hide layers of TYPE ANNOTATION)

Deprecated since version 6.2: Use CLASS->LABEL or CLASS->STYLE in your existing layer instead of a separate ANNOTATION layer

e.g. opt_flag=14 (shown below) means do not show layers in the legend that are out of scale.

[leg_layer_html opt_flag=14]
  ...
[/leg_layer_html]

SUPPORTED TAGS:

Tag:

[leg_layer_group]

Description:

Returns the group name of the layer. This was added to MapServer v4.8.

Tag:

[leg_layer_index]

Description:

Returns the mapfile index value of the layer, which is useful for ordering. This was added to MapServer v4.8.

Tag:

[leg_layer_maxscale]

Description:

Returns the maximum scale set for the layer. This was added to MapServer v4.8.

Tag:

[leg_layer_minscale]

Description:

Returns the minimum scale set for the layer. This was added to MapServer v4.8.

Tag:

[leg_layer_name]

Description:

Returns the current LAYER NAME value.

Tag:

[leg_icon width=<optional_width> height=<optional_height>]

Description:

In the layer context, the [leg_icon] tag returns the URL of a legend icon for the first class in this layer.

Tag:

[metadata name=<metadata_field_to_display>]

Description:

Returns specified metadata value from this layer’s metadata and web’s metadata.

e.g. the layer block below simply displays an icon of the layer’s class and the layer name:

[leg_layer_html]
   <tr><td><img src=[leg_icon width=15 height=15]><b>[leg_layer_name]</b></td></tr>
[/leg_layer_html]

CLASS block

Tag:

[leg_class_html <OPTIONAL PARAMS>] … [/leg_class_html]

Description:

HTML block to use for classes. If not set then no classes are displayed (could allow a legend with only layer headers in it). Note that classes with NULL (i.e. empty) NAMEs are not displayed.

SUPPORTED PARAMETERS:

Parameter:

opt_flag=<bit_mask>

Description:

Control the layer (i.e. class) display process. Add the values below to acquire the desired options (default is 15). Note that using this parameter for the CLASS block has the same effect as using the opt_flag parameter in the LAYER block.

1:

If set, show layer even if out of scale (default: hide layers out of scale).

2:

If set, show layer even if status is OFF (default: hide layers with STATUS OFF).

4:

If set, show layer even if type is QUERY (default: hide layers of TYPE QUERY)

8:

If set, show layer even if type is ANNOTATION (default: hide layers of TYPE ANNOTATION)

Deprecated since version 6.2: Use CLASS->LABEL or CLASS->STYLE in your existing layer instead of a separate ANNOTATION layer

e.g. opt_flag=14 (shown below) means do not show classes in the legend that are out of scale.

[leg_class_html opt_flag=14]
  ...
[/leg_class_html]

SUPPORTED TAGS:

Tag:

[leg_class_index]

Description:

Returns the mapfile index value of the class, which is useful for ordering and legend icon creation. This was added to MapServer v4.8.

Tag:

[leg_class_maxscale]

Description:

Returns the maximum scale set for the class. This was added to MapServer v4.8.

Tag:

[leg_class_minscale]

Description:

Returns the minimum scale set for the class. This was added to MapServer v4.8.

Tag:

[leg_class_name]

Description:

Returns the CLASS NAME value.

Tag:

[leg_class_title]

Description:

Returns the CLASS TITLE value.

Tag:

[leg_layer_name]

Description:

Returns the parent layer name. This was added to MapServer v4.8.

Tag:

[leg_icon width=<optional_width> height=<optional_height>]

Description:

In the layer context, the [leg_icon] tag returns the URL of a legend icon for the first class in this layer.

Tag:

[metadata name=<metadata_field_to_display>]

Description:

Returns specified metadata value from the metadata of the layer to which this class belongs and web’s metadata.

e.g. the class block below simply displays an icon of the layer’s class and the class name:

[leg_class_html]
  <tr><td><img src=[leg_icon width=15 height=15]><b>[leg_class_name]</b></td></tr>
[/leg_class_html]

CONDITIONAL text

[if] tags can be used in any of the [leg_*_html] tags above to place conditional text. The syntax is:

[if name=<field_to_check> oper=<eq|neq|isset|isnull> value=<to_compare_with_field>] ... [/if]

Note:

Nested IF’s are supported. Parameter “oper” can be “eq” for equal, “neq” for not equal, “isset” (self-explanatory), or “isnull” (self-explanatory). The default value is equal.

Example 6. [if] tag can be used to maintain the state of a layer checkbox

[leg_layer_html order_metadata=legend_order opt_flag=5]
<tr>
    <td>
        <input type=checkbox name="map_[leg_layer_name]_status"
         value=1 [if name=layer_status oper=eq value=2]CHECKED[/if] >
    </td>
    <td colspan=2>
        <a href="[metadata name=href]">[metadata name=layer_title]</a>
    </td>
</tr >
[/leg_layer_html]

The possible values that can be tested in an [if] tag depend on the context in which the [if] tag is used. At the moment, the number of values that can be tested is limited, but new values may be added as needed.

Note that the order of the items in the following [if] contexts are listed by their order of precedence. The rule is always that special keywords have top priority (e.g. layer_status, etc.), followed by layer-level metadata, and ending with map-level metadata. The possible values that can be tested are as follows:

In a [leg_group_html] context:

  • [if name=layer_status value=…] … [/if]

    value is the layer status of the first layer that belongs to the group in integer format: 0=OFF, 1=ON, 2=DEFAULT

  • [if name=layer_visible value=…] … [/if]

    value is the visibility of the first layer in the group: 0=NOT VISIBLE, 1=VISIBLE

  • [if name=group_name value=…] … [/if]

  • [if name=any_layer_metadata value=…] … [/if]

    Uses metadata value from the first layer in the mapfile that belongs to that group

  • [if name=any_web_metadata value=…] … [/if]

  • [if name=layer_queryable value=…] … [/if]

    Added in version 5.6.

    value is the queryability of the first layer in the group: 0=NOT QUERYABLE, 1=QUERYABLE

In a [leg_layer_html] context:

  • [if name=layer_status value=…] … [/if]

    value is the layer’s status in integer format: 0=OFF, 1=ON, 2=DEFAULT

  • [if name=layer_type value=…] … [/if]

    value is the layer’s type in integer format: 0=POINT, 1=LINE, 2=POLYGON, 3=RASTER, 4=ANNOTATION (deprecated since 6.2), 5=QUERY, 6=CIRCLE

  • [if name=layer_name value=…] … [/if]

    value is the layer’s name in string format

  • [if name=layer_group value=…] … [/if]

    value is the layer’s group name in string format

  • [if name=layer_visible value=…] … [/if]

    value is the visibility of the layer: 0=NOT VISIBLE, 1=VISIBLE

  • [if name=any_layer_metadata value=…] … [/if]

  • [if name=any_web_metadata value=…] … [/if]

  • [if name=layer_queryable value=…] … [/if]

    Added in version 5.6.

    value is the queryability of the layer: 0=NOT QUERYABLE, 1=QUERYABLE

In a [leg_class_html] context:

  • [if name=layer_status value=…] … [/if]

    value is the status of the layer in which the class is located

  • [if name=layer_type value=…] … [/if]

    value is the layer’s type in integer format: 0=POINT, 1=LINE, 2=POLYGON, 3=RASTER, 4=ANNOTATION (deprecated since 6.2), 5=QUERY, 6=CIRCLE

  • [if name=layer_name value=…] … [/if]

    value is the layer’s name in string format

  • [if name=layer_group value=…] … [/if]

    value is the layer’s group name in string format

  • [if name=layer_visible value=…] … [/if]

    value is the visibility of the layer: 0=NOT VISIBLE, 1=VISIBLE

  • [if name=class_name value=…] … [/if]

  • [if name=any_layer_metadata value=…] … [/if]

  • [if name=any_web_metadata value=…] … [/if]

  • [if name=layer_queryable value=…] … [/if]

    Added in version 5.6.

    value is the queryability of the layer: 0=NOT QUERYABLE, 1=QUERYABLE

Sample Site Using the HTML Legend

https://demo.mapserver.org/itasca_legend/

This demo is based on the MapServer Itasca demo and contains several variations of HTML Legends, some of which are listed below:

  • “HTML Legend 1” - displays classes only, similar to the traditional legends:

    [leg_class_html opt_flag=15]
       <img src=[leg_icon]> [leg_class_name]<br>
    [/leg_class_html]
    
  • “HTML Legend 2” - displays layer titles with HREF links and classes:

    [leg_layer_html order_metadata=WMS_ORDER visibility_flag=15]
       <a href="[leg_layer_name]">[metadata name=WMS_TITLE]</a><BR>
    [/leg_layer_html]
    
    [leg_class_html visibility_flag=15]
       <img src=[leg_icon]> [leg_class_name]<br>
    [/leg_class_html]
    
  • “HTML Legend 3” - displays layers by group, with checkboxes to turn layers on/off:

    [leg_group_html]
       <tr><td colspan=2><b>[leg_group_name]</b></td></tr>
    [/leg_group_html]
    
    [leg_layer_html order_metadata=WMS_ORDER opt_flag=15]
       <tr>
            <td><input type=checkbox name=layer value=[leg_layer_name]
              [if name=layer_status value=1]CHECKED[/if]>
               [if name=layer_type value=4]
                   <img src=[leg_icon width=22 height=18]>
               [/if]
               [if name=layer_type oper=neq value=4]<img src=[leg_icon]>[/if]
            </td>
            <td>
               <a href="[leg_layer_name]">[metadata name=WMS_TITLE]</a>
            </td>
       </tr>
    [/leg_layer_html]