Created
December 24, 2020 08:40
-
-
Save escamoteur/a76fd4be7406228153ef4e9f813bce0e to your computer and use it in GitHub Desktop.
AntennaWidget
This file contains hidden or 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 'dart:math' as math; | |
import 'package:flutter/material.dart'; | |
import 'package:vector_math/vector_math_64.dart' show radians; | |
/// Used to display Antennas on the Map as well as | |
/// the compass in aiming mode | |
class AntennaWidget extends StatelessWidget { | |
const AntennaWidget({ | |
Key key, | |
@required this.radius, | |
@required this.azimuth, | |
@required this.segments, | |
this.showAntennaGrid = true, | |
this.color, | |
this.isAimingCompass = false, | |
// currently not used | |
// this.children, | |
}) : super(key: key); | |
final double radius; | |
/// This is currently ignored | |
final List<double> segments; | |
final bool showAntennaGrid; | |
// final List<AntennaPoint> children; | |
final double azimuth; | |
final Color color; | |
final bool isAimingCompass; | |
@override | |
Widget build(BuildContext context) { | |
final size = radius * 2; | |
return SizedBox( | |
width: size, | |
height: size, | |
child: CustomPaint( | |
painter: _AntennaGraphPainter( | |
azimuth: azimuth, | |
showAntennaGrid: showAntennaGrid, | |
isAimingCompass: isAimingCompass, | |
color: color), | |
size: Size(size, size), | |
// child: children != null | |
// ? Flow( | |
// delegate: _AntennaGraphFlowDelegate(this), | |
// children: children, | |
// ) | |
// : null, | |
), | |
); | |
} | |
} | |
enum AntennaSizes { big, medium, small, min } | |
class _AntennaGraphPainter extends CustomPainter { | |
final double azimuth; | |
final bool showAntennaGrid; | |
final Color color; | |
final bool isAimingCompass; | |
_AntennaGraphPainter( | |
{@required this.showAntennaGrid, | |
@required this.azimuth, | |
this.isAimingCompass, | |
this.color = Colors.white}) { | |
_text = TextPainter( | |
textDirection: TextDirection.ltr, | |
); | |
} | |
TextPainter _text; | |
@override | |
void paint(Canvas canvas, Size size) { | |
const numberOfSegments = 12; | |
final double segmentSize = radians(360 / numberOfSegments); | |
final outerRadius = size.shortestSide * 0.5; | |
double antennaCenterRadius = 10.0; | |
double innerRadius; | |
double rings = 1; | |
double textSize; | |
AntennaSizes antennaSize; | |
/// depending on the antenna size we draw it with | |
/// different levels of details | |
if (outerRadius >= 160) { | |
antennaCenterRadius = 20.0; | |
rings = 4; | |
antennaSize = AntennaSizes.big; | |
textSize = 14; | |
} else if (outerRadius >= 100) { | |
antennaCenterRadius = 15.0; | |
rings = 3; | |
antennaSize = AntennaSizes.medium; | |
textSize = 12; | |
} else if (outerRadius >= 50) { | |
rings = 2; | |
antennaSize = AntennaSizes.small; | |
textSize = 10; | |
} else { | |
rings = 2; | |
antennaSize = AntennaSizes.min; | |
} | |
innerRadius = math.max( | |
antennaCenterRadius + outerRadius / (rings + 2), outerRadius * 0.2); | |
final double ringDistance = (outerRadius - innerRadius) * 0.9 / rings; | |
final segmentPaint = Paint() | |
..color = color.withOpacity(0.7) | |
..style = PaintingStyle.stroke | |
..strokeWidth = 1.2; | |
final edgePaint = Paint() | |
..color = color | |
..style = PaintingStyle.stroke | |
..strokeWidth = 2.5; | |
final centerEdgePaint = Paint() | |
..color = color | |
..strokeWidth = 2 | |
..style = PaintingStyle.stroke; | |
final centerFillPaint = Paint() | |
..color = isAimingCompass ? Colors.green : color | |
..style = PaintingStyle.fill; | |
canvas.save(); | |
final center = size.center(Offset.zero); | |
canvas.translate(center.dx, center.dy); | |
if (showAntennaGrid) { | |
// Antenna segments | |
// draw circles | |
for (double circleRadius = innerRadius; | |
circleRadius <= outerRadius - ringDistance; | |
circleRadius += ringDistance) { | |
canvas.drawCircle(Offset.zero, circleRadius, segmentPaint); | |
} | |
canvas.drawCircle(Offset.zero, innerRadius, segmentPaint); | |
canvas.drawCircle(Offset.zero, outerRadius, edgePaint); | |
final segmentStart = Offset(innerRadius - 6.0, 0.0); | |
final segmentEnd = Offset(outerRadius * 0.8, 0.0); | |
// Draw Antenna segments | |
for (int i = 0; i < numberOfSegments; i++) { | |
canvas.drawLine(segmentStart, segmentEnd, segmentPaint); | |
canvas.rotate(segmentSize); | |
} | |
if (antennaSize != AntennaSizes.min) { | |
// Draw small units every 10 degrees | |
for (int i = 0; i < 360 / 10; i++) { | |
canvas.drawLine(Offset(outerRadius - 6.0, 0.0), | |
Offset(outerRadius, 0), edgePaint); | |
canvas.rotate(radians(10)); | |
} | |
// draw 90° marker lines | |
for (int i = 0; i < 4; i++) { | |
canvas.rotate(radians(90)); | |
canvas.drawLine(Offset(innerRadius, 0.0), | |
Offset(outerRadius - ringDistance, 0), edgePaint); | |
} | |
if (outerRadius >= 50.0) { | |
for (int i = 0; i < 12; i++) { | |
final angle = i * 30.0; | |
_drawText(canvas, angle, outerRadius - 16.0, | |
angle.toStringAsFixed(0), textSize); | |
} | |
} | |
} | |
} | |
// draw antenna center | |
if (!isAimingCompass) { | |
final rect = | |
Rect.fromCircle(center: Offset.zero, radius: antennaCenterRadius); | |
canvas.drawArc(rect, radians(90.0) - azimuth, radians(-180.0), true, | |
centerFillPaint); | |
} else { | |
canvas.drawCircle(Offset.zero, antennaCenterRadius, centerFillPaint); | |
} | |
canvas.drawCircle(Offset.zero, antennaCenterRadius, centerEdgePaint); | |
canvas.restore(); | |
} | |
/// used to draw the degrees around the Antenna | |
void _drawText(Canvas canvas, double angle, double radius, String text, | |
double textSize) { | |
_text.text = TextSpan(text: text, style: TextStyle(fontSize: textSize)); | |
_text.layout(); | |
final center = _text.size.center(Offset.zero); | |
final x = math.cos(radians(-90 + angle)) * radius - center.dx; | |
final y = math.sin(radians(-90 + angle)) * radius - center.dy; | |
_text.paint(canvas, Offset(x, y)); | |
} | |
@override | |
bool shouldRepaint(CustomPainter oldDelegate) { | |
return true; | |
} | |
} | |
/// This would draw the Small arrows on the bearing lines iside the antenna | |
/// Currently not used becaus the antennas get to small | |
// class BearingIndicator extends StatelessWidget implements AntennaPoint { | |
// const BearingIndicator({ | |
// Key key, | |
// this.heading, | |
// }) : super(key: key); | |
// @override | |
// final double heading; | |
// @override | |
// Widget build(BuildContext context) { | |
// return Row( | |
// mainAxisSize: MainAxisSize.min, | |
// children: <Widget>[ | |
// Icon( | |
// Icons.arrow_right, | |
// size: 48.0, | |
// color: Colors.white, | |
// ), | |
// Container( | |
// width: 8.0, | |
// height: 8.0, | |
// color: Colors.blue, | |
// ), | |
// ], | |
// ); | |
// } | |
// } | |
// abstract class AntennaPoint implements Widget { | |
// double get heading; | |
// } | |
// class _AntennaGraphFlowDelegate extends FlowDelegate { | |
// _AntennaGraphFlowDelegate(this.widget); | |
// final AntennaWidget widget; | |
// @override | |
// BoxConstraints getConstraintsForChild(int i, BoxConstraints constraints) => | |
// constraints.loosen(); | |
// @override | |
// void paintChildren(FlowPaintingContext context) { | |
// final center = context.size.center(Offset.zero); | |
// final centerMatrix = Matrix4.translationValues(center.dx, center.dy, 0.0); | |
// final radius = widget.radius; | |
// for (int i = 0; i < context.childCount; i++) { | |
// final heading = widget.children[i].heading; | |
// final childSize = context.getChildSize(i); | |
// context.paintChild(i, | |
// transform: centerMatrix * | |
// Matrix4.rotationZ(radians(-90 + heading)) * | |
// Matrix4.translationValues( | |
// radius - childSize.width, -childSize.height * 0.5, 0.0)); | |
// } | |
// } | |
// @override | |
// bool shouldRepaint(FlowDelegate oldDelegate) { | |
// return true; | |
// } | |
//} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment