Skip to content

Commit

Permalink
Merge pull request #201 from tratteo/master
Browse files Browse the repository at this point in the history
PopupLayer rotation fix
  • Loading branch information
lpongetti authored Dec 5, 2023
2 parents ba928e0 + d0a996c commit 8eed7ae
Showing 1 changed file with 55 additions and 104 deletions.
159 changes: 55 additions & 104 deletions lib/src/marker_cluster_layer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ class MarkerClusterLayer extends StatefulWidget {
State<MarkerClusterLayer> createState() => _MarkerClusterLayerState();
}

class _MarkerClusterLayerState extends State<MarkerClusterLayer>
with TickerProviderStateMixin {
class _MarkerClusterLayerState extends State<MarkerClusterLayer> with TickerProviderStateMixin {
late MapCalculator _mapCalculator;
late ClusterManager _clusterManager;
late int _maxZoom;
Expand All @@ -53,21 +52,14 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
_MarkerClusterLayerState();

bool _isSpiderfyCluster(MarkerClusterNode cluster) {
return spiderfyCluster != null &&
spiderfyCluster!.bounds.center == cluster.bounds.center;
return spiderfyCluster != null && spiderfyCluster!.bounds.center == cluster.bounds.center;
}

bool get _animating =>
_zoomController.isAnimating ||
_fitBoundController.isAnimating ||
_centerMarkerController.isAnimating ||
_spiderfyController.isAnimating;
bool get _animating => _zoomController.isAnimating || _fitBoundController.isAnimating || _centerMarkerController.isAnimating || _spiderfyController.isAnimating;

bool get _zoomingIn =>
_zoomController.isAnimating && _currentZoom > _previousZoom;
bool get _zoomingIn => _zoomController.isAnimating && _currentZoom > _previousZoom;

bool get _zoomingOut =>
_zoomController.isAnimating && _currentZoom < _previousZoom;
bool get _zoomingOut => _zoomController.isAnimating && _currentZoom < _previousZoom;

@override
void initState() {
Expand Down Expand Up @@ -157,10 +149,25 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>

@override
Widget build(BuildContext context) {
return MobileLayerTransformer(
child: Stack(
children: _buildLayers(),
),
final popupOptions = widget.options.popupOptions;
return Stack(
children: [
// Keep the layers in a MobileTransformStack
MobileLayerTransformer(
child: Stack(
children: _buildMobileTransformStack(),
),
),
// Move the PopupLayer outside the MobileLayerTransformer since it has its own
if (popupOptions != null)
PopupLayer(
popupDisplayOptions: PopupDisplayOptions(
builder: popupOptions.popupBuilder,
animation: popupOptions.popupAnimation,
snap: popupOptions.popupSnap,
),
)
],
);
}

Expand Down Expand Up @@ -194,18 +201,12 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
/// Function that is called when the marker is hover (if popup building on hover is selected).
/// if enter == true then it's onHoverEnter, if enter == false it's onHoverExit
void _onMarkerHover(MarkerNode marker, bool enter) {
if (_zoomController.isAnimating ||
_centerMarkerController.isAnimating ||
_fitBoundController.isAnimating) return;
if (_zoomController.isAnimating || _centerMarkerController.isAnimating || _fitBoundController.isAnimating) return;

if (widget.options.popupOptions != null) {
final popupOptions = widget.options.popupOptions!;
enter
? Future.delayed(
Duration(
milliseconds: popupOptions.timeToShowPopupOnHover >= 0
? popupOptions.timeToShowPopupOnHover
: 0), () {
? Future.delayed(Duration(milliseconds: popupOptions.timeToShowPopupOnHover >= 0 ? popupOptions.timeToShowPopupOnHover : 0), () {
popupOptions.markerTapBehavior.apply(
PopupSpec.wrap(marker.marker),
PopupState.maybeOf(context, listen: false)!,
Expand All @@ -216,9 +217,7 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
}

if (widget.options.onMarkerTap != null) {
enter
? widget.options.onMarkerHoverEnter?.call(marker.marker)
: widget.options.onMarkerHoverExit?.call(marker.marker);
enter ? widget.options.onMarkerHoverEnter?.call(marker.marker) : widget.options.onMarkerHoverExit?.call(marker.marker);
}
}

Expand All @@ -232,18 +231,14 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
Future<void> _unspiderfy() async {
switch (_spiderfyController.status) {
case AnimationStatus.completed:
final markersGettingClustered = spiderfyCluster?.markers
.map((markerNode) => markerNode.marker)
.toList();
final markersGettingClustered = spiderfyCluster?.markers.map((markerNode) => markerNode.marker).toList();

if (widget.options.popupOptions != null &&
markersGettingClustered != null) {
if (widget.options.popupOptions != null && markersGettingClustered != null) {
widget.options.popupOptions!.popupController.hidePopupsOnlyFor(
markersGettingClustered,
);
}
if (widget.options.onMarkersClustered != null &&
markersGettingClustered != null) {
if (widget.options.onMarkersClustered != null && markersGettingClustered != null) {
widget.options.onMarkersClustered!(markersGettingClustered);
}

Expand All @@ -254,13 +249,10 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
);
break;
case AnimationStatus.forward:
final markersGettingClustered = spiderfyCluster?.markers
.map((markerNode) => markerNode.marker)
.toList();
final markersGettingClustered = spiderfyCluster?.markers.map((markerNode) => markerNode.marker).toList();

if (markersGettingClustered != null) {
widget.options.popupOptions?.popupController
.hidePopupsOnlyFor(markersGettingClustered);
widget.options.popupOptions?.popupController.hidePopupsOnlyFor(markersGettingClustered);
widget.options.onMarkersClustered?.call(markersGettingClustered);
}

Expand Down Expand Up @@ -315,8 +307,7 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
angle: -widget.mapCamera.rotationRad,
alignment: widget.options.alignment,
),
fade:
Fade.fadeOut(curve: widget.options.animationsOptions.fadeOutCurve),
fade: Fade.fadeOut(curve: widget.options.animationsOptions.fadeOutCurve),
child: ClusterWidget(
cluster: markerNode.parent!,
builder: widget.options.builder,
Expand All @@ -326,12 +317,10 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
);
}

void _addMarkerClusterLayer(MarkerClusterNode clusterNode,
List<Widget> layers, List<Widget> spiderfyLayers) {
void _addMarkerClusterLayer(MarkerClusterNode clusterNode, List<Widget> layers, List<Widget> spiderfyLayers) {
if (_zoomingOut && clusterNode.children.length > 1) {
_addClusterClosingLayer(clusterNode, layers);
} else if (_zoomingIn &&
clusterNode.parent!.bounds.center != clusterNode.bounds.center) {
} else if (_zoomingIn && clusterNode.parent!.bounds.center != clusterNode.bounds.center) {
_addClusterOpeningLayer(clusterNode, layers);
} else if (_isSpiderfyCluster(clusterNode)) {
spiderfyLayers.addAll(_buildSpiderfyCluster(clusterNode, _currentZoom));
Expand All @@ -357,8 +346,7 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
}
}

void _addClusterClosingLayer(
MarkerClusterNode clusterNode, List<Widget> layers) {
void _addClusterClosingLayer(MarkerClusterNode clusterNode, List<Widget> layers) {
// cluster
layers.add(
MapWidget(
Expand Down Expand Up @@ -390,8 +378,7 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
_buildMarker(
marker: child,
controller: _zoomController,
fade: Fade.fadeOut(
curve: widget.options.animationsOptions.fadeOutCurve),
fade: Fade.fadeOut(curve: widget.options.animationsOptions.fadeOutCurve),
translate: AnimatedTranslate.fromMyPosToNewPos(
mapCalculator: _mapCalculator,
from: child,
Expand All @@ -418,8 +405,7 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
angle: -widget.mapCamera.rotationRad,
alignment: widget.options.alignment,
),
fade: Fade.fadeOut(
curve: widget.options.animationsOptions.fadeOutCurve),
fade: Fade.fadeOut(curve: widget.options.animationsOptions.fadeOutCurve),
child: ClusterWidget(
cluster: child,
builder: widget.options.builder,
Expand All @@ -436,8 +422,7 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
widget.options.onMarkersClustered?.call(markersGettingClustered);
}

void _addClusterOpeningLayer(
MarkerClusterNode clusterNode, List<Widget> layers) {
void _addClusterOpeningLayer(MarkerClusterNode clusterNode, List<Widget> layers) {
// cluster
layers.add(MapWidget(
size: clusterNode.size(),
Expand Down Expand Up @@ -497,8 +482,7 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
angle: -widget.mapCamera.rotationRad,
alignment: widget.options.alignment,
),
fade: Fade.almostFadeOut(
curve: widget.options.animationsOptions.fadeOutCurve),
fade: Fade.almostFadeOut(curve: widget.options.animationsOptions.fadeOutCurve),
child: ClusterWidget(
cluster: cluster,
builder: widget.options.builder,
Expand All @@ -518,8 +502,7 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
_buildMarker(
marker: marker,
controller: _spiderfyController,
fade:
Fade.fadeIn(curve: widget.options.animationsOptions.fadeInCurve),
fade: Fade.fadeIn(curve: widget.options.animationsOptions.fadeInCurve),
translate: AnimatedTranslate.spiderfy(
mapCalculator: _mapCalculator,
cluster: cluster,
Expand All @@ -533,7 +516,7 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
return results;
}

List<Widget> _buildLayers() {
List<Widget> _buildMobileTransformStack() {
if (widget.mapCamera.zoom != _previousZoomDouble) {
_previousZoomDouble = widget.mapCamera.zoom;
_unspiderfy();
Expand Down Expand Up @@ -574,9 +557,7 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
0.5,
);

_clusterManager.recursivelyFromTopClusterLevel(
_currentZoom, widget.options.disableClusteringAtZoom, recursionBounds,
(MarkerOrClusterNode layer) {
_clusterManager.recursivelyFromTopClusterLevel(_currentZoom, widget.options.disableClusteringAtZoom, recursionBounds, (MarkerOrClusterNode layer) {
// This is the performance critical hot path recursed on every map event!

// Cull markers/clusters that are not on screen.
Expand All @@ -597,17 +578,6 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>

// ensures the spiderfy layers markers are on top of other markers and clusters
layers.addAll(spiderfyLayers);

final popupOptions = widget.options.popupOptions;
if (popupOptions != null) {
layers.add(PopupLayer(
popupDisplayOptions: PopupDisplayOptions(
builder: popupOptions.popupBuilder,
animation: popupOptions.popupAnimation,
snap: popupOptions.popupSnap),
));
}

return layers;
}

Expand Down Expand Up @@ -646,19 +616,12 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
).fit(widget.mapCamera);

// check if children can un-cluster
final cannotDivide = cluster.markers.every((marker) =>
marker.parent!.zoom == _maxZoom &&
marker.parent == cluster.markers.first.parent) ||
final cannotDivide = cluster.markers.every((marker) => marker.parent!.zoom == _maxZoom && marker.parent == cluster.markers.first.parent) ||
(dest.zoom == _currentZoom && _currentZoom == opt.maxZoom);

if (cannotDivide) {
//dest = CenterZoom(center: dest.center, zoom: _currentZoom.toDouble());
dest = MapCamera(
crs: dest.crs,
center: dest.center,
zoom: _currentZoom.toDouble(),
rotation: dest.rotation,
nonRotatedSize: dest.nonRotatedSize);
dest = MapCamera(crs: dest.crs, center: dest.center, zoom: _currentZoom.toDouble(), rotation: dest.rotation, nonRotatedSize: dest.nonRotatedSize);

if (spiderfyCluster != null) {
if (spiderfyCluster == cluster) {
Expand All @@ -674,16 +637,11 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
_showPolygon(cluster.markers.map((m) => m.point).toList());
}

final latTween =
Tween<double>(begin: center.latitude, end: dest.center.latitude);
final lonTween =
Tween<double>(begin: center.longitude, end: dest.center.longitude);
final zoomTween =
Tween<double>(begin: widget.mapCamera.zoom, end: dest.zoom);
final latTween = Tween<double>(begin: center.latitude, end: dest.center.latitude);
final lonTween = Tween<double>(begin: center.longitude, end: dest.center.longitude);
final zoomTween = Tween<double>(begin: widget.mapCamera.zoom, end: dest.zoom);

final isAlreadyFit = latTween.begin == latTween.end &&
lonTween.begin == lonTween.end &&
zoomTween.begin == zoomTween.end;
final isAlreadyFit = latTween.begin == latTween.end && lonTween.begin == lonTween.end && zoomTween.begin == zoomTween.end;

if (isAlreadyFit) {
if (cannotDivide && widget.options.spiderfyCluster) {
Expand All @@ -692,12 +650,9 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
return;
}

final animation = CurvedAnimation(
parent: _fitBoundController,
curve: widget.options.animationsOptions.fitBoundCurves);
final animation = CurvedAnimation(parent: _fitBoundController, curve: widget.options.animationsOptions.fitBoundCurves);

final listener = _centerMarkerListener(animation, latTween, lonTween,
zoomTween: zoomTween);
final listener = _centerMarkerListener(animation, latTween, lonTween, zoomTween: zoomTween);

_fitBoundController.addListener(listener);

Expand Down Expand Up @@ -731,10 +686,8 @@ class _MarkerClusterLayerState extends State<MarkerClusterLayer>
if (!widget.options.centerMarkerOnClick) return;

final center = widget.mapCamera.center;
final latTween =
Tween<double>(begin: center.latitude, end: marker.point.latitude);
final lonTween =
Tween<double>(begin: center.longitude, end: marker.point.longitude);
final latTween = Tween<double>(begin: center.latitude, end: marker.point.latitude);
final lonTween = Tween<double>(begin: center.longitude, end: marker.point.longitude);

final Animation<double> animation = CurvedAnimation(
parent: _centerMarkerController,
Expand Down Expand Up @@ -815,10 +768,8 @@ LatLngBounds _extendBounds(LatLngBounds bounds, double stickonFactor) {
// Clamp rather than wrap around. This function is used in the context of
// drawing things onto a map. Since the map renderer does't wrap maps itself,
// we also shouldn't wrap around the bounding boxes.
final point1 = LatLng((bounds.south - height).clamp(-90, 90),
(bounds.west - width).clamp(-180, 180));
final point2 = LatLng((bounds.north + height).clamp(-90, 90),
(bounds.east + width).clamp(-180, 180));
final point1 = LatLng((bounds.south - height).clamp(-90, 90), (bounds.west - width).clamp(-180, 180));
final point2 = LatLng((bounds.north + height).clamp(-90, 90), (bounds.east + width).clamp(-180, 180));

return LatLngBounds(point1, point2);
}

0 comments on commit 8eed7ae

Please sign in to comment.