diff --git a/lib/src/layer/polygon_layer/label.dart b/lib/src/layer/polygon_layer/label.dart index da2c5195c..3f3684470 100644 --- a/lib/src/layer/polygon_layer/label.dart +++ b/lib/src/layer/polygon_layer/label.dart @@ -6,57 +6,46 @@ import 'package:flutter_map/src/layer/polygon_layer/polygon_layer.dart'; import 'package:latlong2/latlong.dart'; import 'package:polylabel/polylabel.dart'; -void Function(Canvas canvas)? buildLabelTextPainter( - List locs, - LatLng labelLoc, { +void Function(Canvas canvas)? buildLabelTextPainter({ required Offset placementPoint, required List points, required String labelText, required double rotationRad, - bool rotate = false, - TextStyle? labelStyle, - double padding = 0, + required bool rotate, + required TextStyle labelStyle, + required double padding, }) { - double dx = placementPoint.dx; - double dy = placementPoint.dy; + final textSpan = TextSpan(text: labelText, style: labelStyle); + final textPainter = TextPainter( + text: textSpan, + textAlign: TextAlign.center, + textDirection: TextDirection.ltr, + )..layout(); - if (dx > 0) { - final textSpan = TextSpan(text: labelText, style: labelStyle); - final textPainter = TextPainter( - text: textSpan, - textAlign: TextAlign.center, - textDirection: TextDirection.ltr, - maxLines: 1, - ); + final dx = placementPoint.dx - textPainter.width / 2; + final dy = placementPoint.dy - textPainter.height / 2; - textPainter.layout(); - dx -= textPainter.width / 2; - dy -= textPainter.height / 2; + double maxDx = 0; + var minDx = double.infinity; + for (final point in points) { + maxDx = math.max(maxDx, point.dx); + minDx = math.min(minDx, point.dx); + } - var maxDx = 0.0; - var minDx = double.infinity; - for (final point in points) { - maxDx = math.max(maxDx, point.dx); - minDx = math.min(minDx, point.dx); - } + if (maxDx - minDx - padding > textPainter.width) { + return (canvas) { + if (rotate) { + canvas.save(); + canvas.translate(placementPoint.dx, placementPoint.dy); + canvas.rotate(-rotationRad); + canvas.translate(-placementPoint.dx, -placementPoint.dy); + } - if (maxDx - minDx - padding > textPainter.width) { - return (canvas) { - if (rotate) { - canvas.save(); - canvas.translate(placementPoint.dx, placementPoint.dy); - canvas.rotate(-rotationRad); - canvas.translate(-placementPoint.dx, -placementPoint.dy); - } - textPainter.paint( - canvas, - Offset(dx, dy), - ); - if (rotate) { - canvas.restore(); - } - }; - } + textPainter.paint(canvas, Offset(dx, dy)); + if (rotate) { + canvas.restore(); + } + }; } return null; } @@ -89,9 +78,8 @@ LatLng _computePolylabel(List points) { // i.e. cheaper at the expense off less optimal label placement. precision: 0.000001, ); - final latlng = LatLng( + return LatLng( labelPosition.point.y.toDouble(), labelPosition.point.x.toDouble(), ); - return latlng; } diff --git a/lib/src/layer/polygon_layer/polygon_layer.dart b/lib/src/layer/polygon_layer/polygon_layer.dart index 16381e423..7b1382808 100644 --- a/lib/src/layer/polygon_layer/polygon_layer.dart +++ b/lib/src/layer/polygon_layer/polygon_layer.dart @@ -98,11 +98,15 @@ class PolygonLayer extends StatelessWidget { // Turn on/off per-polygon label drawing on the layer-level. final bool polygonLabels; + // Whether to draw labels last and thus over all the polygons. + final bool drawLabelsLast; + const PolygonLayer({ super.key, required this.polygons, this.polygonCulling = false, this.polygonLabels = true, + this.drawLabelsLast = false, }); @override @@ -118,7 +122,7 @@ class PolygonLayer extends StatelessWidget { return MobileLayerTransformer( child: CustomPaint( - painter: PolygonPainter(pgons, map, polygonLabels), + painter: PolygonPainter(pgons, map, polygonLabels, drawLabelsLast), size: size, isComplex: true, ), @@ -131,8 +135,10 @@ class PolygonPainter extends CustomPainter { final MapCamera map; final LatLngBounds bounds; final bool polygonLabels; + final bool drawLabelsLast; - PolygonPainter(this.polygons, this.map, this.polygonLabels) + PolygonPainter( + this.polygons, this.map, this.polygonLabels, this.drawLabelsLast) : bounds = map.visibleBounds; int get hash { @@ -189,10 +195,10 @@ class PolygonPainter extends CustomPainter { // Main loop constructing batched fill and border paths from given polygons. for (final polygon in polygons) { - final offsets = getOffsets(polygon.points); - if (offsets.isEmpty) { + if (polygon.points.isEmpty) { continue; } + final offsets = getOffsets(polygon.points); // The hash is based on the polygons visual properties. If the hash from // the current and the previous polygon no longer match, we need to flush @@ -235,7 +241,7 @@ class PolygonPainter extends CustomPainter { } } - if (polygonLabels && polygon.label != null) { + if (polygonLabels && !drawLabelsLast && polygon.label != null) { // Labels are expensive because: // * they themselves cannot easily be pulled into our batched path // painting with the given text APIs @@ -246,15 +252,13 @@ class PolygonPainter extends CustomPainter { // The painter will be null if the layouting algorithm determined that // there isn't enough space. final painter = buildLabelTextPainter( - polygon.points, - polygon.labelPosition, placementPoint: map.getOffsetFromOrigin(polygon.labelPosition), points: offsets, labelText: polygon.label!, labelStyle: polygon.labelStyle, rotationRad: map.rotationRad, rotate: polygon.rotateLabel, - padding: 10, + padding: 20, ); if (painter != null) { @@ -267,6 +271,29 @@ class PolygonPainter extends CustomPainter { } drawPaths(); + + if (polygonLabels && drawLabelsLast) { + for (final polygon in polygons) { + if (polygon.points.isEmpty) { + continue; + } + final offsets = getOffsets(polygon.points); + + if (polygon.label != null) { + final painter = buildLabelTextPainter( + placementPoint: map.getOffsetFromOrigin(polygon.labelPosition), + points: offsets, + labelText: polygon.label!, + labelStyle: polygon.labelStyle, + rotationRad: map.rotationRad, + rotate: polygon.rotateLabel, + padding: 20, + ); + + painter?.call(canvas); + } + } + } } Paint _getBorderPaint(Polygon polygon) {