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

Fixed CircleMarker's incorrect appearance and size #1692

Merged
merged 6 commits into from
Oct 18, 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
21 changes: 15 additions & 6 deletions example/lib/pages/circle.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,21 @@ class CirclePage extends StatelessWidget {
Widget build(BuildContext context) {
final circleMarkers = <CircleMarker>[
CircleMarker(
point: const LatLng(51.5, -0.09),
color: Colors.blue.withOpacity(0.7),
borderStrokeWidth: 2,
useRadiusInMeter: true,
radius: 2000 // 2000 meters | 2 km
),
point: const LatLng(51.5, -0.09),
color: Colors.blue.withOpacity(0.7),
borderColor: Colors.black,
borderStrokeWidth: 2,
useRadiusInMeter: true,
radius: 2000, // 2000 meters
),
CircleMarker(
point: const LatLng(51.4937, -0.6638), // Dorney Lake is ~2km long
color: Colors.green.withOpacity(0.9),
borderColor: Colors.black,
borderStrokeWidth: 2,
useRadiusInMeter: true,
radius: 1000, // 1000 meters
),
];

return Scaffold(
Expand Down
95 changes: 63 additions & 32 deletions lib/src/layer/circle_layer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,10 @@ class CircleLayer extends StatelessWidget {
Widget build(BuildContext context) {
final map = MapCamera.of(context);
return MobileLayerTransformer(
child: LayoutBuilder(
builder: (context, bc) {
final size = Size(bc.maxWidth, bc.maxHeight);
return CustomPaint(
painter: CirclePainter(circles, map),
size: size,
);
},
child: CustomPaint(
painter: CirclePainter(circles, map),
size: Size(map.size.x, map.size.y),
isComplex: true,
),
);
}
Expand All @@ -65,7 +61,8 @@ class CirclePainter extends CustomPainter {

// Let's calculate all the points grouped by color and radius
final points = <Color, Map<double, List<Offset>>>{};
final pointsBorder = <Color, Map<double, List<Offset>>>{};
final pointsFilledBorder = <Color, Map<double, List<Offset>>>{};
final pointsBorder = <Color, Map<double, Map<double, List<Offset>>>>{};
for (final circle in circles) {
final offset = map.getOffsetFromOrigin(circle.point);
double radius = circle.radius;
Expand All @@ -79,52 +76,86 @@ class CirclePainter extends CustomPainter {
points[circle.color]![radius]!.add(offset);

if (circle.borderStrokeWidth > 0) {
double radiusBorder = circle.radius + circle.borderStrokeWidth;
if (circle.useRadiusInMeter) {
final rBorder = distance.offset(circle.point, radiusBorder, 180);
final deltaBorder = offset - map.getOffsetFromOrigin(rBorder);
radiusBorder = deltaBorder.distance;
// Check if color have some transparency or not
// As drawPoints is more efficient than drawCircle
if (circle.color.alpha == 0xFF) {
double radiusBorder = circle.radius + circle.borderStrokeWidth;
if (circle.useRadiusInMeter) {
final rBorder = distance.offset(circle.point, radiusBorder, 180);
final deltaBorder = offset - map.getOffsetFromOrigin(rBorder);
radiusBorder = deltaBorder.distance;
}
pointsFilledBorder[circle.borderColor] ??= {};
pointsFilledBorder[circle.borderColor]![radiusBorder] ??= [];
pointsFilledBorder[circle.borderColor]![radiusBorder]!.add(offset);
} else {
double realRadius = circle.radius;
if (circle.useRadiusInMeter) {
final rBorder = distance.offset(circle.point, realRadius, 180);
final deltaBorder = offset - map.getOffsetFromOrigin(rBorder);
realRadius = deltaBorder.distance;
}
pointsBorder[circle.borderColor] ??= {};
pointsBorder[circle.borderColor]![circle.borderStrokeWidth] ??= {};
pointsBorder[circle.borderColor]![circle.borderStrokeWidth]![
realRadius] ??= [];
pointsBorder[circle.borderColor]![circle.borderStrokeWidth]![
realRadius]!
.add(offset);
}
pointsBorder[circle.borderColor] ??= {};
pointsBorder[circle.borderColor]![radiusBorder] ??= [];
pointsBorder[circle.borderColor]![radiusBorder]!.add(offset);
}
}

// Now that all the points are grouped, let's draw them
// First by border in order to be under the circle
final paintBorder = Paint()..style = PaintingStyle.stroke;
for (final color in pointsBorder.keys) {
final paint = Paint()
..strokeCap = StrokeCap.round
..isAntiAlias = false
..color = color;
final pointsByRadius = pointsBorder[color]!;
final paint = paintBorder..color = color;
for (final borderWidth in pointsBorder[color]!.keys) {
final pointsByRadius = pointsBorder[color]![borderWidth]!;
final radiusPaint = paint..strokeWidth = borderWidth;
for (final radius in pointsByRadius.keys) {
final pointsByRadiusColor = pointsByRadius[radius]!;
for (final offset in pointsByRadiusColor) {
_paintCircle(canvas, offset, radius, radiusPaint);
}
}
}
}

// Then the filled border in order to be under the circle
final paintPoint = Paint()
..isAntiAlias = false
..strokeCap = StrokeCap.round;
for (final color in pointsFilledBorder.keys) {
final paint = paintPoint..color = color;
final pointsByRadius = pointsFilledBorder[color]!;
for (final radius in pointsByRadius.keys) {
final pointsByRadiusColor = pointsByRadius[radius]!;
final radiusPaint = paint..strokeWidth = radius;
_paintCircle(canvas, pointsByRadiusColor, radiusPaint);
final radiusPaint = paint..strokeWidth = radius * 2;
_paintPoints(canvas, pointsByRadiusColor, radiusPaint);
}
}

// And then the circle
for (final color in points.keys) {
final paint = Paint()
..isAntiAlias = false
..strokeCap = StrokeCap.round
..color = color;
final paint = paintPoint..color = color;
final pointsByRadius = points[color]!;
for (final radius in pointsByRadius.keys) {
final pointsByRadiusColor = pointsByRadius[radius]!;
final radiusPaint = paint..strokeWidth = radius;
_paintCircle(canvas, pointsByRadiusColor, radiusPaint);
final radiusPaint = paint..strokeWidth = radius * 2;
_paintPoints(canvas, pointsByRadiusColor, radiusPaint);
}
}
}

void _paintCircle(Canvas canvas, List<Offset> offsets, Paint paint) {
void _paintPoints(Canvas canvas, List<Offset> offsets, Paint paint) {
canvas.drawPoints(PointMode.points, offsets, paint);
}

void _paintCircle(Canvas canvas, Offset offset, double radius, Paint paint) {
canvas.drawCircle(offset, radius, paint);
}

@override
bool shouldRepaint(CirclePainter oldDelegate) => false;
}
Loading