Skip to content
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;
}