import 'dart:math'; import 'package:trackoffical_app/logger.dart'; import 'package:trackoffical_app/screen.dart'; import 'package:trackoffical_app/service/app.dart'; import 'layer.dart'; import '../../../model/m_control_point.dart'; class _LayerParams { bool isHideRouteBeforeStart = true; List wantList = []; List wantListOnScreen = []; int? nextPlanCPIndex; double radiusPx = 0; bool isStarted = false; double numRadians=0; } class LayerCP extends GetView { LayerCP({ super.key, required bool isHideRouteBeforeStart, required List wantList, int? nextPlanCPIndex, double? numRadians }) : _params = _LayerParams() ..isHideRouteBeforeStart = isHideRouteBeforeStart ..wantList = wantList ..numRadians=numRadians??0 ..nextPlanCPIndex = nextPlanCPIndex; final _LayerParams _params; final _userProfile = App.to.userProfile; Color get colorCP => _userProfile.gameSettingsCpColor.value; @override Widget build(BuildContext context) { return Obx(() { _params.wantListOnScreen.clear(); for (var one in _params.wantList) { final p = controller.mapOffsetToScreen(one.onMap); _params.wantListOnScreen.add(p); if (one.isStart) { _params.isStarted = one.isSuccess; } } _params.radiusPx = controller.meterToOnScreen(controller.cpRadiusMeter.value); final children = [ _LayerCPContent( params: _params, ) ]; wCPNum(children); return Layer(children: children); }); } wCPNum(List children) { if ((!_params.isStarted) && _params.isHideRouteBeforeStart) { return const SizedBox(); } final style = TextStyle( color: colorCP, fontSize: 22, fontWeight: FontWeight.w700); var h = _params.radiusPx * 1.1; if(h.isNaN){ return; } const textHeight = 30.0; var points = _params.wantList; for (var i = 0; i < points.length; i++) { final one = points[i]; var xy = _params.wantListOnScreen[i]; var x = xy.dx; var y = xy.dy; if (!one.isStart && !one.isFinish) { final height = h + textHeight; children.add(Positioned( top: y - height, left: x - 40, width: 80, height: height, child: Transform.rotate( angle: _params.numRadians, alignment: Alignment.bottomCenter, child: Container( alignment: Alignment.topCenter, // color: Colors.white, child: Text(one.sn, style: style))), )); } } } } class _LayerCPContent extends StatefulWidget { const _LayerCPContent({ required _LayerParams params, }) : _params = params; final _LayerParams _params; @override State createState() { return _LayerCPContentState(); } } class _LayerCPContentState extends State<_LayerCPContent> with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation _animation; @override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: const Duration(milliseconds: 500), reverseDuration: const Duration(milliseconds: 500), )..repeat(reverse: true); _animation = IntTween(begin: 255, end: 0).animate(_animationController) ..addListener(() { setState(() { // The state that has changed here is the animation object’s value. }); }); } @override Widget build(BuildContext context) { return SizedBox( width: context.width, height: context.height, child: CustomPaint( painter: _RoutePointsPainter( widget._params, _animation.value, ), )); } @override void dispose() { _animationController.dispose(); super.dispose(); } } class _RoutePointsPainter extends CustomPainter { final _userProfile = App.to.userProfile; Color get colorCP => _userProfile.gameSettingsCpColor.value; Color get colorCPTarget => _userProfile.gameSettingsCpTargetColor.value; Color get colorCPJump => _userProfile.gameSettingsCpJumpColor.value; Color get colorCPPunched => _userProfile.gameSettingsCpPunchedColor.value; final _LayerParams params; final int nextAlpha; _RoutePointsPainter( this.params, this.nextAlpha, ); @override void paint(Canvas canvas, Size size) { final paint = Paint(); final radiusPx = params.radiusPx; final nextPlanIndex = params.nextPlanCPIndex; final strokeWidthColor = radiusPx * 0.15; final strokeWidthWhite = strokeWidthColor * 2; paint.strokeWidth = strokeWidthColor; final textSize = 8.0.wp; // const textSize = 5.0; const isShowText = false; var lastXY = Offset.zero; for (var i = params.wantList.length - 1; i >= 0; i--) { if ((!params.isStarted) && params.isHideRouteBeforeStart && i != 0) { continue; } final one = params.wantList[i]; if (one.onMap != Offset.zero) { var xy = params.wantListOnScreen[i]; var x = xy.dx; var y = xy.dy; var isNext = false; var isJumped = false; if (nextPlanIndex == null) { isNext = one.isNext; } else { isNext = i == nextPlanIndex; isJumped = !one.isSuccess && i < nextPlanIndex; } var color = colorCP; var strokeColor = Colors.white; if (one.isSuccess) { color = colorCPPunched; } if (isNext) { color = colorCPTarget.withAlpha(nextAlpha); strokeColor = Colors.white.withAlpha(nextAlpha); // paint.color = const Color(0xffff4d00); } if (isJumped) { color = colorCPJump; } paint.style = PaintingStyle.fill; final thisXY = Offset(x, y); // canvas.drawCircle(thisXY, 2, paint); // if (lastXY != Offset.zero) { if (i - 1 >= 0) { final next = params.wantList[i - 1]; lastXY = params.wantListOnScreen[i - 1]; final dx = thisXY.dx - lastXY.dx; final dy = thisXY.dy - lastXY.dy; final len = sqrt(dx * dx + dy * dy); final dx1 = dx / len * radiusPx; final dy1 = dy / len * radiusPx; var p1 = lastXY + Offset(dx1, dy1); var p2 = thisXY - Offset(dx1, dy1); if (p1.dx.isNaN || p1.dy.isNaN || p2.dx.isNaN || p2.dy.isNaN) { continue; } paint.color = strokeColor; paint.strokeWidth = strokeWidthWhite; canvas.drawLine(p1, p2, paint); paint.color = color; paint.strokeWidth = strokeWidthColor; canvas.drawLine(p1, p2, paint); } lastXY = thisXY; if (one.isStart) { final path = Path(); final widthLeft = radiusPx * 0.9; final widthRight = radiusPx * 1.1; final heightHalf = radiusPx; path.moveTo(x - widthLeft, y - heightHalf); path.lineTo(x + widthRight, y); path.lineTo(x - widthLeft, y + heightHalf); path.close(); paint.style = PaintingStyle.stroke; paint.color = strokeColor; paint.strokeWidth = strokeWidthWhite; canvas.drawPath(path, paint); paint.color = color; paint.strokeWidth = strokeWidthColor; canvas.drawPath(path, paint); } else if (one.isFinish) { paint.style = PaintingStyle.stroke; paint.color = strokeColor; paint.strokeWidth = strokeWidthWhite; canvas.drawCircle(thisXY, radiusPx, paint); canvas.drawCircle(thisXY, radiusPx * 0.7, paint); paint.color = color; paint.strokeWidth = strokeWidthColor; canvas.drawCircle(thisXY, radiusPx, paint); canvas.drawCircle(thisXY, radiusPx * 0.7, paint); } else { paint.style = PaintingStyle.stroke; paint.color = strokeColor; paint.strokeWidth = strokeWidthWhite; canvas.drawCircle(thisXY, radiusPx, paint); paint.color = color; paint.strokeWidth = strokeWidthColor; canvas.drawCircle(thisXY, radiusPx, paint); } if (!one.isStart && !one.isFinish && isShowText) { var textPainter = TextPainter( text: TextSpan( text: one.sn, style: TextStyle( color: paint.color, fontSize: textSize, fontWeight: FontWeight.w700)), textDirection: TextDirection.rtl, textWidthBasis: TextWidthBasis.longestLine, maxLines: 1, )..layout(); textPainter.paint( canvas, Offset(x - textPainter.width / 2, y - textPainter.height - radiusPx)); } } } } @override bool shouldRepaint(_RoutePointsPainter oldDelegate) => true; }