Skip to content

Commit 547d592

Browse files
evil159pjleonard37
andauthored
Layer expression support (#565)
* sfsfsfsfsfs * Add optionalCast util * Fix animated route example crashing * Add default value to GeoJsonSource.data * Generate layer expression properties * Fix typecasting for layer expressions * Add filter and explicit constructor parameter types to Layer class * Fix color decoding * Add optional casting helpers * Add layer expression tests * Add changelog entry * Update lib/src/utils.dart Co-authored-by: Patrick Leonard <pjleonard37@users.noreply.github.com> * Remove commented out code --------- Co-authored-by: Patrick Leonard <pjleonard37@users.noreply.github.com>
1 parent 7fa2f50 commit 547d592

29 files changed

+3285
-648
lines changed

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,30 @@
11
### main
22

33
* Add ModelLayer API.
4+
* Layer expressions support. Specify expressions when constructing a layer with all new expression support for layers.
5+
*Before:*
6+
```dart
7+
mapboxMap.style.setStyleLayerProperty("layer", "line-gradient",
8+
'["interpolate",["linear"],["line-progress"],0.0,["rgb",255,0,0],0.4,["rgb",0,255,0],1.0,["rgb",0,0,255]]');
9+
10+
```
11+
*After:*
12+
```dart
13+
LineLayer(
14+
...
15+
lineGradientExpression: [
16+
"interpolate",
17+
["linear"],
18+
["line-progress"],
19+
0.0,
20+
["rgb", 255, 0, 0],
21+
0.4,
22+
["rgb", 0, 255, 0],
23+
1.0,
24+
["rgb", 0, 0, 255]
25+
],
26+
);
27+
```
428

529
### 2.0.0
630

example/integration_test/style/layer/background_layer_test.dart

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,43 @@ void main() {
3636
expect(layer.backgroundOpacity, 1.0);
3737
expect(layer.backgroundPattern, "abc");
3838
});
39+
40+
testWidgets('Add BackgroundLayer with expressions',
41+
(WidgetTester tester) async {
42+
final mapFuture = app.main();
43+
await tester.pumpAndSettle();
44+
final mapboxMap = await mapFuture;
45+
46+
await mapboxMap.style.addLayer(BackgroundLayer(
47+
id: 'layer',
48+
visibilityExpression: ['string', 'none'],
49+
filter: [
50+
"==",
51+
["get", "type"],
52+
"Feature"
53+
],
54+
minZoom: 1.0,
55+
maxZoom: 20.0,
56+
slot: LayerSlot.BOTTOM,
57+
backgroundColorExpression: ['rgba', 255, 0, 0, 1],
58+
backgroundEmissiveStrengthExpression: ['number', 1.0],
59+
backgroundOpacityExpression: ['number', 1.0],
60+
backgroundPatternExpression: ['image', "abc"],
61+
));
62+
var layer = await mapboxMap.style.getLayer('layer') as BackgroundLayer;
63+
expect(layer.minZoom, 1);
64+
expect(layer.maxZoom, 20);
65+
expect(layer.slot, LayerSlot.BOTTOM);
66+
expect(layer.visibility, Visibility.NONE);
67+
expect(layer.filter, [
68+
"==",
69+
["get", "type"],
70+
"Feature"
71+
]);
72+
expect(layer.backgroundColorExpression, ['rgba', 255, 0, 0, 1]);
73+
expect(layer.backgroundEmissiveStrength, 1.0);
74+
expect(layer.backgroundOpacity, 1.0);
75+
expect(layer.backgroundPatternExpression, ['image', "abc"]);
76+
});
3977
}
4078
// End of generated file.

