From d590be261f81bc4cff61397b54cc8bd0fea92dad Mon Sep 17 00:00:00 2001 From: Leon Date: Tue, 3 Jun 2025 09:44:10 -0300 Subject: [PATCH 1/6] feat: parameters to use marker in meters --- lib/src/layer/marker_layer/marker.dart | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/src/layer/marker_layer/marker.dart b/lib/src/layer/marker_layer/marker.dart index 764770342..95358cfc9 100644 --- a/lib/src/layer/marker_layer/marker.dart +++ b/lib/src/layer/marker_layer/marker.dart @@ -48,6 +48,18 @@ class Marker { /// marker. Use a widget inside [child] to perform this. final bool? rotate; + /// Parameter to enable or not the feature to use markers dimensions in meters. + /// + /// A good way to use that feature is using a LayoutBuilder and building according the + /// maxHeight and minWidth values. + final bool useSizeInMeters; + + /// TODO: Documentation + final double? maxWidthUsingMetersPixels; + final double? maxHeightUsingMetersPixels; + final double? minWidthUsingMetersPixels; + final double? minHeightUsingMetersPixels; + /// Creates a container for a [child] widget located at a geographic coordinate /// [point] /// @@ -61,6 +73,11 @@ class Marker { this.height = 30, this.alignment, this.rotate, + this.useSizeInMeters = false, + this.maxWidthUsingMetersPixels, + this.maxHeightUsingMetersPixels, + this.minHeightUsingMetersPixels, + this.minWidthUsingMetersPixels, }); /// Returns the alignment of a [width]x[height] rectangle by [left]x[top] pixels. From 3bc637f73d74d9f97ba3b4862a72a2b782a314f9 Mon Sep 17 00:00:00 2001 From: Leon Date: Tue, 3 Jun 2025 10:14:08 -0300 Subject: [PATCH 2/6] refactor: change positioned left, top, bottom and right variables creating that only in the needed function --- lib/src/layer/marker_layer/marker_layer.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/src/layer/marker_layer/marker_layer.dart b/lib/src/layer/marker_layer/marker_layer.dart index fe4693d46..32ed910d0 100644 --- a/lib/src/layer/marker_layer/marker_layer.dart +++ b/lib/src/layer/marker_layer/marker_layer.dart @@ -47,19 +47,19 @@ class MarkerLayer extends StatelessWidget { child: Stack( children: (List markers) sync* { for (final m in markers) { - // Resolve real alignment - // TODO: maybe just using Size, Offset, and Rect? - final left = 0.5 * m.width * ((m.alignment ?? alignment).x + 1); - final top = 0.5 * m.height * ((m.alignment ?? alignment).y + 1); - final right = m.width - left; - final bottom = m.height - top; - // Perform projection final pxPoint = map.projectAtZoom(m.point); Positioned? getPositioned(double worldShift) { final shiftedX = pxPoint.dx + worldShift; + // Resolve real alignment + // TODO: maybe just using Size, Offset, and Rect? + final left = 0.5 * m.width * ((m.alignment ?? alignment).x + 1); + final top = 0.5 * m.height * ((m.alignment ?? alignment).y + 1); + final right = m.width - left; + final bottom = m.height - top; + // Cull if out of bounds if (!map.pixelBounds.overlaps( Rect.fromPoints( From f1f8394807639112da5920e5f01eb4f0712e2c42 Mon Sep 17 00:00:00 2001 From: Leon Date: Tue, 3 Jun 2025 10:56:29 -0300 Subject: [PATCH 3/6] feat: width and height according the using meters implementation --- lib/src/layer/marker_layer/marker_layer.dart | 51 +++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/lib/src/layer/marker_layer/marker_layer.dart b/lib/src/layer/marker_layer/marker_layer.dart index 32ed910d0..91d230940 100644 --- a/lib/src/layer/marker_layer/marker_layer.dart +++ b/lib/src/layer/marker_layer/marker_layer.dart @@ -53,12 +53,51 @@ class MarkerLayer extends StatelessWidget { Positioned? getPositioned(double worldShift) { final shiftedX = pxPoint.dx + worldShift; + double height = m.height; + double width = m.width; + + if (m.useSizeInMeters) { + final basePoint = m.point; + final baseOffset = map.getOffsetFromOrigin(basePoint); + final rHeight = + const Distance().offset(basePoint, height / 2, 0); + final rWidth = const Distance().offset(basePoint, width / 2, 0); + + height = + (baseOffset - map.getOffsetFromOrigin(rHeight)).distance * + 2; + width = + (baseOffset - map.getOffsetFromOrigin(rWidth)).distance * 2; + + final maxHeightUsingMetersPixels = m.maxHeightUsingMetersPixels; + final maxWidthUsingMetersPixels = m.maxWidthUsingMetersPixels; + if (maxHeightUsingMetersPixels != null && + height > maxHeightUsingMetersPixels) { + height = maxHeightUsingMetersPixels; + } + if (maxWidthUsingMetersPixels != null && + width > maxWidthUsingMetersPixels) { + width = maxWidthUsingMetersPixels; + } + + final minHeightUsingMetersPixels = m.minHeightUsingMetersPixels; + final minWidthUsingMetersPixels = m.minWidthUsingMetersPixels; + if (minHeightUsingMetersPixels != null && + height < minHeightUsingMetersPixels) { + height = minHeightUsingMetersPixels; + } + if (minWidthUsingMetersPixels != null && + width < minWidthUsingMetersPixels) { + width = minWidthUsingMetersPixels; + } + } + // Resolve real alignment // TODO: maybe just using Size, Offset, and Rect? - final left = 0.5 * m.width * ((m.alignment ?? alignment).x + 1); - final top = 0.5 * m.height * ((m.alignment ?? alignment).y + 1); - final right = m.width - left; - final bottom = m.height - top; + final left = 0.5 * width * ((m.alignment ?? alignment).x + 1); + final top = 0.5 * height * ((m.alignment ?? alignment).y + 1); + final right = width - left; + final bottom = height - top; // Cull if out of bounds if (!map.pixelBounds.overlaps( @@ -77,8 +116,8 @@ class MarkerLayer extends StatelessWidget { return Positioned( key: m.key, - width: m.width, - height: m.height, + width: width, + height: height, left: shiftedLocalPoint.dx - right, top: shiftedLocalPoint.dy - bottom, child: (m.rotate ?? rotate) From 5f88ba825fdd514c0703f063730f31a4dec15ff5 Mon Sep 17 00:00:00 2001 From: Leon Date: Tue, 3 Jun 2025 11:34:46 -0300 Subject: [PATCH 4/6] feat: marker using size in meters example --- example/lib/pages/markers.dart | 44 ++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/example/lib/pages/markers.dart b/example/lib/pages/markers.dart index 2f652096b..d71a0d3d7 100644 --- a/example/lib/pages/markers.dart +++ b/example/lib/pages/markers.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map_example/misc/tile_providers.dart'; @@ -117,8 +119,11 @@ class _MarkerPageState extends State { Flexible( child: FlutterMap( options: MapOptions( - initialCenter: const LatLng(51.5, -0.09), - initialZoom: 5, + initialCenter: const LatLng( + 51.51868093513547, + -0.12835376940892318, + ), + initialZoom: 15, onTap: (_, p) => setState(() => customMarkers.add(buildPin(p))), interactionOptions: const InteractionOptions( flags: ~InteractiveFlag.doubleTapZoom, @@ -167,6 +172,41 @@ class _MarkerPageState extends State { rotate: counterRotate, alignment: selectedAlignment, ), + MarkerLayer( + markers: [ + Marker( + point: const LatLng( + 51.51868093513547, + -0.12835376940892318, + ), + height: 20, + width: 20, + maxHeightUsingMetersPixels: 200, + maxWidthUsingMetersPixels: 200, + child: LayoutBuilder( + builder: (context, constraints) { + final minDimension = min( + constraints.maxHeight, + constraints.maxWidth, + ); + + return Transform.scale( + scale: minDimension / 30, + child: const SizedBox( + width: 30, + height: 30, + child: Icon( + Icons.map, + color: Colors.amber, + ), + ), + ); + }, + ), + useSizeInMeters: true, + ), + ], + ), ], ), ), From dbb1f99b6297d197054efcb12ae4091f3e467da1 Mon Sep 17 00:00:00 2001 From: Leon Date: Tue, 3 Jun 2025 12:10:10 -0300 Subject: [PATCH 5/6] feat: documentation of the new parameters --- lib/src/layer/marker_layer/marker.dart | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/src/layer/marker_layer/marker.dart b/lib/src/layer/marker_layer/marker.dart index 95358cfc9..9e724c987 100644 --- a/lib/src/layer/marker_layer/marker.dart +++ b/lib/src/layer/marker_layer/marker.dart @@ -54,10 +54,24 @@ class Marker { /// maxHeight and minWidth values. final bool useSizeInMeters; - /// TODO: Documentation + /// Parameter to control the max width in pixels of the marker region when the parameter + /// [useSizeInMeters] is enabled. That size is optional and when existent will limited + /// the marker size pixel width final double? maxWidthUsingMetersPixels; + + /// Parameter to control the max height in pixels of the marker region when the parameter + /// [useSizeInMeters] is enabled. That size is optional and when existent will limited + /// the marker size pixel height final double? maxHeightUsingMetersPixels; + + /// Parameter to control the min width in pixels of the marker region when the parameter + /// [useSizeInMeters] is enabled. That size is optional and when existent will be the + /// minimal width for the marker pixel region final double? minWidthUsingMetersPixels; + + /// Parameter to control the min height in pixels of the marker region when the parameter + /// [useSizeInMeters] is enabled. That size is optional and when existent will be the + /// minimal height for the marker pixel region final double? minHeightUsingMetersPixels; /// Creates a container for a [child] widget located at a geographic coordinate From 35e1f11787777c259538a5659bcf4c6e2265194b Mon Sep 17 00:00:00 2001 From: Leon Date: Mon, 9 Jun 2025 13:33:44 -0300 Subject: [PATCH 6/6] refactor: marker parameters to control the min and max height and width in a box contraint to avoid so many parameters --- example/lib/pages/markers.dart | 6 ++-- lib/src/layer/marker_layer/marker.dart | 28 +++------------- lib/src/layer/marker_layer/marker_layer.dart | 35 +++++++++----------- 3 files changed, 24 insertions(+), 45 deletions(-) diff --git a/example/lib/pages/markers.dart b/example/lib/pages/markers.dart index d71a0d3d7..22dad83a1 100644 --- a/example/lib/pages/markers.dart +++ b/example/lib/pages/markers.dart @@ -181,8 +181,10 @@ class _MarkerPageState extends State { ), height: 20, width: 20, - maxHeightUsingMetersPixels: 200, - maxWidthUsingMetersPixels: 200, + boxConstraintsUsingMetersInPixels: const BoxConstraints( + maxHeight: 200, + maxWidth: 200, + ), child: LayoutBuilder( builder: (context, constraints) { final minDimension = min( diff --git a/lib/src/layer/marker_layer/marker.dart b/lib/src/layer/marker_layer/marker.dart index 9e724c987..f66a8c227 100644 --- a/lib/src/layer/marker_layer/marker.dart +++ b/lib/src/layer/marker_layer/marker.dart @@ -54,25 +54,10 @@ class Marker { /// maxHeight and minWidth values. final bool useSizeInMeters; - /// Parameter to control the max width in pixels of the marker region when the parameter - /// [useSizeInMeters] is enabled. That size is optional and when existent will limited - /// the marker size pixel width - final double? maxWidthUsingMetersPixels; - - /// Parameter to control the max height in pixels of the marker region when the parameter - /// [useSizeInMeters] is enabled. That size is optional and when existent will limited - /// the marker size pixel height - final double? maxHeightUsingMetersPixels; - - /// Parameter to control the min width in pixels of the marker region when the parameter - /// [useSizeInMeters] is enabled. That size is optional and when existent will be the - /// minimal width for the marker pixel region - final double? minWidthUsingMetersPixels; - - /// Parameter to control the min height in pixels of the marker region when the parameter - /// [useSizeInMeters] is enabled. That size is optional and when existent will be the - /// minimal height for the marker pixel region - final double? minHeightUsingMetersPixels; + /// Parameter to control the box size when the parameter [useSizeInMeters] is enabled. + /// That BoxConstraints is optional and when exists control the minimal and maximal size + /// in pixels of that region created by the map visible region in meters. + final BoxConstraints? boxConstraintsUsingMetersInPixels; /// Creates a container for a [child] widget located at a geographic coordinate /// [point] @@ -88,10 +73,7 @@ class Marker { this.alignment, this.rotate, this.useSizeInMeters = false, - this.maxWidthUsingMetersPixels, - this.maxHeightUsingMetersPixels, - this.minHeightUsingMetersPixels, - this.minWidthUsingMetersPixels, + this.boxConstraintsUsingMetersInPixels, }); /// Returns the alignment of a [width]x[height] rectangle by [left]x[top] pixels. diff --git a/lib/src/layer/marker_layer/marker_layer.dart b/lib/src/layer/marker_layer/marker_layer.dart index 91d230940..6489829e0 100644 --- a/lib/src/layer/marker_layer/marker_layer.dart +++ b/lib/src/layer/marker_layer/marker_layer.dart @@ -69,26 +69,21 @@ class MarkerLayer extends StatelessWidget { width = (baseOffset - map.getOffsetFromOrigin(rWidth)).distance * 2; - final maxHeightUsingMetersPixels = m.maxHeightUsingMetersPixels; - final maxWidthUsingMetersPixels = m.maxWidthUsingMetersPixels; - if (maxHeightUsingMetersPixels != null && - height > maxHeightUsingMetersPixels) { - height = maxHeightUsingMetersPixels; - } - if (maxWidthUsingMetersPixels != null && - width > maxWidthUsingMetersPixels) { - width = maxWidthUsingMetersPixels; - } - - final minHeightUsingMetersPixels = m.minHeightUsingMetersPixels; - final minWidthUsingMetersPixels = m.minWidthUsingMetersPixels; - if (minHeightUsingMetersPixels != null && - height < minHeightUsingMetersPixels) { - height = minHeightUsingMetersPixels; - } - if (minWidthUsingMetersPixels != null && - width < minWidthUsingMetersPixels) { - width = minWidthUsingMetersPixels; + final boxConstraintsUsingMetersInPixels = + m.boxConstraintsUsingMetersInPixels; + if (boxConstraintsUsingMetersInPixels != null) { + if (height > boxConstraintsUsingMetersInPixels.maxHeight) { + height = boxConstraintsUsingMetersInPixels.maxHeight; + } + if (width > boxConstraintsUsingMetersInPixels.maxWidth) { + width = boxConstraintsUsingMetersInPixels.maxWidth; + } + if (height < boxConstraintsUsingMetersInPixels.minHeight) { + height = boxConstraintsUsingMetersInPixels.minHeight; + } + if (width < boxConstraintsUsingMetersInPixels.minWidth) { + width = boxConstraintsUsingMetersInPixels.minWidth; + } } }