import 'dart:math'; import 'package:flutter/material.dart'; import '../../service/app.dart'; import 'package:get/get.dart'; class Ruler2 extends StatefulWidget { const Ruler2({ super.key, required this.isScaleMode, this.onReturn, this.mapScale, }); final bool isScaleMode; final VoidCallback? onReturn; final double? mapScale; @override State createState() { return Ruler2State(); } } class Ruler2State extends State { var _iter1Y = 180.0; var _iter2Y = 280.0; static const _iterHeight = 50.0; static const _iterColorNormal = Colors.green; static const _iterColorOnTap = Colors.red; var _iter1Color = _iterColorNormal; var _iter2Color = _iterColorNormal; var screenLen = ''; String? mapLen; @override void initState() { super.initState(); onIterChanged(); } @override Widget build(BuildContext context) { final children = [ CustomPaint( painter: _RulerPainter(App.to.heightOneMM(), widget.isScaleMode), size: Size(context.width, context.height), ) ]; if (widget.isScaleMode) { children.addAll([ _lenArrow(context), _wIter( context, _iter1Y, _iter1Color, onIter1Update, () { _iter1Color = _iterColorOnTap; }, () { _iter1Color = _iterColorNormal; }, ), _wIter(context, _iter2Y, _iter2Color, onIter2Update, () { _iter2Color = _iterColorOnTap; }, () { _iter2Color = _iterColorNormal; }), ]); _wIterLenText(context, children); children.add(Positioned( bottom: 20, right: 80, child: GestureDetector( onTap: widget.onReturn, child: Image.asset( 'assets/images/btn_ruler_no_map.png', width: 46, )))); } return Stack(children: children); } onIter1Update(DragUpdateDetails e) { var tmp = _iter1Y + e.delta.dy; if (tmp > _iter2Y - _iterHeight || tmp < 30 + _iterHeight) { return; } _iter1Y = tmp; onIterChanged(); } onIter2Update(DragUpdateDetails e) { var tmp = _iter2Y + e.delta.dy; if (tmp - _iterHeight < _iter1Y || tmp > context.height) { return; } _iter2Y = tmp; onIterChanged(); } onIterChanged() { final heightOneMM = App.to.heightOneMM(); final height = _iter2Y - _iter1Y; final mm = height / heightOneMM; final cm = mm / 10; screenLen = '${cm.toStringAsFixed(1)} cm'; if (widget.mapScale != null) { var mapL = cm * widget.mapScale! / 100; var unit = 'm'; if (mapL > 1000) { mapL /= 1000; unit = 'km'; } mapLen = '${mapL.toStringAsFixed(1)} $unit'; } } _wIterLenText( BuildContext context, List children ) { var text = screenLen; if(mapLen!=null){ text += ' ($mapLen)'; } const textLen = 200.0; final centerX = context.width / 2 -textLen/2; children.addAll([ Positioned( left: centerX - 15, top: (_iter1Y + _iter2Y) / 2 - _iterHeight/2, child: Transform.rotate( angle: pi / 2, child: SizedBox(width:textLen, child: Text(text, textAlign: TextAlign.center,)) ) ), Positioned( left: centerX + 15, top: (_iter1Y + _iter2Y) / 2 - _iterHeight/2, child: Transform.rotate( angle: -pi / 2, child: SizedBox(width:textLen, child: Text(text, textAlign: TextAlign.center,)) ) ), ]); } Widget _wIter( BuildContext context, double y, Color color, void Function(DragUpdateDetails e) onUpdate, VoidCallback onTapDown, VoidCallback onTapUp, ) { return Positioned( top: y - _iterHeight, left: 0, child: GestureDetector( onPanStart: (e) { setState(() { onTapDown(); }); }, onPanEnd: (e) { setState(() { onTapUp(); }); }, onPanUpdate: (DragUpdateDetails e) { setState(() { onUpdate(e); }); }, child: Container( width: context.width, height: _iterHeight, color: Colors.white.withAlpha(10), alignment: Alignment.center, child: Container(width: context.width, height: 2, color: color), ), )); } Widget _lenArrow(BuildContext context) { final height = _iter2Y - _iter1Y; return Positioned( top: _iter1Y - _iterHeight / 2, child: CustomPaint( painter: _LenArrowPainter(screenLen: screenLen, mapLen: mapLen), size: Size(context.width, height), )); } } class _LenArrowPainter extends CustomPainter { _LenArrowPainter({required this.screenLen, this.mapLen}); final String? mapLen; final String screenLen; final textPainter = TextPainter( textDirection: TextDirection.ltr, textAlign: TextAlign.center, ); final style = const TextStyle( color: Colors.white, fontSize: 11, fontWeight: FontWeight.w500, ); @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = Colors.white ..style = PaintingStyle.stroke ..strokeWidth = 2; var path = Path(); final centerX = size.width / 2; const arrowR = 3; path.moveTo(centerX, 2); path.lineTo(centerX + arrowR, arrowR * 2 + 2); path.lineTo(centerX - arrowR, arrowR * 2 + 2); path.close(); canvas.drawPath(path, paint); path.moveTo(centerX, size.height - 2); path.lineTo(centerX + arrowR, size.height - 2 - arrowR * 2); path.lineTo(centerX - arrowR, size.height - 2 - arrowR * 2); path.close(); canvas.drawPath(path, paint); canvas.drawLine( Offset(size.width / 2, 0), Offset(size.width / 2, size.height), paint); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) { return false; } } class _RulerPainter extends CustomPainter { _RulerPainter(this.heightOneMM, this.isScaleMode); final bool isScaleMode; final double heightOneMM; final textPainter = TextPainter( textDirection: TextDirection.ltr, textAlign: TextAlign.center, ); final style = TextStyle( color: Colors.white.withAlpha(120), fontSize: 11, fontWeight: FontWeight.w500, ); @override void paint(Canvas canvas, Size size) { if (isScaleMode) { final paint = Paint() ..color = Colors.black.withAlpha((255 * 0.8).round()) ..style = PaintingStyle.fill; canvas.drawRect(Rect.largest, paint); } paintScale(canvas, size); } void paintScale(Canvas canvas, Size size) { final paint = Paint() ..color = Colors.white ..style = PaintingStyle.stroke; var width = 20.0; const widthSmall = 20.0; var h = size.height; var i = 0; final maxI = size.height ~/ (heightOneMM * 10) * 10; for (; i <= maxI; i++) { if (i % 5 == 0) { width = 33; } else { width = widthSmall; } if (i % 10 == 0) { if (i != 0) { textPainter.text = TextSpan(text: '${(i / 10).round()} cm', style: style); textPainter.layout(); textPainter.paint(canvas, Offset(size.width - widthSmall - textPainter.width - 2, h)); } if (i != 0) { textPainter.text = TextSpan(text: '${(i / 10).round()} cm', style: style); textPainter.layout(); final hLeft = size.height - ((maxI- i) * heightOneMM); Offset labelOffset = Offset(widthSmall + 2, hLeft - textPainter.height); textPainter.paint(canvas, labelOffset); } } canvas.drawLine(Offset(0, h), Offset(width, h), paint); canvas.drawLine( Offset(size.width, h), Offset(size.width - width, h), paint); h -= heightOneMM; } } @override bool shouldRepaint(covariant CustomPainter oldDelegate) { return true; } }