Skip to content

CartoCSS notes

Mark Tehver edited this page Apr 18, 2019 · 14 revisions

About

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.

Supported CartoCSS parameters

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

Extensions

View-level parameters

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

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.

Metavariables

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].

Additional expressions and operators

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

Interpolation expressions

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

Global options

SDK supports global options for defining map pole colors when using globe view:

Map {
  south-pole-color: #fff;
  north-pole-color: #00f;
}

Differences and incompatibilities

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).

Interpretation of the '%' sign

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.

Interpretation of trailing comma in style selectors

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.

Interpretation of fields and pseudo-fields in expressions

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.

Performance

SDK uses OpenGL as a rendering backend and few features can be unexpectedly expensive due to technical reasons.

Multiple symbolizers per layer

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.

Layer-level effects

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).

Clone this wiki locally