widget_ruler.dart 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import '../../styles/theme.dart';
  4. class Ruler extends StatelessWidget{
  5. const Ruler({
  6. super.key,
  7. required this.hideHeight,
  8. required this.mapScale});
  9. final double hideHeight;
  10. final double mapScale;
  11. @override
  12. Widget build(BuildContext context) {
  13. return CustomPaint(
  14. size: Size(context.width, context.height),
  15. painter: _RulerPainter(
  16. hideHeight: hideHeight,
  17. mapScale: mapScale
  18. ),
  19. );
  20. }
  21. }
  22. class _Scale{
  23. var text = '';
  24. var px = 0.0;
  25. var meter = 0;
  26. _Scale(this.text, this.px, this.meter);
  27. }
  28. class _RulerPainter extends CustomPainter {
  29. _RulerPainter({
  30. required this.hideHeight,
  31. required this.mapScale,
  32. });
  33. final double hideHeight;
  34. final double mapScale;
  35. static const Color _color = Colors.black;
  36. final painter = Paint()
  37. ..color = _color
  38. ..strokeWidth = 1.5;
  39. final textPainter = TextPainter(
  40. textDirection: TextDirection.ltr,
  41. textAlign: TextAlign.center,
  42. );
  43. final path = Path();
  44. @override
  45. void paint(Canvas canvas, Size size) {
  46. final centerX = size.width/2;
  47. const arrowHeight = 24.0;
  48. canvas.drawLine(Offset(centerX, arrowHeight), Offset(centerX, size.height - hideHeight), painter);
  49. final oneScale = _getScale();
  50. const steps = 10.0;
  51. double heightLeft = size.height;
  52. final scaleXLeft = centerX-5;
  53. final scaleXRight = centerX + 5;
  54. final littleScale = oneScale.px / steps;
  55. final littleScaleXLeft = scaleXLeft + 2;
  56. final littleScaleXRight = scaleXRight - 2;
  57. path.moveTo(centerX, 0);
  58. path.lineTo(centerX + 5, arrowHeight);
  59. path.lineTo(centerX - 5, arrowHeight);
  60. path.close();
  61. canvas.drawPath(path, painter);
  62. for(var i = 0; heightLeft > arrowHeight + 1;i++){
  63. if(size.height - heightLeft < hideHeight){
  64. heightLeft -= littleScale;
  65. continue;
  66. }
  67. if(i % steps == 0){
  68. canvas.drawLine(Offset(scaleXLeft, heightLeft), Offset(scaleXRight, heightLeft), painter);
  69. textPainter.text = TextSpan(
  70. text: _meterToStr(i ~/ steps * oneScale.meter),
  71. style: const TextStyle(
  72. color: _color,
  73. fontSize: 14,
  74. fontWeight: FontWeight.w500,
  75. ),
  76. );
  77. textPainter.layout();
  78. Offset labelOffset =
  79. Offset(
  80. centerX + 10,
  81. heightLeft - textPainter.height / 2);
  82. textPainter.paint(canvas, labelOffset);
  83. }else{
  84. canvas.drawLine(Offset(littleScaleXLeft, heightLeft), Offset(littleScaleXRight, heightLeft), painter);
  85. }
  86. heightLeft -= littleScale;
  87. }
  88. }
  89. @override
  90. bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
  91. _Scale? _getOneScaleLen(int meter) {
  92. var valuePx = meter * mapScale;
  93. if (valuePx > 100) {
  94. return _Scale(_meterToStr(meter), valuePx, meter);
  95. }
  96. return null;
  97. }
  98. String _meterToStr(int meter){
  99. if(meter < 1000){
  100. return '$meter m';
  101. }else{
  102. return "${(meter.toDouble()/1000).toStringAsFixed(1)} km";
  103. }
  104. }
  105. _Scale _getScale() {
  106. var s = 1;
  107. _Scale? out;
  108. while(out == null){
  109. out = _getOneScaleLen(5 * s);
  110. if (out != null) {
  111. return out;
  112. }
  113. out = _getOneScaleLen(10 * s);
  114. if (out != null) {
  115. return out;
  116. }
  117. out = _getOneScaleLen(20 * s);
  118. if (out != null) {
  119. return out;
  120. }
  121. s *= 10;
  122. }
  123. return out;
  124. }
  125. }
  126. void main() async {
  127. runApp(GetMaterialApp(
  128. theme: appThemeData(),
  129. home: const Scaffold(
  130. body: Ruler(hideHeight: 20, mapScale: 1),
  131. )));
  132. }