example/integration_test/style/layer/circle_layer_test.dart

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,69 @@ void main() {
6060
expect(layer.circleTranslate, [0.0, 1.0]);
6161
expect(layer.circleTranslateAnchor, CircleTranslateAnchor.MAP);
6262
});
63+
64+
testWidgets('Add CircleLayer with expressions', (WidgetTester tester) async {
65+
final mapFuture = app.main();
66+
await tester.pumpAndSettle();
67+
final mapboxMap = await mapFuture;
68+
69+
final point = Point(coordinates: Position(-77.032667, 38.913175));
70+
await mapboxMap.style
71+
.addSource(GeoJsonSource(id: "source", data: json.encode(point)));
72+
73+
await mapboxMap.style.addLayer(CircleLayer(
74+
id: 'layer',
75+
sourceId: 'source',
76+
visibilityExpression: ['string', 'none'],
77+
filter: [
78+
"==",
79+
["get", "type"],
80+
"Feature"
81+
],
82+
minZoom: 1.0,
83+
maxZoom: 20.0,
84+
slot: LayerSlot.BOTTOM,
85+
circleSortKeyExpression: ['number', 1.0],
86+
circleBlurExpression: ['number', 1.0],
87+
circleColorExpression: ['rgba', 255, 0, 0, 1],
88+
circleEmissiveStrengthExpression: ['number', 1.0],
89+
circleOpacityExpression: ['number', 1.0],
90+
circlePitchAlignmentExpression: ['string', 'map'],
91+
circlePitchScaleExpression: ['string', 'map'],
92+
circleRadiusExpression: ['number', 1.0],
93+
circleStrokeColorExpression: ['rgba', 255, 0, 0, 1],
94+
circleStrokeOpacityExpression: ['number', 1.0],
95+
circleStrokeWidthExpression: ['number', 1.0],
96+
circleTranslateExpression: [
97+
'literal',
98+
[0.0, 1.0]
99+
],
100+
circleTranslateAnchorExpression: ['string', 'map'],
101+
));
102+
var layer = await mapboxMap.style.getLayer('layer') as CircleLayer;
103+
expect('source', layer.sourceId);
104+
expect(layer.minZoom, 1);
105+
expect(layer.maxZoom, 20);
106+
expect(layer.slot, LayerSlot.BOTTOM);
107+
expect(layer.visibility, Visibility.NONE);
108+
expect(layer.filter, [
109+
"==",
110+
["get", "type"],
111+
"Feature"
112+
]);
113+
expect(layer.circleSortKey, 1.0);
114+
expect(layer.circleBlur, 1.0);
115+
expect(layer.circleColorExpression, ['rgba', 255, 0, 0, 1]);
116+
expect(layer.circleEmissiveStrength, 1.0);
117+
expect(layer.circleOpacity, 1.0);
118+
expect(layer.circlePitchAlignment, CirclePitchAlignment.MAP);
119+
expect(layer.circlePitchScale, CirclePitchScale.MAP);
120+
expect(layer.circleRadius, 1.0);
121+
expect(layer.circleStrokeColorExpression, ['rgba', 255, 0, 0, 1]);
122+
expect(layer.circleStrokeOpacity, 1.0);
123+
expect(layer.circleStrokeWidth, 1.0);
124+
expect(layer.circleTranslate, [0.0, 1.0]);
125+
expect(layer.circleTranslateAnchor, CircleTranslateAnchor.MAP);
126+
});
63127
}
64128
// End of generated file.

