compass.dart 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. import 'dart:math';
  2. import 'package:flutter/material.dart';
  3. import 'package:get/get.dart';
  4. import '../styles/theme.dart';
  5. import 'package:sensor/sensor.dart' as sensor;
  6. class Compass extends StatelessWidget {
  7. const Compass(
  8. {super.key,
  9. required this.compassRadians,
  10. required this.mapNorthRadians,
  11. required this.orientation,
  12. required this.diameter,
  13. this.nextPointRadians
  14. });
  15. final double diameter;
  16. final double compassRadians;
  17. final double mapNorthRadians;
  18. final sensor.Orientation orientation;
  19. final double? nextPointRadians;
  20. int getDegrees(){
  21. var d = (mapNorthRadians-compassRadians)*180~/pi;
  22. while(d < 0){
  23. d+=360;
  24. }
  25. while(d > 360){
  26. d-=360;
  27. }
  28. return d;
  29. }
  30. @override
  31. Widget build(BuildContext context) {
  32. return Stack(
  33. children: [
  34. Transform.rotate(angle: compassRadians, child: SizedBox(
  35. width: diameter,
  36. height: diameter,
  37. child: CustomPaint(painter: _ArrowPainter()),
  38. ),),
  39. Transform.rotate(angle: mapNorthRadians, child: SizedBox(
  40. width: diameter,
  41. height: diameter,
  42. child: CustomPaint(painter: _PlatePainter()),
  43. )),
  44. nextPointRadians != null? Transform.rotate(angle: nextPointRadians!, child: SizedBox(
  45. width: diameter,
  46. height: diameter,
  47. child: CustomPaint(painter: _NextPointArrowPainter()),
  48. )): const SizedBox(),
  49. SizedBox(
  50. width: diameter,
  51. height: diameter,
  52. child: CustomPaint(painter: _OrientationPainter(orientation)),
  53. ),
  54. Container(
  55. width: diameter,
  56. alignment: Alignment.topCenter,
  57. padding: const EdgeInsets.only(top: 30),
  58. child: Text(' ${getDegrees()}°'))
  59. ],
  60. );
  61. }
  62. }
  63. void drawArrow(Canvas canvas, Paint painter, Offset topCenter){
  64. final path = Path();
  65. var x = topCenter.dx;
  66. var y = topCenter.dy;
  67. path.moveTo(x, y);
  68. x += 5;
  69. y +=10;
  70. path.lineTo(x, y);
  71. x -= 5;
  72. y -= 2;
  73. path.lineTo(x, y);
  74. x -= 5;
  75. y += 2;
  76. path.lineTo(x, y);
  77. path.close();
  78. painter.style = PaintingStyle.fill;
  79. canvas.drawPath(path, painter);
  80. }
  81. class _ArrowPainter extends CustomPainter {
  82. var textPainter = TextPainter();
  83. final painter = Paint();
  84. @override
  85. void paint(Canvas canvas, Size size) {
  86. var radius = size.height / 2 - 4;
  87. painter.isAntiAlias = true;
  88. painter.style = PaintingStyle.stroke;
  89. painter.color = const Color(0x5eaff59f);
  90. final center = Offset(size.height / 2, size.width / 2);
  91. final centerX = center.dx;
  92. final centerY = center.dy;
  93. canvas.drawCircle(center, radius, painter);
  94. radius -= 3;
  95. painter.style = PaintingStyle.fill;
  96. painter.color = Colors.white.withAlpha(120);
  97. canvas.drawCircle(center, radius, painter);
  98. painter.color = const Color(0xff92b686);
  99. painter.strokeWidth = 0.5;
  100. painter.style = PaintingStyle.stroke;
  101. textPainter = TextPainter(
  102. textDirection: TextDirection.ltr,
  103. textAlign: TextAlign.center,
  104. );
  105. double angle = 0;
  106. const padding = 4;
  107. for (int i = 0; i < 360; i += 5) {
  108. angle = (i-90) * pi / 180;
  109. var start = Offset(
  110. centerX + (radius - padding - 5) * cos(angle),
  111. centerY + (radius - padding - 5) * sin(angle),
  112. );
  113. var end = Offset(
  114. centerX + (radius - padding) * cos(angle),
  115. centerY + (radius - padding) * sin(angle),
  116. );
  117. if (i % 30 == 0) {
  118. start = Offset(
  119. centerX + (radius - padding - 8) * cos(angle),
  120. centerY + (radius - padding - 8) * sin(angle),
  121. );
  122. // String label = "$i";
  123. // textPainter.text = TextSpan(
  124. // text: label,
  125. // style: const TextStyle(
  126. // color: Colors.black,
  127. // fontSize: 8,
  128. // fontWeight: FontWeight.w100,
  129. // ),
  130. // );
  131. // textPainter.layout();
  132. // Offset labelOffset =
  133. // Offset(
  134. // start.dx - 10 * cos(angle) - textPainter.width / 2,
  135. // start.dy - 10 * sin(angle) - textPainter.height / 2);
  136. // textPainter.paint(canvas, labelOffset);
  137. }
  138. canvas.drawLine(start, end, painter);
  139. }
  140. painter.color = Colors.red;
  141. drawArrow(canvas, painter, Offset(centerX, radius - 40));
  142. }
  143. @override
  144. bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
  145. }
  146. class _PlatePainter extends CustomPainter {
  147. final painter = Paint()
  148. ..color = const Color(0xff92b686)
  149. ..style = PaintingStyle.fill;
  150. @override
  151. void paint(Canvas canvas, Size size) {
  152. final centerX = size.width/2;
  153. final path = Path();
  154. var x = centerX;
  155. var y = 20.0;
  156. path.moveTo(x, y);
  157. x += 5;
  158. y = 0;
  159. path.lineTo(x, y);
  160. x -= 10;
  161. path.lineTo(x, y);
  162. path.close();
  163. canvas.drawPath(path, painter);
  164. }
  165. @override
  166. bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
  167. }
  168. class _NextPointArrowPainter extends CustomPainter {
  169. final painter = Paint()
  170. ..color = const Color(0xffffcb00);
  171. @override
  172. void paint(Canvas canvas, Size size) {
  173. final centerX = size.width/2;
  174. var radius = size.height / 2 - 4;
  175. drawArrow(canvas, painter, Offset(centerX, radius-40));
  176. }
  177. @override
  178. bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
  179. }
  180. class _OrientationPainter extends CustomPainter {
  181. _OrientationPainter(this.orientation);
  182. final sensor.Orientation orientation;
  183. final painter1 = Paint()
  184. ..color = Colors.grey
  185. ..style = PaintingStyle.fill
  186. ..blendMode = BlendMode.xor
  187. ;
  188. final painter2 = Paint()
  189. ..color = const Color(0xff38941b)
  190. ..style = PaintingStyle.fill
  191. ;
  192. @override
  193. void paint(Canvas canvas, Size size) {
  194. final centerX = size.width/2;
  195. final centerY = centerX;
  196. const radius1 = 10.0;
  197. const radius2 = radius1+2;
  198. const maxOffset = 20;
  199. var d = sqrt(orientation.x * orientation.x + orientation.y * orientation.y);
  200. var len = d / sqrt(pi/2 * pi/2 + pi/2 * pi/2) * maxOffset;
  201. var dx = 0.0;
  202. var dy = 0.0;
  203. if(d!=0){
  204. dx = len * (orientation.y / d) / 2;
  205. dy = len * (orientation.x / d) / 2;
  206. }
  207. final c1 = Offset(centerX + dx, centerY + dy);
  208. final c2 = Offset(centerX - dx, centerY - dy);
  209. canvas.saveLayer(null, Paint());
  210. canvas.drawCircle(c2, radius2, painter2);
  211. canvas.drawCircle(c1, radius1, painter1);
  212. canvas.restore();
  213. }
  214. @override
  215. bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
  216. }
  217. void main() async {
  218. runApp(GetMaterialApp(
  219. theme: appThemeData(),
  220. home: Container(
  221. width: double.infinity,
  222. height: double.infinity,
  223. color: Colors.white,
  224. alignment: Alignment.center,
  225. child: Compass(
  226. diameter: 140,
  227. compassRadians: 0,
  228. mapNorthRadians: 0,
  229. orientation: sensor.Orientation()
  230. ..x = 45
  231. ..y = 45,
  232. ))));
  233. }