Expressions
Every property of a style layer is an Expression<T>, where T is the Dart
type it evaluates to: num, String, bool, Color, Offset, a List or a
spec enum like LineCap. A constant is .literal(x); anything else is computed
by the map from the feature, the zoom level and more. See the
expressions of the style spec
for what each one does.
final layer = CircleStyleLayer(
id: 'quakes',
sourceId: 'quakes',
filter: .all([
.greaterThan(.get('mag').asNumber(), .literal(5)),
.has('place'),
]),
radius: .interpolate(.exponential(2), .zoom(), {
5: .literal(2),
10: .literal(8),
}),
color: .match(
.get('type'),
{'major': const .literal(Color(0xFFFF0000))},
fallback: const .literal(Color(0xFF888888)),
),
);
Dot shorthands need a parameter type to resolve against, so they don't work as
operands of an operator. Start with Expression. there:
Expression.get('mag').asNumber() > .literal(5).
Names
Spec names are kept, except where they clash with Dart keywords or members:
| Spec | Dart |
|---|---|
case |
Expression.select([(test, output), …], fallback: …) |
in |
list.contains(item), string.contains(substring) |
let / var |
Expression.withVariable(name, value, (v) => … v.use() …) |
! |
expression.not() |
==, != |
Expression.equal(a, b), Expression.notEqual(a, b) |
>, <, >=, <= |
Expression.greaterThan(a, b) and so on, or the operators on number and string expressions |
+, -, *, /, % |
operators on number expressions; + on string expressions is concat |
^ |
base.pow(exponent) |
typeof |
expression.type() |
string, number, boolean, object, array |
asString(), asNumber(), asBoolean(), asObject(), asArray<E>() |
to-string, to-number, to-boolean, to-color |
convertToString(), convertToNumber(), convertToBoolean(), convertToColor() |
Untyped values such as .get('x') are Expression<Object?>. Assert their type
before use with asNumber() and the like, or change only the static type with
cast<R>().
Expression.raw(['get', 'x']) takes the JSON of the style spec, for anything
not covered.
Layers on the map
A layer you added, or one from style.layers, is its own controller. Its setters
update the map without waiting for it, in order, so an animation can call them
every frame:
final line = style.layers['route']! as LineStyleLayer;
line.width = const .literal(4);
line.visible = false;
line.width = null; // back to the default
line.moveBelow('labels');
Getters return the value that is set or the default of the spec. A constant
reads back as a Literal:
if (line.width case Literal(:final value)) print(value);
Everything else reads back as an Expression.raw. Removing the layer or loading
a new style detaches the object; its setters then only change the object.
A property with a transition has a typed one next to it, such as
line.colorTransition = const StyleTransition(duration: Duration(seconds: 1)).
To show several changes in one frame on native maps, use a batch. The callback must be synchronous:
style.batch(() {
line.visible = true;
style.layers.move('route', belowLayerId: 'labels');
});