-
Notifications
You must be signed in to change notification settings - Fork 1
GSIP 173
Note: this is a new version of the abandoned GSIP 81, updated to be more strictly a legend, use the GeoServer facilities made available in the meantime, and generate a more compact output.
GeoServer should be able to generate a JSON representation of a legend that can be used client side to lay out a nice looking legend.
Andrea Aime
This proposal is for GeoServer 2.15-beta.
A server side generated legend graphic might not fit properly in the client user interface, is not dynamic, and may be layed out in a unsuitable way. A JSON description of the legend would allow clients to achieve deeper, seamless integration with the rest of the user interface/user experience.
The overall JSON structure would look as follows:
{
"Legend": [
{
"title": "Default",
"symbolyzers": [
{
"Polygon": {
"stroke": "#c0c0c0",
"stroke-dasharray": [
2,
2
],
"stroke-dashoffset": 10
}
}
]
}
}
The basic JSON structure is a Legend
object containing an array of Rule
objects (also see examples section at the end of the document).
Each Rule
object has a title
(to be shown in the legend), a filter
, a z-order
(derived from the current FeatureTypeStyle order, used to determine where the rule stacks up), and an array of symbolizers. The rule does not have a min/max scale denominator, as those should have been filtered during the GetLegendGraphic request, indicating the current scale.
Each Symbolizer
has a type (Line
, Point
, Polygon
, Text
, Raster
) and contains the visual properties of the corresponding SLD visual object, using as JSON property name the same name as the corresponding CSSProperty. For other properties, in case of doubt, the GeoCSS property names will be used.
Properties that have no visual value, such as the symbolizer geometry or most vendor options (e.g., label priority, label placement), are not going to be included.
Filters, as well as any property depending on feature attributes, will be encoded as a CQL expression, and written as a string between square brackets, e.g.:
"filter": "[total_usd_percapita <= 1000000]"
"rotation": "[myAngleAttribute]"
The point symbology can be complex to represent in JSON.
In general, all point symbolizer, graphic strokes, fill strokes will have a url
property where they can retrieve the symbol in question, along with a size
and a rotation
property for eventual re-scaling.
The url
is going to be always backed by the existing KML IconService
, which is going to be moved to the WMS module for re-use. The classes in that module also provide facilities for extracting the necessary properties from the style and build the URL.
In addition to that, simple external graphic will also have a external-graphic-url
property pointing to the external graphic, and a external-graphic-type
reporting the type of referenced image, just like in SLD.
Finally, for marks a mark
property with the mark name will be provided, along with fill and stroke related properties to allow rebuilding the simplest symbols on the client side too, e.g.:
{
"type": "Point",
"mark": "square",
"fill": "0xFF0000",
"stroke": "0x0000",
"stroke-width": 1,
"url": "http://cloudsdi.geo-solutions.it:80/geoserver/kml/icon/point?0.0.0=",
"Size": 32
}
{
"type": "Point",
"external-graphic-url": "http://myserver/icon.png",
"external-graphic-type": "image/png",
"url": "http://cloudsdi.geo-solutions.it:80/geoserver/kml/icon/point?0.0.0=",
"size": 32
}
Example GetLegendGraphic
call:
http://localhost:8080/geoserver/sf/wms?service=WMS&version=1.1.0&request=GetLegendGraphic&layer=sf:sfdem&styles=&bbox=589980.0,4913700.0,609000.0,4928010.0&width=512&height=385&srs=EPSG:26713&format=application/json&outputFormat=application/json
Raster colormap example output:
{
"Legend": [
{
"title": "This is the rule title",
"symbolyzers": [
{
"type": "Raster",
"colormap": {
"entries": [
{
"label": "nodata",
"opacity": "0.0",
"quantity": "-500",
"color": "#000000"
},
{
"label": "values",
"opacity": null,
"quantity": "0",
"color": "#AAFFAA"
},
{
"label": null,
"opacity": null,
"quantity": "1000",
"color": "#00FF00"
},
{
"label": "values",
"opacity": null,
"quantity": "1200",
"color": "#FFFF00"
},
{
"label": "values",
"opacity": null,
"quantity": "1400",
"color": "#FF7F00"
},
{
"label": "values",
"opacity": null,
"quantity": "1600",
"color": "#BF7F3F"
},
{
"label": "values",
"opacity": null,
"quantity": "2000",
"color": "#000000"
}
]
}
}
]
}
]
}
Categorized vector data example
{
"Legend": [
{
"title": "Default",
"symbolyzers": [
{
"Polygon": {
"stroke": "#c0c0c0",
"stroke-dasharray": [
2,
2
],
"stroke-dashoffset": 10
}
}
]
},
{
"title": "low",
"filter": "[total_usd_percapita <= 1000000]",
"symbolyzers": [
{
"Polygon": {
"fill-opacity": 0.5,
"fill": "#00ff00"
}
}
]
},
{
"title": "mid",
"filter": "[total_usd_percapita > 1000000 AND total_usd_percapita <= 10000000]",
"symbolyzers": [
{
"Polygon": {
"fill-opacity": 0.5,
"fill": "#ff0000"
}
}
]
},
{
"title": "high",
"filter": "[total_usd_percapita > 1000000]",
"symbolyzers": [
{
"Polygon": {
"fill-opacity": 0.5,
"fill": "#0000ff"
}
}
]
}
]
}
The legend is generated from the style by means of filtering and pre-processing the style. The pre-processing is present in the BufferedImageLegendGraphicBuilder, and should possibly be extracted in a separate class (might be a base class or an external worker class, which ultimately returns a list of Rule objects).
- Under Discussion
- In Progress
- Completed
- Rejected
- Deferred
Project Steering Committee:
- Alessio Fabiani:
- Andrea Aime:
- Ben Caradoc-Davies:
- Brad Hards:
- Ian Turton:
- Jody Garnett: +1
- Jukka Rahkonen:
- Kevin Smith:
- Simone Giannecchini:
©2020 Open Source Geospatial Foundation