-
Notifications
You must be signed in to change notification settings - Fork 5
/
raw_recursive_squares_grid.dart
132 lines (113 loc) · 3.35 KB
/
raw_recursive_squares_grid.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import 'package:flutter/material.dart';
class RawRecursiveSquaresGrid extends StatelessWidget {
const RawRecursiveSquaresGrid({
super.key,
this.side = 80,
this.strokeWidth = 1.5,
this.gap = 10,
this.minSquareSideFraction = 0.2,
});
final double side;
final double strokeWidth;
final double gap;
final double minSquareSideFraction;
@override
Widget build(BuildContext context) {
return ColoredBox(
color: Colors.white,
child: SizedBox.expand(
child: CustomPaint(
painter: _RecursiveSquaresCustomPainter(
sideLength: side,
strokeWidth: strokeWidth,
minSquareSideFraction: minSquareSideFraction,
gap: gap,
),
),
),
);
}
}
class _RecursiveSquaresCustomPainter extends CustomPainter {
_RecursiveSquaresCustomPainter({
this.sideLength = 80,
this.strokeWidth = 2,
this.gap = 10,
this.minSquareSideFraction = 0.2,
}) : minSideLength = sideLength * minSquareSideFraction;
final double sideLength;
final double strokeWidth;
final double gap;
final double minSideLength;
final double minSquareSideFraction;
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..style = PaintingStyle.stroke
..strokeWidth = strokeWidth;
// Calculate the number of squares that can fit on the horizontal axis
final xCount = ((size.width + gap) / (sideLength + gap)).floor();
// Calculate the number of squares that can fit on the vertical axis
final yCount = ((size.height + gap) / (sideLength + gap)).floor();
// Calculate the size of the grid of squares
final contentSize = Size(
(xCount * sideLength) + ((xCount - 1) * gap),
(yCount * sideLength) + ((yCount - 1) * gap),
);
// Calculate the offset from which we should start painting
// the grid so that it is eventually centered
final offset = Offset(
(size.width - contentSize.width) / 2,
(size.height - contentSize.height) / 2,
);
final totalCount = xCount * yCount;
canvas.save();
canvas.translate(offset.dx, offset.dy);
for (int index = 0; index < totalCount; index++) {
int i = index ~/ yCount;
int j = index % yCount;
// Recursively draw squares
drawNestedSquares(
canvas,
Offset(
(i * (sideLength + gap)),
(j * (sideLength + gap)),
),
sideLength,
paint,
);
}
canvas.restore();
}
void drawNestedSquares(
Canvas canvas,
Offset start,
double sideLength,
Paint paint,
) {
// Recursively draw squares until the side of the square
// reaches the minimum defined by the `minSideLength` input
if (sideLength < minSideLength) return;
canvas.drawRect(
Rect.fromLTWH(
start.dx,
start.dy,
sideLength,
sideLength,
),
paint,
);
// calculate the side length for the next square
final nextSideLength = sideLength * 0.8;
final nextStart = Offset(
start.dx + sideLength / 2 - nextSideLength / 2,
start.dy + sideLength / 2 - nextSideLength / 2,
);
// recursive call with the next side length and starting point
drawNestedSquares(canvas, nextStart, nextSideLength, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}