Last active
June 26, 2021 18:23
-
-
Save Barttje/8c1e65facf4077857e96b2c229222874 to your computer and use it in GitHub Desktop.
Hexagon Grid Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'dart:math' as math; | |
void main() => runApp(HexagonGridDemo()); | |
class HexagonGridDemo extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
home: Scaffold( | |
appBar: AppBar( | |
title: Text('Hexagon Grid Demo'), | |
), | |
body: Container( | |
color: Colors.grey[200], | |
padding: EdgeInsets.all(8), | |
child: LayoutBuilder(builder: (context, constraints) { | |
return Container( | |
color: Colors.transparent, | |
child: HexagonGrid(constraints.maxWidth, constraints.maxHeight), | |
); | |
}), | |
), | |
), | |
); | |
} | |
} | |
class HexagonGrid extends StatelessWidget { | |
static const int nrX = 6; | |
static const int nrY = 9; | |
static const int marginY = 5; | |
static const int marginX = 5; | |
final double screenWidth; | |
final double screenHeight; | |
final double radius; | |
final double height; | |
final List<HexagonPaint> hexagons = []; | |
HexagonGrid(this.screenWidth, this.screenHeight) | |
: radius = computeRadius(screenWidth, screenHeight), | |
height = computeHeight(computeRadius(screenWidth, screenHeight)) { | |
for (int x = 0; x < nrX; x++) { | |
for (int y = 0; y < nrY; y++) { | |
hexagons.add(HexagonPaint(computeCenter(x, y), radius)); | |
} | |
} | |
} | |
static double computeRadius(double screenWidth, double screenHeight) { | |
var maxWidth = (screenWidth - totalMarginX()) / (((nrX - 1) * 1.5) + 2); | |
var maxHeight = 0.5 * | |
(screenHeight - totalMarginY()) / | |
(heightRatioOfRadius() * (nrY + 0.5)); | |
return math.min(maxWidth, maxHeight); | |
} | |
static double heightRatioOfRadius() => | |
math.cos(math.pi / HexagonPainter.SIDES_OF_HEXAGON); | |
static double totalMarginY() => (nrY - 0.5) * marginY; | |
static int totalMarginX() => (nrX - 1) * marginX; | |
static double computeHeight(double radius) { | |
return heightRatioOfRadius() * radius * 2; | |
} | |
Offset computeCenter(int x, int y) { | |
var centerX = computeX(x); | |
var centerY = computeY(x, y); | |
return Offset(centerX, centerY); | |
} | |
computeY(int x, int y) { | |
var centerY; | |
if (x % 2 == 0) { | |
centerY = y * height + y * marginY + height / 2; | |
} else { | |
centerY = y * height + (y + 0.5) * marginY + height; | |
} | |
double marginsVertical = computeEmptySpaceY() / 2; | |
return centerY + marginsVertical; | |
} | |
double computeEmptySpaceY() { | |
return screenHeight - ((nrY - 1) * height + 1.5 * height + totalMarginY()); | |
} | |
double computeX(int x) { | |
double marginsHorizontal = computeEmptySpaceX() / 2; | |
return x * marginX + x * 1.5 * radius + radius + marginsHorizontal; | |
} | |
double computeEmptySpaceX() { | |
return screenWidth - | |
(totalMarginX() + (nrX - 1) * 1.5 * radius + 2 * radius); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Stack(children: hexagons); | |
} | |
} | |
class HexagonPaint extends StatelessWidget { | |
final Offset center; | |
final double radius; | |
HexagonPaint(this.center, this.radius); | |
@override | |
Widget build(BuildContext context) { | |
return CustomPaint( | |
painter: HexagonPainter(center, radius), | |
); | |
} | |
} | |
class HexagonPainter extends CustomPainter { | |
static const int SIDES_OF_HEXAGON = 6; | |
final double radius; | |
final Offset center; | |
HexagonPainter(this.center, this.radius); | |
@override | |
void paint(Canvas canvas, Size size) { | |
Paint paint = Paint()..color = Colors.blue; | |
Path path = createHexagonPath(); | |
canvas.drawPath(path, paint); | |
} | |
Path createHexagonPath() { | |
final path = Path(); | |
var angle = (math.pi * 2) / SIDES_OF_HEXAGON; | |
Offset firstPoint = Offset(radius * math.cos(0.0), radius * math.sin(0.0)); | |
path.moveTo(firstPoint.dx + center.dx, firstPoint.dy + center.dy); | |
for (int i = 1; i <= SIDES_OF_HEXAGON; i++) { | |
double x = radius * math.cos(angle * i) + center.dx; | |
double y = radius * math.sin(angle * i) + center.dy; | |
path.lineTo(x, y); | |
} | |
path.close(); | |
return path; | |
} | |
@override | |
bool shouldRepaint(CustomPainter oldDelegate) => false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment