Skip to content

Commit 9308857

Browse files
authored
[google_maps_flutter_platform_interface] Platform interface changes to support heatmaps (#7312)
Prequel to: - #7313 - #7314 - #7315 - #3257
1 parent c451af7 commit 9308857

File tree

12 files changed

+1036
-7
lines changed

12 files changed

+1036
-7
lines changed

packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.9.0
2+
3+
* Adds support for heatmap layers.
4+
15
## 2.8.0
26

37
* Deprecates `BitmapDescriptor.fromAssetImage` in favor of `BitmapDescriptor.asset` and `AssetMapBitmap.create`.

packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart

+13
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'package:stream_transform/stream_transform.dart';
1414
import '../../google_maps_flutter_platform_interface.dart';
1515
import '../types/tile_overlay_updates.dart';
1616
import '../types/utils/map_configuration_serialization.dart';
17+
import 'serialization.dart';
1718

1819
/// Error thrown when an unknown map ID is provided to a method channel API.
1920
class UnknownMapIDError extends Error {
@@ -363,6 +364,17 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform {
363364
);
364365
}
365366

367+
@override
368+
Future<void> updateHeatmaps(
369+
HeatmapUpdates heatmapUpdates, {
370+
required int mapId,
371+
}) {
372+
return channel(mapId).invokeMethod<void>(
373+
'heatmaps#update',
374+
serializeMapsObjectUpdates(heatmapUpdates, serializeHeatmap),
375+
);
376+
}
377+
366378
@override
367379
Future<void> updateTileOverlays({
368380
required Set<TileOverlay> newTileOverlays,
@@ -542,6 +554,7 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform {
542554
'polygonsToAdd': serializePolygonSet(mapObjects.polygons),
543555
'polylinesToAdd': serializePolylineSet(mapObjects.polylines),
544556
'circlesToAdd': serializeCircleSet(mapObjects.circles),
557+
'heatmapsToAdd': serializeHeatmapSet(mapObjects.heatmaps),
545558
'tileOverlaysToAdd': serializeTileOverlaySet(mapObjects.tileOverlays),
546559
};
547560

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter/material.dart';
6+
import '../../google_maps_flutter_platform_interface.dart';
7+
8+
String _objectsToAddKey(String name) => '${name}sToAdd';
9+
String _objectsToChangeKey(String name) => '${name}sToChange';
10+
String _objectIdsToRemoveKey(String name) => '${name}IdsToRemove';
11+
const String _heatmapIdKey = 'heatmapId';
12+
const String _heatmapDataKey = 'data';
13+
const String _heatmapDissipatingKey = 'dissipating';
14+
const String _heatmapGradientKey = 'gradient';
15+
const String _heatmapMaxIntensityKey = 'maxIntensity';
16+
const String _heatmapOpacityKey = 'opacity';
17+
const String _heatmapRadiusKey = 'radius';
18+
const String _heatmapMinimumZoomIntensityKey = 'minimumZoomIntensity';
19+
const String _heatmapMaximumZoomIntensityKey = 'maximumZoomIntensity';
20+
const String _heatmapGradientColorsKey = 'colors';
21+
const String _heatmapGradientStartPointsKey = 'startPoints';
22+
const String _heatmapGradientColorMapSizeKey = 'colorMapSize';
23+
24+
void _addIfNonNull(Map<String, Object?> map, String fieldName, Object? value) {
25+
if (value != null) {
26+
map[fieldName] = value;
27+
}
28+
}
29+
30+
/// Serialize [MapsObjectUpdates]
31+
Object serializeMapsObjectUpdates<T extends MapsObject<T>>(
32+
MapsObjectUpdates<T> updates,
33+
Object Function(T) serialize,
34+
) {
35+
final Map<String, Object> json = <String, Object>{};
36+
37+
_addIfNonNull(
38+
json,
39+
_objectsToAddKey(updates.objectName),
40+
updates.objectsToAdd.map(serialize).toList(),
41+
);
42+
_addIfNonNull(
43+
json,
44+
_objectsToChangeKey(updates.objectName),
45+
updates.objectsToChange.map(serialize).toList(),
46+
);
47+
_addIfNonNull(
48+
json,
49+
_objectIdsToRemoveKey(updates.objectName),
50+
updates.objectIdsToRemove
51+
.map<String>((MapsObjectId<T> m) => m.value)
52+
.toList(),
53+
);
54+
55+
return json;
56+
}
57+
58+
/// Serialize [Heatmap]
59+
Object serializeHeatmap(Heatmap heatmap) {
60+
final Map<String, Object> json = <String, Object>{};
61+
62+
_addIfNonNull(json, _heatmapIdKey, heatmap.heatmapId.value);
63+
_addIfNonNull(
64+
json,
65+
_heatmapDataKey,
66+
heatmap.data.map(serializeWeightedLatLng).toList(),
67+
);
68+
_addIfNonNull(json, _heatmapDissipatingKey, heatmap.dissipating);
69+
70+
final HeatmapGradient? gradient = heatmap.gradient;
71+
if (gradient != null) {
72+
_addIfNonNull(
73+
json, _heatmapGradientKey, serializeHeatmapGradient(gradient));
74+
}
75+
_addIfNonNull(json, _heatmapMaxIntensityKey, heatmap.maxIntensity);
76+
_addIfNonNull(json, _heatmapOpacityKey, heatmap.opacity);
77+
_addIfNonNull(json, _heatmapRadiusKey, heatmap.radius.radius);
78+
_addIfNonNull(
79+
json, _heatmapMinimumZoomIntensityKey, heatmap.minimumZoomIntensity);
80+
_addIfNonNull(
81+
json, _heatmapMaximumZoomIntensityKey, heatmap.maximumZoomIntensity);
82+
83+
return json;
84+
}
85+
86+
/// Serialize [WeightedLatLng]
87+
Object serializeWeightedLatLng(WeightedLatLng wll) {
88+
return <Object>[serializeLatLng(wll.point), wll.weight];
89+
}
90+
91+
/// Deserialize [WeightedLatLng]
92+
WeightedLatLng? deserializeWeightedLatLng(Object? json) {
93+
if (json == null) {
94+
return null;
95+
}
96+
assert(json is List && json.length == 2);
97+
final List<dynamic> list = json as List<dynamic>;
98+
final LatLng latLng = deserializeLatLng(list[0])!;
99+
return WeightedLatLng(latLng, weight: list[1] as double);
100+
}
101+
102+
/// Serialize [LatLng]
103+
Object serializeLatLng(LatLng latLng) {
104+
return <Object>[latLng.latitude, latLng.longitude];
105+
}
106+
107+
/// Deserialize [LatLng]
108+
LatLng? deserializeLatLng(Object? json) {
109+
if (json == null) {
110+
return null;
111+
}
112+
assert(json is List && json.length == 2);
113+
final List<Object?> list = json as List<Object?>;
114+
return LatLng(list[0]! as double, list[1]! as double);
115+
}
116+
117+
/// Serialize [HeatmapGradient]
118+
Object serializeHeatmapGradient(HeatmapGradient gradient) {
119+
final Map<String, Object> json = <String, Object>{};
120+
121+
_addIfNonNull(
122+
json,
123+
_heatmapGradientColorsKey,
124+
gradient.colors.map((HeatmapGradientColor e) => e.color.value).toList(),
125+
);
126+
_addIfNonNull(
127+
json,
128+
_heatmapGradientStartPointsKey,
129+
gradient.colors.map((HeatmapGradientColor e) => e.startPoint).toList(),
130+
);
131+
_addIfNonNull(json, _heatmapGradientColorMapSizeKey, gradient.colorMapSize);
132+
133+
return json;
134+
}
135+
136+
/// Deserialize [HeatmapGradient]
137+
HeatmapGradient? deserializeHeatmapGradient(Object? json) {
138+
if (json == null) {
139+
return null;
140+
}
141+
assert(json is Map);
142+
final Map<String, Object?> map = (json as Map<Object?, Object?>).cast();
143+
final List<Color> colors = (map[_heatmapGradientColorsKey]! as List<Object?>)
144+
.whereType<int>()
145+
.map((int e) => Color(e))
146+
.toList();
147+
final List<double> startPoints =
148+
(map[_heatmapGradientStartPointsKey]! as List<Object?>)
149+
.whereType<double>()
150+
.toList();
151+
final List<HeatmapGradientColor> gradientColors = <HeatmapGradientColor>[];
152+
for (int i = 0; i < colors.length; i++) {
153+
gradientColors.add(HeatmapGradientColor(colors[i], startPoints[i]));
154+
}
155+
return HeatmapGradient(
156+
gradientColors,
157+
colorMapSize: map[_heatmapGradientColorMapSizeKey] as int? ?? 256,
158+
);
159+
}

packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart

+19-6
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface {
4949
throw UnimplementedError('init() has not been implemented.');
5050
}
5151

52-
/// Updates configuration options of the map user interface - deprecated, use
53-
/// updateMapConfiguration instead.
52+
/// Updates configuration options of the map user interface.
5453
///
5554
/// Change listeners are notified once the update has been made on the
5655
/// platform side.
5756
///
5857
/// The returned [Future] completes after listeners have been notified.
58+
@Deprecated('Use updateMapConfiguration instead.')
5959
Future<void> updateMapOptions(
6060
Map<String, dynamic> optionsUpdate, {
6161
required int mapId,
@@ -129,6 +129,19 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface {
129129
throw UnimplementedError('updateCircles() has not been implemented.');
130130
}
131131

132+
/// Updates heatmap configuration.
133+
///
134+
/// Change listeners are notified once the update has been made on the
135+
/// platform side.
136+
///
137+
/// The returned [Future] completes after listeners have been notified.
138+
Future<void> updateHeatmaps(
139+
HeatmapUpdates heatmapUpdates, {
140+
required int mapId,
141+
}) {
142+
throw UnimplementedError('updateHeatmaps() has not been implemented.');
143+
}
144+
132145
/// Updates tile overlay configuration.
133146
///
134147
/// Change listeners are notified once the update has been made on the
@@ -387,8 +400,8 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface {
387400
return null;
388401
}
389402

390-
/// Returns a widget displaying the map view - deprecated, use
391-
/// [buildViewWithConfiguration] instead.
403+
/// Returns a widget displaying the map view.
404+
@Deprecated('Use buildViewWithConfiguration instead.')
392405
Widget buildView(
393406
int creationId,
394407
PlatformViewCreatedCallback onPlatformViewCreated, {
@@ -407,8 +420,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface {
407420
throw UnimplementedError('buildView() has not been implemented.');
408421
}
409422

410-
/// Returns a widget displaying the map view - deprecated, use
411-
/// [buildViewWithConfiguration] instead.
423+
/// Returns a widget displaying the map view.
412424
///
413425
/// This method is similar to [buildView], but contains a parameter for
414426
/// platforms that require a text direction.
@@ -417,6 +429,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface {
417429
/// [buildView]. This is for backward compatibility with existing
418430
/// implementations. Platforms that use the text direction should override
419431
/// this as the primary implementation, and delegate to it from buildView.
432+
@Deprecated('Use buildViewWithConfiguration instead.')
420433
Widget buildViewWithTextDirection(
421434
int creationId,
422435
PlatformViewCreatedCallback onPlatformViewCreated, {

packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_inspector_platform.dart

+16
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,22 @@ abstract class GoogleMapsInspectorPlatform extends PlatformInterface {
116116
throw UnimplementedError('getTileOverlayInfo() has not been implemented.');
117117
}
118118

119+
/// If the platform supports getting information about heatmaps.
120+
bool supportsGettingHeatmapInfo() {
121+
throw UnimplementedError(
122+
'supportsGettingHeatmapInfo() has not been implemented.',
123+
);
124+
}
125+
126+
/// Returns information about the heatmap with the given ID.
127+
///
128+
/// The returned object will be synthesized from platform data, so will not
129+
/// be the same Dart object as the original [Heatmap] provided to the
130+
/// platform interface with that ID, and not all fields will be populated.
131+
Future<Heatmap?> getHeatmapInfo(HeatmapId heatmapId, {required int mapId}) {
132+
throw UnimplementedError('getHeatmapInfo() has not been implemented.');
133+
}
134+
119135
/// Returns current clusters from [ClusterManager].
120136
Future<List<Cluster>> getClusters(
121137
{required int mapId, required ClusterManagerId clusterManagerId}) {

0 commit comments

Comments
 (0)