When mapping a road network, the display order is important as we don’t want the main roads to be cut by secondary roads.
Unexpected result:

Expected result:

The display order depends on many factors. This article explains the behavior of MapServer when rendering features so that you can create clean maps with all features displayed in the right order. Note that some of the rules explained here only apply to LINE type LAYER objects.
1) Read first - drawn first
The first thing to consider when trying to display features in a specific order is the order in which the source data is read by MapServer. In a LAYER, the first feature encountered by MapServer is drawn first, then the next one will be drawn on top of it and so on. This is regardless of the CLASS rendering it and its position, which means that the source data should be sorted. For example, in PostGIS, the data can be sorted according to a ‘z-index’ attribute (z_order in OpenStreetMap) and the length of each line.
DATA "geometry from (select osm_id, geometry, name, type
from osm_roads
where type in ('secondary', 'tertiary', 'residential')
order by z_order asc, st_length(geometry) asc)
as foo using unique osm_id using srid=900913"
When mapping ‘shapefiles’, the sortshp tool might be very useful.
NOTE: This rule applies to any type of layer
2) Number of STYLE objects inside the CLASS
The number of STYLE objects found inside a CLASS affects the display order. Inside a given LAYER, the first STYLE of each CLASS is processed and rendered, then MapServer proceeds to the second STYLE of each CLASS and so on.
3) Outline first
When the first STYLE object of a given CLASS contains a OUTLINEWIDTH, the outlines of each class are drawn before the feature’s interior. This has been true since MapServer 5.4 and it is documented in the RFC-49.
Unexpected result:

Expected result:

Incorrect mapfile example:
CLASS # secondary roads
EXPRESSION /secondary/
STYLE
WIDTH 12
COLOR 255 0 0 # red
OUTLINEWIDTH 2
OUTLINECOLOR 153 111 57 # brown
END
STYLE
WIDTH 11
COLOR 223 197 124 # orange
END
END
CLASS # tertiary roads
EXPRESSION /tertiary/
STYLE
WIDTH 11
OUTLINEWIDTH 1
OUTLINECOLOR 193 188 157 # gray
COLOR 255 253 139 # yellow
END
END
CLASS # residential roads
STYLE
WIDTH 11
OUTLINEWIDTH 1
OUTLINECOLOR 103 181 157 # green
END
STYLE
WIDTH 11
COLOR 238 225 226 # pink
END
END
Considering that the source data has been sorted in that order: residential, tertiary, secondary, the display order is the following:
- Residential roads’ outline(green)
- Tertiary roads’ outline (gray)
- Secondary roads’ outline (brown)
- Residential roads’ first style (outline only)
- Tertiary roads’ only style (yellow)
- Secondary roads’ first style (red)
- Residential roads’ second style (pink)
- Secondary roads’ second style (orange)
The problems:
- The red outline of the secondary roads crosses the yellow lines. Note that the red outline is not an actual outline but a STYLE with a COLOR tag and a WIDTH tag greater than that of the second STYLE.
- The pink lines’ interior are drawn over the yellow lines instead of being drawn below.
- The pink lines’ interior are drawn over the red lines.
Correct mapfile example:
CLASS # secondary roads
EXPRESSION /secondary/
STYLE
WIDTH 12
COLOR 255 0 0 # red
OUTLINEWIDTH 2
OUTLINECOLOR 153 111 57 # brown
END
STYLE
WIDTH 11
COLOR 223 197 124 # orange
END
END
CLASS # tertiary roads
EXPRESSION /tertiary/
STYLE
WIDTH 11
OUTLINEWIDTH 1
OUTLINECOLOR 193 188 157 # gray
END
STYLE
WIDTH 11
COLOR 255 253 139 # yellow
END
END
CLASS # residential roads
STYLE
WIDTH 11
OUTLINEWIDTH 1
OUTLINECOLOR 103 181 157 # green
END
STYLE
WIDTH 11
COLOR 238 225 226 # pink
END
END
NOTE: This article was originally posted in French on Simon Mercier’s blog