All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mapfish.print.map.style.json.MapfishStyleParserPlugin Maven / Gradle / Ivy

There is a newer version: 3.22.0
Show newest version
package org.mapfish.print.map.style.json;

import org.geotools.styling.Style;
import org.geotools.styling.StyleBuilder;
import org.json.JSONObject;
import org.mapfish.print.Constants;
import org.mapfish.print.ExceptionUtils;
import org.mapfish.print.config.Configuration;
import org.mapfish.print.map.style.ParserPluginUtils;
import org.mapfish.print.map.style.SLDParserPlugin;
import org.mapfish.print.map.style.StyleParserPlugin;
import org.mapfish.print.wrapper.json.PJsonObject;
import org.springframework.http.client.ClientHttpRequestFactory;

import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import static org.mapfish.print.map.style.json.MapfishJsonStyleVersion1.DEFAULT_GEOM_ATT_NAME;

/**
 * Supports all style format.
 * 

* This style parser support two versions of JSON and SLD formatting. Both versions use the same parameter * names for configuring the values of the various properties of the style but the layout differs between the * two and version 2 is more flexible and powerful than version 1. *

*

Mapfish JSON Style Version 1

*

* Version 1 is compatible with mapfish print <= v2 and is based on the OpenLayers v2 styling. The layout * is as follows: *

*

 * {
 *   "version" : "1",
 *   "styleProperty":"_gx_style",
 *   "1": {
 *     "fillColor":"#FF0000",
 *     "fillOpacity":0,
 *     "rotation" : "30",
 *
 *     "externalGraphic" : "mark.png"
 *     "graphicName": "circle",
 *     "graphicOpacity": 0.4,
 *     "pointRadius": 5,
 *
 *     "strokeColor":"#FFA829",
 *     "strokeOpacity":1,
 *     "strokeWidth":5,
 *     "strokeLinecap":"round",
 *     "strokeDashstyle":"dot",
 *
 *     "fontColor":"#000000",
 *     "fontFamily": "sans-serif",
 *     "fontSize": "12px",
 *     "fontStyle": "normal",
 *     "fontWeight": "bold",
 *     "haloColor": "#123456",
 *     "haloOpacity": "0.7",
 *     "haloRadius": "3.0",
 *     "label": "${name}",
 *     "labelAlign": "cm",
 *     "labelRotation": "45",
 *     "labelXOffset": "-25.0",
 *     "labelYOffset": "-35.0"
 *    }
 * }
 * 
*

*

Mapfish JSON Style Version 2

*

* Version 2 uses the same property names as version 1 but has a different structure. The layout is as * follows: *

*

 * {
 *   "version" : "2",
 *   // shared values can be declared here (at top level)
 *   // and used in form ${constName} later in json
 *   "val1" : "#FFA829",
 *   // default values for properties can be defined here
 *   " strokeDashstyle" : "dot"
 *   "[population > 300]" : {
 *     // default values for current rule can be defined here
 *     // they will override default values defined at
 *     // higher level
 *     "rotation" : "30",
 *
 *     //min and max scale denominator are optional
 *     "maxScale" : 1000000,
 *     "minScale" : 100000,
 *     "symbolizers" : [{
 *       // values defined in symbolizer will override defaults
 *       "type" : "point",
 *       "fillColor":"#FF0000",
 *       "fillOpacity":0,
 *       "rotation" : "30",
 *       "externalGraphic" : "mark.png",
 *
 *       "graphicName": "circle",
 *       "graphicOpacity": 0.4,
 *       "pointRadius": 5,
 *
 *       "strokeColor":"${val1}",
 *       "strokeOpacity":1,
 *       "strokeWidth":5,
 *       "strokeLinecap":"round",
 *       "strokeDashstyle":"dot"
 *     }, {
 *       "type" : "line",
 *       "strokeColor":"${val1}",
 *       "strokeOpacity":1,
 *       "strokeWidth":5,
 *       "strokeLinecap":"round",
 *       "strokeDashstyle":"dot"
 *     }, {
 *       "type" : "polygon",
 *       "fillColor":"#FF0000",
 *       "fillOpacity":0,
 *
 *       "strokeColor":"${val1}",
 *       "strokeOpacity":1,
 *       "strokeWidth":5,
 *       "strokeLinecap":"round",
 *       "strokeDashstyle":"dot"
 *     }, {
 *       "type" : "text",
 *       "fontColor":"#000000",
 *       "fontFamily": "sans-serif",
 *       "fontSize": "12px",
 *       "fontStyle": "normal",
 *       "fontWeight": "bold",
 *       "haloColor": "#123456",
 *       "haloOpacity": "0.7",
 *       "haloRadius": "3.0",
 *       "label": "[name]",
 *       "fillColor":"#FF0000",
 *       "fillOpacity":0,
 *       "labelAlign": "cm",
 *       "labelRotation": "45",
 *       "labelXOffset": "-25.0",
 *       "labelYOffset": "-35.0"
 *     }
 *   ]}
 * }
 * 
*

* As illustrated above the style consists of: *

*
    *
  • The version number (2) (required)
  • *
  • * Common values which can be referenced in symbolizer property values.(optional) *

    Values can be referenced in the value of a property with the pattern: ${valName}

    *

    Value names can only contain numbers, characters, _ or -

    *

    * Values do not have to be the full property they will be interpolated. For example: * The value is ${val} *

    *
  • *
  • * Defaults property definitions(optional): *

    * In order to reduce duplication and keep the style definitions small, default values can be specified. The * default values in the root (style level) will be used in all symbolizers if the value is not defined. The * style level default will apply to all symbolizers defined in the system. *

    *

    * The only difference between a value and a default is that the default has a well known name, therefore * defaults can also be used as values. *

    *
  • *
  • * All the styling rules (At least one is required) *

    * A styling rule has a key which is the filter which selects the features that the rule will be used to draw * and the rule definition object. *

    *

    The filter is either * or an * * ECQL Expression) surrounded by square brackets. For example: [att < 23]. *

    *

    * WARNING: At the moment DWITHIN and BEYOND spatial functions take a unit parameter. * However it is ignored by geotools and the distance is always in the crs of the geometry projection. *

    * The rule definition is as follows: *
      *
    • * Default property values (optional): *

      * Each rule can also have defaults. If the style and the rule have a default for the same property the rule * will override the style default. All defaults can be (of course) overridden by a value in a symbolizer. *

      *
    • *
    • * minScale (optional) *

      * The minimum scale that the rule should evaluate to true *

      *
    • *
    • * maxScale (optional) *

      * The maximum scale that the rule should evaluate to true *

      *
    • *
    • * An array of symbolizers. (at least one required). *

      * A symbolizer must have a type property (point, line, polygon, text) which indicates the type of symbolizer * and it has the attributes for that type of symbolizer. All values have defaults so it is possible to * define a symbolizer as with only the type property. The only exception is that the "text" symbolizer needs * a label property. *

      *
    • *
    *
  • *
*

*

Configuration Elements

* The items in the list below are the properties that can be set on the different symbolizers. In brackets * list the symbolizers the values can apply to. *

* Most properties can be static values or ECQL expressions. If the property has [ ] around the * property value then it will be interpreted as an ECQL expression. Otherwise it is assumed to be static * text. If you need static text that start and ends with [ ] then you will have to enter: * ['propertyValue'] (where propertyValue start and ends with [ ]. *

*

* The items below with (ECQL) can have ECQL expressions. *

*
    *
  • fillColor(ECQL) - (polygon, point, text) The color used to fill the point * graphic, polygon or text.
  • *
  • fillOpacity(ECQL) - (polygon, point, text) The opacity used when fill the * point graphic, polygon or text.
  • *
  • rotation(ECQL) - (point) The rotation of the point graphic
  • *
  • * externalGraphic - (point) one of the two options for declaring the point * graphic to use. This can be a URL to the icon to use or, if just a string it will be assumed to refer to a * file in the configuration directory (or subdirectory). Only files in the configuration directory (or * subdirectory) will be allowed. *
  • *
  • * graphicName(ECQL) - (point) one of the two options for declaring the point * graphic to use. This is the default and will be a square if not specified. The option are any of the * Geotools Marks. *

    Geotools has by default 3 types of marks:

    *
      *
    • WellKnownMarks: cross, star, triangle, arrow, X, hatch, square
    • *
    • ShapeMarks: shape://vertline, shape://horline, shape://slash, shape://backslash, * shape://dot, shape://plus, shape://times, shape://oarrow, shape://carrow, shape://coarrow, * shape://ccarrow
    • *
    • TTFMarkFactory: ttf://fontName#code (where fontName is a TrueType font and the code is * the code number of thecharacter to render for the point.
    • *
    *
  • *
  • graphicOpacity(ECQL) - (point) the opacity to use when drawing the point * graphic
  • *
  • pointRadius(ECQL) - (point) the size at which to draw the point graphic
  • *
  • * strokeColor(ECQL) - (line, point, polygon) the color to use when drawing a line * or the outline of a polygon or point graphic *
  • *
  • strokeOpacity(ECQL) - (line, point, polygon) the opacity to use when drawing * the line/stroke
  • *
  • strokeWidth(ECQL) - (line, point, polygon) the widh of the line/stroke
  • *
  • * strokeLinecap(ECQL) - (line, point, polygon) the style used when drawing the * end of a line. *

    * Options: butt (sharp square edge), round (rounded edge), and square (slightly elongated square edge). * Default is butt *

    *
  • *
  • * strokeDashstyle - (line, point, polygon) A string describing how to draw the * line or an array of floats describing the line lengths and space lengths: *
      *
    • dot - translates to dash array: [0.1, 2 * strokeWidth]
    • *
    • dash - translates to dash array: [2 * strokeWidth, 2 * strokeWidth]
    • *
    • dashdot - translates to dash array: [3 * strokeWidth, 2 * strokeWidth, 0.1, 2 * * strokeWidth]
    • *
    • longdash - translates to dash array: [4 * strokeWidth, 2 * strokeWidth]
    • *
    • longdashdot - translates to dash array: [5 * strokeWidth, 2 * strokeWidth, 0.1, 2 * * strokeWidth]
    • *
    • {string containing spaces to delimit array elements} - Example: [1 2 3 1 2]
    • *
    *
  • *
  • fontColor(ECQL) - (text) the color of the text drawn
  • *
  • fontFamily(ECQL) - (text) the font of the text drawn
  • *
  • fontSize(ECQL) - (text) the font size of the text drawn
  • *
  • fontStyle(ECQL) - (text) the font style of the text drawn
  • *
  • fontWeight(ECQL) - (text) the font weight of the text drawn
  • *
  • haloColor(ECQL) - (text) the color of the halo around the text
  • *
  • haloOpacity(ECQL) - (text) the opacity of the halo around the text
  • *
  • haloRadius(ECQL) - (text) the radius of the halo around the text
  • *
  • * label(ECQL) - (text) the expression used to create the label e. See the * section on labelling for more details *
  • *
  • * labelAlign - (Point Placement) the indicator of how to align the text with * respect to the geometry. This property must have 2 characters, the x-align and the y-align. *

    * X-Align options: *

    *
      *
    • l - align to the left of the geometric center
    • *
    • c - align on the center of the geometric center
    • *
    • r - align to the right of the geometric center
    • *
    *

    * Y-Align options: *

    *
      *
    • b - align to the bottom of the geometric center
    • *
    • m - align on the middle of the geometric center
    • *
    • t - align to the top of the geometric center
    • *
    *
  • * *
  • labelRotation(ECQL) - (Point Placement) the rotation of the label
  • *
  • labelXOffset(ECQL) - (Point Placement) the amount to offset the label along the * x axis. negative number offset to the left
  • *
  • labelYOffset(ECQL) - (Point Placement) the amount to offset the label along the * y axis. negative number offset to the top of the printing
  • *
  • labelAnchorPointX(ECQL) - (Point Placement) The point along the x axis that the * label is started at anchored). Offset and rotation is relative to this point. Only one of * labelAnchorPointX/Y or labelAlign will be respected, since they are both ways of defining the anchor * Point
  • *
  • labelAnchorPointY(ECQL) - (Point Placement) The point along the y axis that the * label is started at (anchored). Offset and rotation is relative to this point. Only one of * labelAnchorPointX/Y or labelAlign will be respected, since they are both ways of defining the anchor * Point
  • *
  • labelPerpendicularOffset(ECQL) - (Line Placement) If this property is defined * it will be assumed that the geometry is a line and this property defines how far from the center of the * line the label should be drawn.
  • *
*

*

Labelling:

*

* Labelling in this style format is done by defining a text symbolizer ("type":"text"). All text symbolizers * consist of: *

* * *

Label Property

*

* The label property defines what label will be drawn for a given feature. The value is either a string * which will be the static label for all features that the symbolizer will be drawn on or a string surrounded * by [] which indicates that it is an ECQL Expression. Examples: *

*
    *
  • Static label
  • *
  • [attributeName]
  • *
  • ['Static Label Again']
  • *
  • [5]
  • *
  • 5
  • *
  • env('java.home')
  • *
  • centroid(geomAtt)
  • *
* *

Halo Properties

*

* A halo is a space around the drawn label text that is color (using the halo properties). A label with a * halo is like the drawn label text with a buffer around the label text drawn using the halo properties. This * allows the label to be clearly visible regardless of the background. For example if the text is black and * the halo is with, then the text will always be readable thanks to the white buffer around the label text. *

* *

Font/weight/style/color/opacity *

*

* The Font/weight/style/color/opacity properties define how the label text is drawn. They are for the most * part equivalent to the similarly named css and SLD properties. *

* *

Placement Properties *

*

* An important part of defining a text symbolizer is defining where the text/label will be drawn. The * placement properties are used for this purpose. There are two types of placements, Point and Line * placement and only one type of placement can be used. The type of placement is determined by * inspecting the properties in the text symbolizer and if the labelPerpendicularOffset property is * defined then a line placement will be created for the text symbolizer. *

*

* It is important to realize that since only one type of placement can be used, an error will be reported if * labelPerpendicularOffset is defined in the text symbolizer along with * any of the point placement properties. *

*

Point Placement

*

* Point placement defines an anchor point which is the point to draw the text relative to. For * example an anchor point of 0.5, 0.5 ("labelAnchorPointX" : "0.5", "labelAnchorPointY" : "0.5") would * position the start of the label at the center of the geometry. *

*

* After anchor point, comes displacement displacement defines the distance from the anchor * point to start the label. The combination of the two values determines the final location of the label. *

*

Lastly, there is a label rotation which defines the orientation of the label.

*

* There are two ways to define the anchor point, either the labelAnchorPointX/Y properties are set * or the labelAlign property is set. If both are defined then the * labelAlign will be ignored. *

* *

Vendor Options

*

For text symbolizers the following vendor options are available:

*
    *
  • allowOverruns (false): When false does not allow labels on lines to get beyond the * beginning/end of the line. By default a partial overrun is tolerated, set to false to disallow it. *
  • *
  • autoWrap (400): Number of pixels are which a long label should be split into * multiple lines. Works on all geometries, on lines it is mutually exclusive with the followLine option. *
  • *
  • conflictResolution (true): Enables conflict resolution (default, true) meaning no * two labels will be allowed to overlap. Symbolizers with conflict resolution off are considered outside of * the conflict resolution game, they don’t reserve area and can overlap with other labels. *
  • *
  • followLine (true): When true activates curved labels on linear geometries. The * label will follow the shape of the current line, as opposed to being drawn a tangent straight line *
  • *
  • goodnessOfFit (90): Sets the percentage of the label that must sit inside the * geometry to allow drawing the label. Works only on polygons. *
  • *
  • group (false): If true, geometries with the same labels are grouped and considered * a single entity to be labelled. This allows to avoid or control repeated labels. *
  • *
  • maxDisplacement (400): The distance, in pixel, a label can be displaced from its * natural position in an attempt to find a position that does not conflict with already drawn labels. *
  • *
  • spaceAround (50): The minimum distance between two labels, in pixels.
  • *
*

Example

*

 * {
 *   "version" : "2",
 *   "*" : {
 *     "symbolizers" : [{
 *       "type" : "text",
 *       "fontColor":"#000000",
 *       "label": "[name]",
 *       "goodnessOfFit": 0.1,
 *       "spaceAround": 10
 *     }
 *   ]}
 * }
 * 
*

For more information, please refer to the * GeoTools * documentation. *

*

*

ECQL references:

* */ public final class MapfishStyleParserPlugin implements StyleParserPlugin { static final String JSON_VERSION = "version"; private StyleBuilder sldStyleBuilder = new StyleBuilder(); @Override public Optional