diff --git a/example/lib/pages/markers.dart b/example/lib/pages/markers.dart index df0ff50f7..8a0b3dc92 100644 --- a/example/lib/pages/markers.dart +++ b/example/lib/pages/markers.dart @@ -120,14 +120,14 @@ class MarkerPageState extends State { ), MarkerLayer( rotate: counterRotate, - anchorPos: AnchorPos.defaultAnchorPos, + alignment: AnchorAlignment.defaultAnchorAlignment, markers: [ - Marker( + Marker.withAlignment( point: const LatLng(47.18664724067855, -1.5436768515939427), width: 64, height: 64, - anchorPos: const AnchorPos.align(Alignment.centerLeft), + alignment: const AnchorAlignment(Alignment.centerLeft), builder: (context) => const ColoredBox( color: Colors.lightBlue, child: Align( @@ -136,12 +136,12 @@ class MarkerPageState extends State { ), ), ), - Marker( + Marker.withAlignment( point: const LatLng(47.18664724067855, -1.5436768515939427), width: 64, height: 64, - anchorPos: const AnchorPos.align(Alignment.centerRight), + alignment: const AnchorAlignment(Alignment.centerRight), builder: (context) => const ColoredBox( color: Colors.pink, child: Align( @@ -162,7 +162,7 @@ class MarkerPageState extends State { MarkerLayer( markers: customMarkers, rotate: counterRotate, - anchorPos: AnchorPos.align(anchorAlign), + alignment: AnchorAlignment(anchorAlign), ), ], ), diff --git a/lib/src/layer/marker_layer.dart b/lib/src/layer/marker_layer.dart index e6de5eb87..97cc1d5f8 100644 --- a/lib/src/layer/marker_layer.dart +++ b/lib/src/layer/marker_layer.dart @@ -9,41 +9,30 @@ import 'package:latlong2/latlong.dart'; /// Defines the positioning of a [Marker.builder] widget relative to the center /// of its bounding box /// -/// Can be defined exactly (using [AnchorPos.exactly] with an [Anchor]) or in -/// a relative/dynamic alignment (using [AnchorPos.align] with an [Alignment]). +/// Can be defined exactly (using [AnchorAlignment.exactly] with an [Anchor]) or in +/// a relative/dynamic alignment (using [AnchorAlignment.align] with an [Alignment]). /// -/// If using [AnchorPos.align], the provided [AlignmentGeometry]'s factors must +/// If using [AnchorAlignment.align], the provided [AlignmentGeometry]'s factors must /// be either -1, 1, or 0 only (ie. the pre-provided [Alignment]s). /// [textDirection] will default to [TextDirection.ltr], and is used to resolve /// the [AlignmentGeometry]. @immutable -class AnchorPos { +class AnchorAlignment { /// The default, central alignment - static const defaultAnchorPos = AnchorPos.align(Alignment.center); + static const defaultAnchorAlignment = AnchorAlignment(Alignment.center); - /// Exact left/top anchor - /// - /// Set only if constructed with [AnchorPos.exactly]. - final Anchor? anchor; - - /// Relative/dynamic alignment + /// Relative/dynamic alignment geometry. /// /// Transformed into [anchor] at runtime by [Anchor.fromPos]. Resolved by /// [textDirection]. /// - /// Set only if constructed with [AnchorPos.align]. - final AlignmentGeometry? alignment; + /// Set only if constructed with [AnchorAlignment.align]. + final AlignmentGeometry geometry; /// Used to resolve [alignment]. /// - /// Set only if constructed with [AnchorPos.align]. - final TextDirection? textDirection; - - /// Defines the positioning of a [Marker.builder] widget relative to the center - /// of its bounding box, with an exact left/top anchor - const AnchorPos.exactly(Anchor this.anchor) - : alignment = null, - textDirection = null; + /// Set only if constructed with [AnchorAlignment.align]. + final TextDirection textDirection; /// Defines the positioning of a [Marker.builder] widget relative to the center /// of its bounding box, with a relative/dynamic alignment @@ -51,16 +40,16 @@ class AnchorPos { /// [alignment]'s factors must be either -1, 1, or 0 only (ie. the pre-provided /// [Alignment]s). [textDirection] will default to [TextDirection.ltr], and is /// used to resolve the [AlignmentGeometry]. - const AnchorPos.align( - AlignmentGeometry this.alignment, { + const AnchorAlignment( + this.geometry, { this.textDirection = TextDirection.ltr, - }) : anchor = null; + }); } /// Exact alignment for a [Marker.builder] widget relative to the center /// of its bounding box defined by its [Marker.height] & [Marker.width] /// -/// May be generated from an [AnchorPos] (usually with [AnchorPos.alignment] +/// May be generated from an [AnchorAlignment] (usually with [AnchorAlignment.geometry] /// defined) and dimensions through [Anchor.fromPos]. @immutable class Anchor { @@ -69,33 +58,31 @@ class Anchor { const Anchor(this.left, this.top); - factory Anchor.fromPos(AnchorPos pos, double width, double height) { - if (pos.anchor case final anchor?) return anchor; - if (pos.alignment case final alignment?) { - return Anchor( - switch (alignment.resolve(pos.textDirection).x) { - -1 => 0, - 1 => width, - 0 => width / 2, - _ => throw ArgumentError.value( - alignment, - 'alignment', - 'The `x` factor must be -1, 1, or 0 only (ie. the pre-provided alignments)', - ), - }, - switch (alignment.resolve(pos.textDirection).y) { - -1 => 0, - 1 => height, - 0 => height / 2, - _ => throw ArgumentError.value( - alignment, - 'alignment', - 'The `y` factor must be -1, 1, or 0 only (ie. the pre-provided alignments)', - ), - }, - ); - } - throw Exception(); + factory Anchor.fromPos( + AnchorAlignment alignment, double width, double height) { + final geometry = alignment.geometry; + return Anchor( + switch (geometry.resolve(alignment.textDirection).x) { + -1 => 0, + 1 => width, + 0 => width / 2, + _ => throw ArgumentError.value( + geometry, + 'alignment', + 'The `x` factor must be -1, 1, or 0 only (ie. the pre-provided alignments)', + ), + }, + switch (geometry.resolve(alignment.textDirection).y) { + -1 => 0, + 1 => height, + 0 => height / 2, + _ => throw ArgumentError.value( + geometry, + 'alignment', + 'The `y` factor must be -1, 1, or 0 only (ie. the pre-provided alignments)', + ), + }, + ); } } @@ -137,8 +124,8 @@ class Marker { /// The alignment of the origin, relative to the size of the box. /// - /// Automatically set to the opposite of `anchorPos`, if it was constructed by - /// [AnchorPos.align], but can be overridden. + /// Automatically set to the opposite of `alignment`, if it was constructed by + /// [AnchorAlignment.align], but can be overridden. /// /// This is equivalent to setting an origin based on the size of the box. /// If it is specified at the same time as the [rotateOrigin], both are applied. @@ -152,20 +139,32 @@ class Marker { /// [Directionality.of] returns [TextDirection.rtl]. final AlignmentGeometry? rotateAlignment; - Marker({ + const Marker({ + this.key, + required this.point, + required this.builder, + this.width = 30.0, + this.height = 30.0, + this.anchor, + this.rotate, + this.rotateOrigin, + this.rotateAlignment, + }); + + Marker.withAlignment({ this.key, required this.point, required this.builder, this.width = 30.0, this.height = 30.0, - AnchorPos? anchorPos, + AnchorAlignment? alignment, this.rotate, this.rotateOrigin, AlignmentGeometry? rotateAlignment, }) : anchor = - anchorPos == null ? null : Anchor.fromPos(anchorPos, width, height), + alignment == null ? null : Anchor.fromPos(alignment, width, height), rotateAlignment = rotateAlignment ?? - (anchorPos?.alignment != null ? anchorPos!.alignment! * -1 : null); + (alignment != null ? alignment.geometry * -1 : null); } @immutable @@ -175,8 +174,8 @@ class MarkerLayer extends StatelessWidget { /// Positioning of the [Marker.builder] widget relative to the center of its /// bounding box defined by its [Marker.height] & [Marker.width] /// - /// Overriden on a per [Marker] basis if [Marker.anchorPos] is specified. - final AnchorPos? anchorPos; + /// Overriden on a per [Marker] basis if [Marker.alignment] is specified. + final AnchorAlignment? alignment; /// Whether to counter rotate markers to the map's rotation, to keep a fixed /// orientation @@ -195,8 +194,8 @@ class MarkerLayer extends StatelessWidget { /// The alignment of the origin, relative to the size of the box. /// - /// Automatically set to the opposite of `anchorPos`, if it was constructed by - /// [AnchorPos.align], but can be overridden. + /// Automatically set to the opposite of `alignment`, if it was constructed by + /// [AnchorAlignment.align], but can be overridden. /// /// This is equivalent to setting an origin based on the size of the box. /// If it is specified at the same time as the [rotateOrigin], both are applied. @@ -215,7 +214,7 @@ class MarkerLayer extends StatelessWidget { const MarkerLayer({ super.key, this.markers = const [], - this.anchorPos, + this.alignment, this.rotate = false, this.rotateOrigin, this.rotateAlignment, @@ -236,7 +235,7 @@ class MarkerLayer extends StatelessWidget { // unlike the map coordinates. final anchor = marker.anchor ?? Anchor.fromPos( - anchorPos ?? AnchorPos.defaultAnchorPos, + alignment ?? AnchorAlignment.defaultAnchorAlignment, marker.width, marker.height, ); @@ -250,8 +249,8 @@ class MarkerLayer extends StatelessWidget { continue; } - final defaultAlignment = anchorPos?.alignment != null - ? anchorPos!.alignment! * -1 + final defaultRotateAlignment = alignment != null + ? alignment!.geometry * -1 : Alignment.center; final pos = pxPoint.subtract(map.pixelOrigin); @@ -260,7 +259,7 @@ class MarkerLayer extends StatelessWidget { angle: -map.rotationRad, origin: marker.rotateOrigin ?? rotateOrigin ?? Offset.zero, alignment: - marker.rotateAlignment ?? rotateAlignment ?? defaultAlignment, + marker.rotateAlignment ?? rotateAlignment ?? defaultRotateAlignment, child: marker.builder(context), ) : marker.builder(context);