Skip to content

Commit

Permalink
Compute label position in map/coordinate space rather than pixel space (
Browse files Browse the repository at this point in the history
  • Loading branch information
ignatz authored Sep 7, 2023
1 parent 8223328 commit f73a2e3
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 22 deletions.
1 change: 1 addition & 0 deletions example/lib/pages/polygon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ class PolygonPage extends StatelessWidget {
borderColor: Colors.purple,
label: "Rotated!",
rotateLabel: true,
labelPlacement: PolygonLabelPlacement.polylabel,
),
Polygon(
points: holeOuterPoints,
Expand Down
58 changes: 38 additions & 20 deletions lib/src/layer/label.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,22 @@ import 'dart:math' as math;
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/plugin_api.dart';
import 'package:latlong2/latlong.dart';
import 'package:polylabel/polylabel.dart';

void Function(Canvas canvas)? buildLabelTextPainter({
required String labelText,
void Function(Canvas canvas)? buildLabelTextPainter(
List<LatLng> locs,
LatLng labelLoc, {
required Offset placementPoint,
required List<Offset> points,
required String labelText,
required double rotationRad,
bool rotate = false,
TextStyle? labelStyle,
PolygonLabelPlacement labelPlacement = PolygonLabelPlacement.polylabel,
double padding = 0,
}) {
final placementPoint = switch (labelPlacement) {
PolygonLabelPlacement.centroid => _computeCentroid(points),
PolygonLabelPlacement.polylabel => _computePolylabel(points),
};

var dx = placementPoint.dx;
var dy = placementPoint.dy;
double dx = placementPoint.dx;
double dy = placementPoint.dy;

if (dx > 0) {
final textSpan = TextSpan(text: labelText, style: labelStyle);
Expand Down Expand Up @@ -63,17 +61,37 @@ void Function(Canvas canvas)? buildLabelTextPainter({
return null;
}

Offset _computeCentroid(List<Offset> points) {
return Offset(
points.map((e) => e.dx).average,
points.map((e) => e.dy).average,
LatLng computeLabelPosition(
PolygonLabelPlacement labelPlacement, List<LatLng> points) {
return switch (labelPlacement) {
PolygonLabelPlacement.centroid => _computeCentroid(points),
PolygonLabelPlacement.polylabel => _computePolylabel(points),
};
}

LatLng _computeCentroid(List<LatLng> points) {
return LatLng(
points.map((e) => e.latitude).average,
points.map((e) => e.longitude).average,
);
}

Offset _computePolylabel(List<Offset> points) {
final labelPosition = polylabel([
List<math.Point>.generate(
points.length, (i) => math.Point(points[i].dx, points[i].dy)),
]);
return labelPosition.point.toOffset();
LatLng _computePolylabel(List<LatLng> points) {
final labelPosition = polylabel(
[
List<math.Point>.generate(points.length,
(i) => math.Point(points[i].longitude, points[i].latitude)),
],
// "precision" is a bit of a misnomer. It's a threshold for when to stop
// dividing-and-conquering the polygon in the hopes of finding a better
// point with more distance to the polygon's outline. It's given in
// point-units, i.e. degrees here. A bigger number means less precision,
// i.e. cheaper at the expense off less optimal label placement.
precision: 0.000001,
);
final latlng = LatLng(
labelPosition.point.y.toDouble(),
labelPosition.point.x.toDouble(),
);
return latlng;
}
10 changes: 8 additions & 2 deletions lib/src/layer/polygon_layer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@ class Polygon {
// of opposing clock-directions cut holes into each other leading to a leaky optimization.
final bool _filledAndClockwise;

LatLngBounds? _boundingBox;
// Location where to place the label if `label` is set.
LatLng? _labelPosition;
LatLng get labelPosition =>
_labelPosition ??= computeLabelPosition(labelPlacement, points);

LatLngBounds? _boundingBox;
LatLngBounds get boundingBox =>
_boundingBox ??= LatLngBounds.fromPoints(points);

Expand Down Expand Up @@ -240,12 +244,14 @@ 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,
labelPlacement: polygon.labelPlacement,
padding: 10,
);

Expand Down

0 comments on commit f73a2e3

Please sign in to comment.