widget_ruler2.dart 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. import 'dart:math';
  2. import 'package:flutter/material.dart';
  3. import '../../service/app.dart';
  4. import 'package:get/get.dart';
  5. class Ruler2 extends StatefulWidget {
  6. const Ruler2({
  7. super.key,
  8. required this.isScaleMode,
  9. this.onReturn,
  10. this.mapScale,
  11. });
  12. final bool isScaleMode;
  13. final VoidCallback? onReturn;
  14. final double? mapScale;
  15. @override
  16. State<StatefulWidget> createState() {
  17. return Ruler2State();
  18. }
  19. }
  20. class Ruler2State extends State<Ruler2> {
  21. var _iter1Y = 180.0;
  22. var _iter2Y = 280.0;
  23. static const _iterHeight = 50.0;
  24. static const _iterColorNormal = Colors.green;
  25. static const _iterColorOnTap = Colors.red;
  26. var _iter1Color = _iterColorNormal;
  27. var _iter2Color = _iterColorNormal;
  28. var screenLen = '';
  29. String? mapLen;
  30. @override
  31. void initState() {
  32. super.initState();
  33. onIterChanged();
  34. }
  35. @override
  36. Widget build(BuildContext context) {
  37. final children = <Widget>[
  38. CustomPaint(
  39. painter: _RulerPainter(App.to.heightOneMM(), widget.isScaleMode),
  40. size: Size(context.width, context.height),
  41. )
  42. ];
  43. if (widget.isScaleMode) {
  44. children.addAll([
  45. _lenArrow(context),
  46. _wIter(
  47. context,
  48. _iter1Y,
  49. _iter1Color,
  50. onIter1Update,
  51. () {
  52. _iter1Color = _iterColorOnTap;
  53. },
  54. () {
  55. _iter1Color = _iterColorNormal;
  56. },
  57. ),
  58. _wIter(context, _iter2Y, _iter2Color, onIter2Update, () {
  59. _iter2Color = _iterColorOnTap;
  60. }, () {
  61. _iter2Color = _iterColorNormal;
  62. }),
  63. ]);
  64. _wIterLenText(context, children);
  65. children.add(Positioned(
  66. bottom: 20,
  67. right: 80,
  68. child: GestureDetector(
  69. onTap: widget.onReturn,
  70. child: Image.asset(
  71. 'assets/images/btn_ruler_no_map.png',
  72. width: 46,
  73. ))));
  74. }
  75. return Stack(children: children);
  76. }
  77. onIter1Update(DragUpdateDetails e) {
  78. var tmp = _iter1Y + e.delta.dy;
  79. if (tmp > _iter2Y - _iterHeight || tmp < 30 + _iterHeight) {
  80. return;
  81. }
  82. _iter1Y = tmp;
  83. onIterChanged();
  84. }
  85. onIter2Update(DragUpdateDetails e) {
  86. var tmp = _iter2Y + e.delta.dy;
  87. if (tmp - _iterHeight < _iter1Y || tmp > context.height) {
  88. return;
  89. }
  90. _iter2Y = tmp;
  91. onIterChanged();
  92. }
  93. onIterChanged() {
  94. final heightOneMM = App.to.heightOneMM();
  95. final height = _iter2Y - _iter1Y;
  96. final mm = height / heightOneMM;
  97. final cm = mm / 10;
  98. screenLen = '${cm.toStringAsFixed(1)} cm';
  99. if (widget.mapScale != null) {
  100. var mapL = cm * widget.mapScale! / 100;
  101. var unit = 'm';
  102. if (mapL > 1000) {
  103. mapL /= 1000;
  104. unit = 'km';
  105. }
  106. mapLen = '${mapL.toStringAsFixed(1)} $unit';
  107. }
  108. }
  109. _wIterLenText(
  110. BuildContext context,
  111. List<Widget> children
  112. ) {
  113. var text = screenLen;
  114. if(mapLen!=null){
  115. text += ' ($mapLen)';
  116. }
  117. const textLen = 200.0;
  118. final centerX = context.width / 2 -textLen/2;
  119. children.addAll([
  120. Positioned(
  121. left: centerX - 15,
  122. top: (_iter1Y + _iter2Y) / 2 - _iterHeight/2,
  123. child: Transform.rotate(
  124. angle: pi / 2,
  125. child: SizedBox(width:textLen, child: Text(text, textAlign: TextAlign.center,))
  126. )
  127. ),
  128. Positioned(
  129. left: centerX + 15,
  130. top: (_iter1Y + _iter2Y) / 2 - _iterHeight/2,
  131. child: Transform.rotate(
  132. angle: -pi / 2,
  133. child: SizedBox(width:textLen, child: Text(text, textAlign: TextAlign.center,))
  134. )
  135. ),
  136. ]);
  137. }
  138. Widget _wIter(
  139. BuildContext context,
  140. double y,
  141. Color color,
  142. void Function(DragUpdateDetails e) onUpdate,
  143. VoidCallback onTapDown,
  144. VoidCallback onTapUp,
  145. ) {
  146. return Positioned(
  147. top: y - _iterHeight,
  148. left: 0,
  149. child: GestureDetector(
  150. onPanStart: (e) {
  151. setState(() {
  152. onTapDown();
  153. });
  154. },
  155. onPanEnd: (e) {
  156. setState(() {
  157. onTapUp();
  158. });
  159. },
  160. onPanUpdate: (DragUpdateDetails e) {
  161. setState(() {
  162. onUpdate(e);
  163. });
  164. },
  165. child: Container(
  166. width: context.width,
  167. height: _iterHeight,
  168. color: Colors.white.withAlpha(10),
  169. alignment: Alignment.center,
  170. child: Container(width: context.width, height: 2, color: color),
  171. ),
  172. ));
  173. }
  174. Widget _lenArrow(BuildContext context) {
  175. final height = _iter2Y - _iter1Y;
  176. return Positioned(
  177. top: _iter1Y - _iterHeight / 2,
  178. child: CustomPaint(
  179. painter: _LenArrowPainter(screenLen: screenLen, mapLen: mapLen),
  180. size: Size(context.width, height),
  181. ));
  182. }
  183. }
  184. class _LenArrowPainter extends CustomPainter {
  185. _LenArrowPainter({required this.screenLen, this.mapLen});
  186. final String? mapLen;
  187. final String screenLen;
  188. final textPainter = TextPainter(
  189. textDirection: TextDirection.ltr,
  190. textAlign: TextAlign.center,
  191. );
  192. final style = const TextStyle(
  193. color: Colors.white,
  194. fontSize: 11,
  195. fontWeight: FontWeight.w500,
  196. );
  197. @override
  198. void paint(Canvas canvas, Size size) {
  199. final paint = Paint()
  200. ..color = Colors.white
  201. ..style = PaintingStyle.stroke
  202. ..strokeWidth = 2;
  203. var path = Path();
  204. final centerX = size.width / 2;
  205. const arrowR = 3;
  206. path.moveTo(centerX, 2);
  207. path.lineTo(centerX + arrowR, arrowR * 2 + 2);
  208. path.lineTo(centerX - arrowR, arrowR * 2 + 2);
  209. path.close();
  210. canvas.drawPath(path, paint);
  211. path.moveTo(centerX, size.height - 2);
  212. path.lineTo(centerX + arrowR, size.height - 2 - arrowR * 2);
  213. path.lineTo(centerX - arrowR, size.height - 2 - arrowR * 2);
  214. path.close();
  215. canvas.drawPath(path, paint);
  216. canvas.drawLine(
  217. Offset(size.width / 2, 0), Offset(size.width / 2, size.height), paint);
  218. }
  219. @override
  220. bool shouldRepaint(covariant CustomPainter oldDelegate) {
  221. return false;
  222. }
  223. }
  224. class _RulerPainter extends CustomPainter {
  225. _RulerPainter(this.heightOneMM, this.isScaleMode);
  226. final bool isScaleMode;
  227. final double heightOneMM;
  228. final textPainter = TextPainter(
  229. textDirection: TextDirection.ltr,
  230. textAlign: TextAlign.center,
  231. );
  232. final style = TextStyle(
  233. color: Colors.white.withAlpha(120),
  234. fontSize: 11,
  235. fontWeight: FontWeight.w500,
  236. );
  237. @override
  238. void paint(Canvas canvas, Size size) {
  239. if (isScaleMode) {
  240. final paint = Paint()
  241. ..color = Colors.black.withAlpha((255 * 0.8).round())
  242. ..style = PaintingStyle.fill;
  243. canvas.drawRect(Rect.largest, paint);
  244. }
  245. paintScale(canvas, size);
  246. }
  247. void paintScale(Canvas canvas, Size size) {
  248. final paint = Paint()
  249. ..color = Colors.white
  250. ..style = PaintingStyle.stroke;
  251. var width = 20.0;
  252. const widthSmall = 20.0;
  253. var h = size.height;
  254. var i = 0;
  255. final maxI = size.height ~/ (heightOneMM * 10) * 10;
  256. for (; i <= maxI; i++) {
  257. if (i % 5 == 0) {
  258. width = 33;
  259. } else {
  260. width = widthSmall;
  261. }
  262. if (i % 10 == 0) {
  263. if (i != 0) {
  264. textPainter.text =
  265. TextSpan(text: '${(i / 10).round()} cm', style: style);
  266. textPainter.layout();
  267. textPainter.paint(canvas,
  268. Offset(size.width - widthSmall - textPainter.width - 2, h));
  269. }
  270. if (i != 0) {
  271. textPainter.text =
  272. TextSpan(text: '${(i / 10).round()} cm', style: style);
  273. textPainter.layout();
  274. final hLeft = size.height - ((maxI- i) * heightOneMM);
  275. Offset labelOffset =
  276. Offset(widthSmall + 2, hLeft - textPainter.height);
  277. textPainter.paint(canvas, labelOffset);
  278. }
  279. }
  280. canvas.drawLine(Offset(0, h), Offset(width, h), paint);
  281. canvas.drawLine(
  282. Offset(size.width, h), Offset(size.width - width, h), paint);
  283. h -= heightOneMM;
  284. }
  285. }
  286. @override
  287. bool shouldRepaint(covariant CustomPainter oldDelegate) {
  288. return true;
  289. }
  290. }