example/integration_test/style/layer/fill_extrusion_layer_test.dart

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,89 @@ void main() {
7878
expect(layer.fillExtrusionVerticalGradient, true);
7979
expect(layer.fillExtrusionVerticalScale, 1.0);
8080
});
81+
82+
testWidgets('Add FillExtrusionLayer with expressions',
83+
(WidgetTester tester) async {
84+
final mapFuture = app.main();
85+
await tester.pumpAndSettle();
86+
final mapboxMap = await mapFuture;
87+
88+
await mapboxMap.style.addLayer(FillExtrusionLayer(
89+
id: 'layer',
90+
sourceId: "composite",
91+
sourceLayer: "building",
92+
visibilityExpression: ['string', 'none'],
93+
filter: [
94+
"==",
95+
["get", "type"],
96+
"Feature"
97+
],
98+
minZoom: 1.0,
99+
maxZoom: 20.0,
100+
slot: LayerSlot.BOTTOM,
101+
fillExtrusionEdgeRadiusExpression: ['number', 1.0],
102+
fillExtrusionAmbientOcclusionGroundAttenuationExpression: ['number', 1.0],
103+
fillExtrusionAmbientOcclusionGroundRadiusExpression: ['number', 1.0],
104+
fillExtrusionAmbientOcclusionIntensityExpression: ['number', 1.0],
105+
fillExtrusionAmbientOcclusionRadiusExpression: ['number', 1.0],
106+
fillExtrusionAmbientOcclusionWallRadiusExpression: ['number', 1.0],
107+
fillExtrusionBaseExpression: ['number', 1.0],
108+
fillExtrusionColorExpression: ['rgba', 255, 0, 0, 1],
109+
fillExtrusionCutoffFadeRangeExpression: ['number', 1.0],
110+
fillExtrusionEmissiveStrengthExpression: ['number', 1.0],
111+
fillExtrusionFloodLightColorExpression: ['rgba', 255, 0, 0, 1],
112+
fillExtrusionFloodLightGroundAttenuationExpression: ['number', 1.0],
113+
fillExtrusionFloodLightGroundRadiusExpression: ['number', 1.0],
114+
fillExtrusionFloodLightIntensityExpression: ['number', 1.0],
115+
fillExtrusionFloodLightWallRadiusExpression: ['number', 1.0],
116+
fillExtrusionHeightExpression: ['number', 1.0],
117+
fillExtrusionOpacityExpression: ['number', 1.0],
118+
fillExtrusionPatternExpression: ['image', "abc"],
119+
fillExtrusionRoundedRoofExpression: ['==', true, true],
120+
fillExtrusionTranslateExpression: [
121+
'literal',
122+
[0.0, 1.0]
123+
],
124+
fillExtrusionTranslateAnchorExpression: ['string', 'map'],
125+
fillExtrusionVerticalGradientExpression: ['==', true, true],
126+
fillExtrusionVerticalScaleExpression: ['number', 1.0],
127+
));
128+
var layer = await mapboxMap.style.getLayer('layer') as FillExtrusionLayer;
129+
expect('composite', layer.sourceId);
130+
expect(layer.minZoom, 1);
131+
expect(layer.maxZoom, 20);
132+
expect(layer.slot, LayerSlot.BOTTOM);
133+
expect(layer.visibility, Visibility.NONE);
134+
expect(layer.filter, [
135+
"==",
136+
["get", "type"],
137+
"Feature"
138+
]);
139+
expect(layer.fillExtrusionEdgeRadius, 1.0);
140+
expect(layer.fillExtrusionAmbientOcclusionGroundAttenuation, 1.0);
141+
expect(layer.fillExtrusionAmbientOcclusionGroundRadius, 1.0);
142+
expect(layer.fillExtrusionAmbientOcclusionIntensity, 1.0);
143+
expect(layer.fillExtrusionAmbientOcclusionRadius, 1.0);
144+
expect(layer.fillExtrusionAmbientOcclusionWallRadius, 1.0);
145+
expect(layer.fillExtrusionBase, 1.0);
146+
expect(layer.fillExtrusionColorExpression, ['rgba', 255, 0, 0, 1]);
147+
expect(layer.fillExtrusionCutoffFadeRange, 1.0);
148+
expect(layer.fillExtrusionEmissiveStrength, 1.0);
149+
expect(
150+
layer.fillExtrusionFloodLightColorExpression, ['rgba', 255, 0, 0, 1]);
151+
expect(layer.fillExtrusionFloodLightGroundAttenuation, 1.0);
152+
expect(layer.fillExtrusionFloodLightGroundRadius, 1.0);
153+
expect(layer.fillExtrusionFloodLightIntensity, 1.0);
154+
expect(layer.fillExtrusionFloodLightWallRadius, 1.0);
155+
expect(layer.fillExtrusionHeight, 1.0);
156+
expect(layer.fillExtrusionOpacity, 1.0);
157+
expect(layer.fillExtrusionPatternExpression, ['image', "abc"]);
158+
expect(layer.fillExtrusionRoundedRoof, true);
159+
expect(layer.fillExtrusionTranslate, [0.0, 1.0]);
160+
expect(
161+
layer.fillExtrusionTranslateAnchor, FillExtrusionTranslateAnchor.MAP);
162+
expect(layer.fillExtrusionVerticalGradient, true);
163+
expect(layer.fillExtrusionVerticalScale, 1.0);
164+
});
81165
}
82166
// End of generated file.

