-
Notifications
You must be signed in to change notification settings - Fork 68
CartoCSS notes
These notes are intended to clarify how Carto Mobile SDK implements the CartoCSS styling language. The notes assume good understanding of the CartoCSS specification and cover various aspects specific to the SDK.
SDK supports the following parameters from the CartoCSS specification:
Symbolizer | Parameter |
---|---|
line | line-color |
line-opacity | |
line-width | |
line-dasharray | |
line-join | |
line-cap | |
line-geometry-transform | |
line-comp-op | |
line-pattern | line-pattern-file |
line-pattern-fill | |
line-pattern-opacity | |
line-pattern-geometry-transform | |
line-pattern-comp-op | |
polygon | polygon-fill |
polygon-opacity | |
polygon-geometry-transform | |
polygon-comp-op | |
polygon-pattern | polygon-pattern-file |
polygon-pattern-fill | |
polygon-pattern-opacity | |
polygon-pattern-geometry-transform | |
polygon-pattern-comp-op | |
point | point-file |
point-opacity | |
point-allow-overlap | |
point-ignore-placement | |
point-transform | |
point-comp-op | |
text | text-name |
text-face-name | |
text-placement | |
text-size | |
text-spacing | |
text-fill | |
text-opacity | |
text-halo-fill | |
text-halo-opacity | |
text-halo-radius | |
text-halo-rasterizer | |
text-allow-overlap | |
text-min-distance | |
text-transform | |
text-orientation | |
text-dx | |
text-dy | |
text-avoid-edges | |
text-wrap-width | |
text-wrap-before | |
text-character-spacing | |
text-line-spacing | |
text-horizontal-alignment | |
text-vertical-alignment | |
text-comp-op | |
shield | shield-name |
shield-face-name | |
shield-file | |
shield-dx | |
shield-dy | |
shield-unlock-image | |
shield-placement | |
shield-size | |
shield-spacing | |
shield-fill | |
shield-text-opacity | |
shield-halo-fill | |
shield-halo-opacity | |
shield-halo-radius | |
shield-halo-rasterizer | |
shield-allow-overlap | |
shield-min-distance | |
shield-text-transform | |
shield-orientation | |
shield-text-dx | |
shield-text-dy | |
shield-avoid-edges | |
shield-wrap-width | |
shield-wrap-before | |
shield-character-spacing | |
shield-line-spacing | |
shield-horizontal-alignment | |
shield-vertical-alignment | |
shield-comp-op | |
marker | marker-file |
marker-placement | |
marker-type | |
marker-opacity | |
marker-fill | |
marker-fill-opacity | |
marker-width | |
marker-height | |
marker-line-color | |
marker-line-opacity | |
marker-line-width | |
marker-spacing | |
marker-allow-overlap | |
marker-ignore-placement | |
marker-transform | |
marker-comp-op | |
building | building-fill |
building-fill-opacity | |
building-height | |
building-min-height | |
building-geometry-transform |
In addition, SDK support layer-level 'opacity' and limited set of 'comp-op' options. The following table lists the supported 'comp-op' values:
Comp-op |
---|
src |
src-over |
src-in |
src-atop |
dst |
dst-over |
dst-in |
dst-atop |
clear,zero |
plus |
minus |
multiply |
screen |
darken |
lighten |
Most of the CartoCSS parameters are evaluated during tile loading ('loading domain'), but some parameters are evaluated during each frame ('rendering domain').
A typical example of view-level expression includes [view::zoom]
parameter, for example:
line-width: [view::zoom] * 0.2;
The list of all parameters that are evaluated in rendering domain:
Symbolizer | Parameter |
---|---|
line | line-color |
line-opacity | |
line-width | |
line-pattern | line-pattern-fill |
line-pattern-opacity | |
polygon | polygon-fill |
polygon-opacity | |
polygon-pattern | polygon-pattern-fill |
polygon-pattern-opacity | |
point | point-opacity |
marker | marker-width |
marker-height | |
marker-line-width | |
text | text-size |
text-fill | |
text-opacity | |
text-halo-fill | |
text-halo-opacity | |
text-halo-radius | |
shield | shield-size |
shield-fill | |
shield-text-opacity | |
shield-halo-fill | |
shield-halo-opacity | |
shield-halo-radius | |
building | building-fill |
building-fill-opacity |
When a view-level expression is used for a parameter not in this table, its value is replaced with a reasonable default and the expression is evaluated during tile loading time.
For example, [view::zoom]
is replaced with [zoom] + 0.5
. This gives forward compatibility, if more parameters will be converted to view-level parameters.
Nutiparameters are typed parameters that can be controlled from the application. This allows certain aspects of the styles to be controlled by the application. Typical examples include showing certain POIs, selecting map language and so on. Nutiparameters can be accessed from the style by using 'nuti::' prefix. For example:
line-color: [nuti::color];
Here parameter 'color' is defined by the application.
SDK supports dynamic field names. Dynamic field names are specified using an expression enclosed in square or curly brackets. For example:
text-name: [name_[nuti::lang]];
Here the field used for text names depends on the nutiparameter called 'lang'. If its value is 'en', then this expression is equivalent to [name_en]
.
SDK supports following operators in parameter values (in the order of precedence):
Operator |
---|
.length, .uppercase, .lowercase, .capitalize, .concat, .replace, .match |
unary -, unary ! |
*, / |
+, - |
=~, =, !=, <=, <, >=, > |
&&, || |
?: |
For example, the following expression can be used for language-selection based on nutiparameter named 'lang':
text-name: [name_[nuti::lang]] ? [name_[nuti::lang]] : [name];
In addition to the operators listed above, the following functions are supported:
Function |
---|
exp |
log |
pow |
step |
linear |
cubic |
SDK contains three special functions for key/value interpolation called step
, linear
and cubic
. The first one provides 'constant' interpolation, or simply a table lookup, the second one provides linear interpolation between two nearest key values and the last one provides cubic interpolation with 2nd order continuity. The most useful is linear interpolation. For example:
line-width: linear([x], (2, 1), (3, 2), (5, 8));
The following table demonstrates the values this expression produces depending on the value of [x]
:
x | Value |
---|---|
<=2 | 1 |
2.5 | 1.5 |
3 | 2 |
4 | 5 |
>=5 | 8 |
SDK supports global options for defining map pole colors when using globe view:
Map {
south-pole-color: #fff;
north-pole-color: #00f;
}
Carto Mobile SDK uses 'from scratch' implementation of the CartoCSS styling language and interprets few aspects of the styling differently compared to the MapBox Studio Classic (shorthand MBSC).
The following line is interpreted differently in the SDK vs MBSC:
line-width: mix(#fff, #000, 50);
While the following line works in both implementations:
line-width: mix(#fff, #000, 50%);
MBSC interprets %-sign as an optional 'unit' while SDK treats this as a multiplicator with value of 1/100. The interpretation of SDK is consistent across all values and functions while the MBSC interpretation depends on the context and does not work everywhere. It is recommended to always add explicit % suffix to the functions that mix or modify colors. This makes the expressions compatible with both SDK and MBSC.
The trailing comma after '#layer0' in the following example causes different interpretation of the style in the SDK vs MBSC:
#layer0, {
line-width: 1;
}
MBSC ignores the trailing command while SDK interprets the command as a separator and assumes that the rules applies to elements of layer named 'layer0' and to all other elements. A simple fix is to remove all trailing commas from selectors to make the behavior consistent.
The following expression results in different output in SDK vs MSBC:
marker-width: ([scalerank]-1)*5;
SDK handles this as expected while MSBC provides very strange result. This seems to be a limitation in MSBC CartoCSS parser or CartoCSS -> MapnikXML translator. If compatibility
between SDK and MSBC is required, complex expressions involving fields and pseudo-fields like [zoom]
should be avoided.
SDK uses OpenGL as a rendering backend and few features can be unexpectedly expensive due to technical reasons.
The following example uses 'polygon-pattern' and 'polygon' symbolizers:
#layer {
polygon-pattern-file: url('pattern.png');
polygon-fill: #fff;
}
If the layer contains many polygons (over a thousand) this results in lots of OpenGL draw calls and will most likely drop the rendering rate to a 1 frame per second. There are few special cases that are optimized and are not affected by this: SDK supports batching 'line' and 'line-pattern' symbolizers and 'line' and 'polygon' symbolizers.
Both layer-level 'comp-op' and 'opacity' require drawing to a separate frame buffer and full viewport blending, thus making these operations very expensive especially on high-resolution devices. If possible, element-level 'comp-op' and 'opacity' should be used ('polygon-opacity', for example).