Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add option to draw labels on top of all Polygons #1707

Merged
merged 2 commits into from
Oct 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 32 additions & 44 deletions lib/src/layer/polygon_layer/label.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<LatLng> locs,
LatLng labelLoc, {
void Function(Canvas canvas)? buildLabelTextPainter({
required Offset placementPoint,
required List<Offset> 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) {
JaffaKetchup marked this conversation as resolved.
Show resolved Hide resolved
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;
}
Expand Down Expand Up @@ -89,9 +78,8 @@ LatLng _computePolylabel(List<LatLng> 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;
}
43 changes: 35 additions & 8 deletions lib/src/layer/polygon_layer/polygon_layer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
),
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -235,7 +241,7 @@ class PolygonPainter extends CustomPainter {
}
}

if (polygonLabels && polygon.label != null) {
if (polygonLabels && !drawLabelsLast && polygon.label != null) {
JaffaKetchup marked this conversation as resolved.
Show resolved Hide resolved
// Labels are expensive because:
// * they themselves cannot easily be pulled into our batched path
// painting with the given text APIs
Expand All @@ -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) {
Expand All @@ -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) {
Expand Down
Loading