example/integration_test/style/layer/fill_layer_test.dart

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,68 @@ void main() {
5959
expect(layer.fillTranslate, [0.0, 1.0]);
6060
expect(layer.fillTranslateAnchor, FillTranslateAnchor.MAP);
6161
});
62+
63+
testWidgets('Add FillLayer with expressions', (WidgetTester tester) async {
64+
final mapFuture = app.main();
65+
await tester.pumpAndSettle();
66+
final mapboxMap = await mapFuture;
67+
68+
var polygon = Polygon(coordinates: [
69+
[
70+
Position(-3.363937, -10.733102),
71+
Position(1.754703, -19.716317),
72+
Position(-15.747196, -21.085074),
73+
Position(-3.363937, -10.733102)
74+
]
75+
]);
76+
await mapboxMap.style
77+
.addSource(GeoJsonSource(id: "source", data: json.encode(polygon)));
78+
79+
await mapboxMap.style.addLayer(FillLayer(
80+
id: 'layer',
81+
sourceId: 'source',
82+
visibilityExpression: ['string', 'none'],
83+
filter: [
84+
"==",
85+
["get", "type"],
86+
"Feature"
87+
],
88+
minZoom: 1.0,
89+
maxZoom: 20.0,
90+
slot: LayerSlot.BOTTOM,
91+
fillSortKeyExpression: ['number', 1.0],
92+
fillAntialiasExpression: ['==', true, true],
93+
fillColorExpression: ['rgba', 255, 0, 0, 1],
94+
fillEmissiveStrengthExpression: ['number', 1.0],
95+
fillOpacityExpression: ['number', 1.0],
96+
fillOutlineColorExpression: ['rgba', 255, 0, 0, 1],
97+
fillPatternExpression: ['image', "abc"],
98+
fillTranslateExpression: [
99+
'literal',
100+
[0.0, 1.0]
101+
],
102+
fillTranslateAnchorExpression: ['string', 'map'],
103+
));
104+
var layer = await mapboxMap.style.getLayer('layer') as FillLayer;
105+
expect('source', layer.sourceId);
106+
expect(layer.minZoom, 1);
107+
expect(layer.maxZoom, 20);
108+
expect(layer.slot, LayerSlot.BOTTOM);
109+
expect(layer.visibility, Visibility.NONE);
110+
expect(layer.filter, [
111+
"==",
112+
["get", "type"],
113+
"Feature"
114+
]);
115+
expect(layer.fillSortKey, 1.0);
116+
expect(layer.fillAntialias, true);
117+
expect(layer.fillColorExpression, ['rgba', 255, 0, 0, 1]);
118+
expect(layer.fillEmissiveStrength, 1.0);
119+
expect(layer.fillOpacity, 1.0);
120+
expect(layer.fillOutlineColorExpression, ['rgba', 255, 0, 0, 1]);
121+
expect(layer.fillPatternExpression, ['image', "abc"]);
122+
expect(layer.fillTranslate, [0.0, 1.0]);
123+
expect(layer.fillTranslateAnchor, FillTranslateAnchor.MAP);
124+
});
62125
}
63126
// End of generated file.

example/integration_test/style/layer/heatmap_layer_test.dart

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,51 @@ void main() {
4545
expect(layer.heatmapRadius, 1.0);
4646
expect(layer.heatmapWeight, 1.0);
4747
});
48+
49+
testWidgets('Add HeatmapLayer with expressions', (WidgetTester tester) async {
50+
final mapFuture = app.main();
51+
await tester.pumpAndSettle();
52+
final mapboxMap = await mapFuture;
53+
54+
await mapboxMap.style.addSource(GeoJsonSource(
55+
id: "source",
56+
data:
57+
"https://www.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson"));
58+
59+
await mapboxMap.style.addLayer(HeatmapLayer(
60+
id: 'layer',
61+
sourceId: 'source',
62+
visibilityExpression: ['string', 'none'],
63+
filter: [
64+
"==",
65+
["get", "type"],
66+
"Feature"
67+
],
68+
minZoom: 1.0,
69+
maxZoom: 20.0,
70+
slot: LayerSlot.BOTTOM,
71+
heatmapColorExpression: ['rgba', 255, 0, 0, 1],
72+
heatmapIntensityExpression: ['number', 1.0],
73+
heatmapOpacityExpression: ['number', 1.0],
74+
heatmapRadiusExpression: ['number', 1.0],
75+
heatmapWeightExpression: ['number', 1.0],
76+
));
77+
var layer = await mapboxMap.style.getLayer('layer') as HeatmapLayer;
78+
expect('source', layer.sourceId);
79+
expect(layer.minZoom, 1);
80+
expect(layer.maxZoom, 20);
81+
expect(layer.slot, LayerSlot.BOTTOM);
82+
expect(layer.visibility, Visibility.NONE);
83+
expect(layer.filter, [
84+
"==",
85+
["get", "type"],
86+
"Feature"
87+
]);
88+
expect(layer.heatmapColorExpression, ['rgba', 255, 0, 0, 1]);
89+
expect(layer.heatmapIntensity, 1.0);
90+
expect(layer.heatmapOpacity, 1.0);
91+
expect(layer.heatmapRadius, 1.0);
92+
expect(layer.heatmapWeight, 1.0);
93+
});
4894
}
4995
// End of generated file.

0 commit comments

Comments
 (0)