// import 'package:ef/ef.dart'; // import 'package:fl_chart/fl_chart.dart'; // import 'package:flutter/material.dart'; // import 'package:flutter_svg/svg.dart'; // import 'package:vbvs_app/common/color/appConstants.dart'; // import 'package:vbvs_app/common/util/FitTool.dart'; // import 'package:vbvs_app/common/util/MyUtils.dart'; // class QcTimeSeriesPoint { // final double value; // QcTimeSeriesPoint(this.value); // } // class QcTimeSeriesChart extends StatelessWidget { // final List dataPoints; // final double yMin; // final double yMax; // 注意:这个值在使用时会自动加 padding // final int xSegmentCount; // final double? baseValue; // 基准值,可选 // final String? baseLabel; // 基准值标签,可选 // final double yAxisPadding; // Y轴顶部留白,默认为20 // final double yAxisMargin; // Y轴上下边距,默认为2 // const QcTimeSeriesChart({ // Key? key, // required this.yMin, // required this.yMax, // required this.dataPoints, // this.xSegmentCount = 11, // this.baseValue, // this.baseLabel, // this.yAxisPadding = 20.0, // 默认为20 // this.yAxisMargin = 2.0, // Y轴上下边距,默认为2 // }) : super(key: key); // // 添加一个 getter 来获取实际使用的 yMax(自动加 padding) // double get _actualYMax => yMax + yAxisPadding; // int get _dataPointCount => dataPoints.length; // List _generateYAxisTicks() { // if (yMin >= _actualYMax) { // return [0, 20, 40, 60, 80, 100]; // } // double step = (_actualYMax - yMin) / 5; // List ticks = []; // for (int i = 0; i <= 5; i++) { // ticks.add(yMin + (step * i)); // } // return ticks; // } // // 计算所有刻度位置对应的索引 // List _getTickIndices() { // List tickIndices = []; // // 确保至少显示两个刻度(起点和终点) // if (_dataPointCount <= 1) { // return [0]; // } // // 计算合理的刻度间隔 // double step = _dataPointCount / (xSegmentCount - 1); // for (int i = 0; i < xSegmentCount; i++) { // int index = (i * step).round(); // // 确保索引在有效范围内 // index = index.clamp(0, _dataPointCount - 1); // // 避免重复的索引 // if (tickIndices.isEmpty || index != tickIndices.last) { // tickIndices.add(index); // } // } // // 确保最后一个点是最后一个数据点 // if (tickIndices.last != _dataPointCount - 1) { // tickIndices.add(_dataPointCount - 1); // } // return tickIndices; // } // // 查找最大值和最小值的索引和值 // Map _findMinMax() { // if (dataPoints.isEmpty) // return {'minIndex': -1, 'maxIndex': -1, 'minValue': 0, 'maxValue': 0}; // int minIndex = -1; // int maxIndex = -1; // double minValue = double.infinity; // double maxValue = -double.infinity; // for (int i = 0; i < dataPoints.length; i++) { // var point = dataPoints[i]; // if (point.value != -1) { // // 跳过无效数据 // if (point.value < minValue) { // minValue = point.value; // minIndex = i; // } // if (point.value > maxValue) { // maxValue = point.value; // maxIndex = i; // } // } // } // return { // 'minIndex': minIndex, // 'maxIndex': maxIndex, // 'minValue': minValue, // 'maxValue': maxValue // }; // } // @override // Widget build(BuildContext context) { // // final yTicks = _generateYAxisTicks(); // final double xMax = _dataPointCount.toDouble(); // final double yRange = _actualYMax - yMin; // final double yInterval = yRange > 0 ? yRange / 5 : 20.0; // final tickIndices = _getTickIndices(); // final minMaxData = _findMinMax(); // // 将数据点分割成多个连续段 // List> lineSegments = []; // List currentSegment = []; // for (int i = 0; i < dataPoints.length; i++) { // var point = dataPoints[i]; // if (point.value != -1) { // currentSegment.add(FlSpot( // (i + 1).toDouble(), // point.value, // )); // } else if (currentSegment.isNotEmpty) { // lineSegments.add(currentSegment); // currentSegment = []; // } // } // if (currentSegment.isNotEmpty) { // lineSegments.add(currentSegment); // } // // 创建渐变填充的线图数据 // List lineBarsData = []; // for (var segment in lineSegments) { // if (segment.isEmpty) continue; // lineBarsData.add( // LineChartBarData( // spots: segment, // isCurved: false, // color: themeController.currentColor.sc2, // barWidth: 2, // dotData: FlDotData(show: false), // preventCurveOverShooting: true, // belowBarData: BarAreaData( // show: true, // gradient: LinearGradient( // begin: Alignment.topCenter, // end: Alignment.bottomCenter, // colors: [ // themeController.currentColor.sc2.withOpacity(0.3), // themeController.currentColor.sc2.withOpacity(0.1), // Colors.transparent, // ], // stops: const [0.0, 1, 1.0], // ), // applyCutOffY: true, // cutOffY: 0, // ), // ), // ); // } // // 创建刻度点的数据(绿色小球) // List tickSpots = []; // for (int index in tickIndices) { // if (index >= 0 && index < dataPoints.length) { // var point = dataPoints[index]; // if (point.value != -1) { // tickSpots.add(FlSpot( // (index + 1).toDouble(), // point.value, // )); // } // } // } // // 准备水平线列表 // List horizontalLines = [ // HorizontalLine( // y: 0, // color: themeController.currentColor.sc4, // strokeWidth: 1.rpx, // ), // ]; // // 如果有基准值,添加基准线 // if (baseValue != null) { // horizontalLines.add( // HorizontalLine( // y: baseValue!, // color: themeController.currentColor.sc9, // strokeWidth: 2.rpx, // dashArray: [8, 4], // 虚线样式 // label: HorizontalLineLabel( // show: true, // alignment: Alignment.topRight, // labelResolver: (line) => // "基准".tr + '${baseValue!.toStringAsFixed(0)}', // style: TextStyle( // color: themeController.currentColor.sc9, // fontSize: 18.rpx, // fontWeight: FontWeight.w500, // ), // ), // ), // ); // } // return AspectRatio( // aspectRatio: 2, // child: LayoutBuilder( // builder: (context, constraints) { // return Stack( // children: [ // LineChart( // LineChartData( // minX: 1, // maxX: xMax + 0.5, // minY: yMin - yAxisMargin, // maxY: _actualYMax + yAxisMargin, // gridData: FlGridData(show: false), // extraLinesData: ExtraLinesData( // horizontalLines: horizontalLines, // ), // titlesData: FlTitlesData( // bottomTitles: AxisTitles( // sideTitles: SideTitles( // showTitles: true, // reservedSize: 30, // interval: 1, // 让 fl_chart 自动计算合适的间隔 // getTitlesWidget: (value, meta) { // // 只显示我们在 tickIndices 中定义的刻度 // int index = value.round() - 1; // if (index >= 0 && // index < _dataPointCount && // tickIndices.contains(index)) { // String label; // if (index == 0) { // label = '0'; // } else if (index == _dataPointCount - 1) { // label = '${_dataPointCount}'; // } else { // label = '${index + 1}'; // } // return Padding( // padding: const EdgeInsets.only(top: 8.0), // child: Text( // label, // style: TextStyle( // color: themeController.currentColor.sc4, // fontSize: 14.rpx, // ), // ), // ); // } // return const SizedBox.shrink(); // }, // ), // ), // leftTitles: AxisTitles( // sideTitles: SideTitles( // showTitles: true, // reservedSize: 60.rpx, // interval: yInterval, // getTitlesWidget: (value, meta) { // return Padding( // padding: const EdgeInsets.only(right: 8.0), // child: Text( // value.toStringAsFixed(0), // style: TextStyle( // color: themeController.currentColor.sc4, // fontSize: 16.rpx, // ), // textAlign: TextAlign.right, // ), // ); // }, // ), // ), // rightTitles: // AxisTitles(sideTitles: SideTitles(showTitles: false)), // topTitles: // AxisTitles(sideTitles: SideTitles(showTitles: false)), // ), // borderData: FlBorderData( // show: true, // border: Border( // bottom: BorderSide(color: Colors.grey.withOpacity(0.3)), // left: BorderSide(color: Colors.grey.withOpacity(0.3)), // right: BorderSide.none, // top: BorderSide.none, // ), // ), // lineBarsData: [ // ...lineBarsData, // // 添加绿色小球的线图数据 // LineChartBarData( // spots: tickSpots, // isCurved: false, // color: Colors.transparent, // barWidth: 0, // dotData: FlDotData( // show: true, // getDotPainter: (spot, percent, barData, index) { // return FlDotCirclePainter( // radius: 4.rpx, // color: stringToColor("#5DD8C9"), // strokeWidth: 1, // strokeColor: stringToColor("#00C1AA"), // ); // }, // ), // preventCurveOverShooting: true, // ), // ], // ), // ), // // 使用 Positioned 来绘制最大值和最小值的标签 // if (minMaxData['minIndex'] != -1 || minMaxData['maxIndex'] != -1) // _buildMinMaxLabels( // context, constraints, minMaxData, xMax, yMin, _actualYMax), // ], // ); // }, // ), // ); // } // Widget _buildMinMaxLabels( // BuildContext context, // BoxConstraints constraints, // Map minMaxData, // double xMax, // double yMin, // double yMax, // ) { // // 获取图表区域的实际绘制区域 // // fl_chart 默认会有一些内边距,我们需要估算这些内边距 // double leftPadding = 60.rpx; // 左侧留白,用于Y轴标签 // double rightPadding = 10.rpx; // 右侧留白 // double topPadding = 10.rpx; // 顶部留白 // double bottomPadding = 30.rpx; // 底部留白,用于X轴标签 // double chartWidth = constraints.maxWidth - leftPadding - rightPadding; // double chartHeight = constraints.maxHeight - topPadding - bottomPadding; // // X轴范围:1 到 xMax // // Y轴范围:yMin - yAxisMargin 到 yMax + yAxisMargin // double xMin = 1; // double xMaxValue = xMax; // double yMinValue = yMin - yAxisMargin; // double yMaxValue = yMax + yAxisMargin; // double xRange = xMaxValue - xMin; // double yRange = yMaxValue - yMinValue; // List labels = []; // // 添加最小值标签 // if (minMaxData['minIndex'] != -1) { // double minX = (minMaxData['minIndex'] + 1).toDouble(); // double minY = minMaxData['minValue']; // // 计算在图表中的相对位置 (0-1) // double relativeX = (minX - xMin) / xRange; // double relativeY = (minY - yMinValue) / yRange; // // 转换为像素位置 // double left = leftPadding + (relativeX * chartWidth); // double top = topPadding + ((1 - relativeY) * chartHeight); // // 标签尺寸 // double labelWidth = 38.rpx; // double labelHeight = 50.rpx; // labels.add( // Positioned( // left: left - labelWidth / 2, // 水平居中 // top: top - labelHeight - 8.rpx, // 显示在点的正上方,留出8rpx间距 // child: SizedBox( // width: labelWidth, // height: labelHeight, // child: Stack( // alignment: Alignment.center, // children: [ // // SVG图片作为背景 // SvgPicture.asset( // 'assets/img/icon/location.svg', // fit: BoxFit.contain, // color: stringToColor("#d69dd2"), // ), // Padding( // padding: EdgeInsets.only(bottom: 12.rpx), // child: Text( // '${minMaxData['minValue'].toStringAsFixed(0)}', // style: TextStyle( // color: Colors.white, // fontSize: AppConstants().smaller_text_fontSize, // ), // ), // ), // ], // ), // ), // ), // ); // } // // 添加最大值标签 // if (minMaxData['maxIndex'] != -1 && // minMaxData['maxIndex'] != minMaxData['minIndex']) { // double maxX = (minMaxData['maxIndex'] + 1).toDouble(); // double maxY = minMaxData['maxValue']; // // 计算在图表中的相对位置 (0-1) // double relativeX = (maxX - xMin) / xRange; // double relativeY = (maxY - yMinValue) / yRange; // // 转换为像素位置 // double left = leftPadding + (relativeX * chartWidth); // double top = topPadding + ((1 - relativeY) * chartHeight); // // 标签尺寸 // double labelWidth = 38.rpx; // double labelHeight = 50.rpx; // labels.add( // Positioned( // left: left - labelWidth / 2, // 水平居中 // top: top - labelHeight - 8.rpx, // 显示在点的正上方,留出8rpx间距 // child: SizedBox( // width: labelWidth, // height: labelHeight, // child: Stack( // alignment: Alignment.center, // children: [ // // SVG图片作为背景 // SvgPicture.asset( // 'assets/img/icon/location.svg', // fit: BoxFit.contain, // color: stringToColor("#FF9F66"), // ), // Padding( // padding: EdgeInsets.only(bottom: 12.rpx), // child: Text( // '${minMaxData['maxValue'].toStringAsFixed(0)}', // style: TextStyle( // color: Colors.white, // fontSize: AppConstants().smaller_text_fontSize, // ), // ), // ), // ], // ), // ), // ), // ); // } // return Stack( // children: labels, // ); // } // } import 'package:ef/ef.dart'; import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:vbvs_app/common/color/appConstants.dart'; import 'package:vbvs_app/common/util/FitTool.dart'; import 'package:vbvs_app/common/util/MyUtils.dart'; class QcTimeSeriesPoint { final double value; QcTimeSeriesPoint(this.value); } class QcTimeSeriesChart extends StatelessWidget { final List dataPoints; final double yMin; final double yMax; // 注意:这个值在使用时会自动加 padding final int xSegmentCount; final double? baseValue; // 基准值,可选 final String? baseLabel; // 基准值标签,可选 final double yAxisPadding; // Y轴顶部留白,默认为20 final double yAxisMargin; // Y轴上下边距,默认为2 const QcTimeSeriesChart({ Key? key, required this.yMin, required this.yMax, required this.dataPoints, this.xSegmentCount = 11, this.baseValue, this.baseLabel, this.yAxisPadding = 20.0, // 默认为20 this.yAxisMargin = 2.0, // Y轴上下边距,默认为2 }) : super(key: key); // 添加一个 getter 来获取实际使用的 yMax(自动加 padding) double get _actualYMax => yMax + yAxisPadding; int get _dataPointCount => dataPoints.length; List _generateYAxisTicks() { if (yMin >= _actualYMax) { return [0, 20, 40, 60, 80, 100]; } double step = (_actualYMax - yMin) / 5; List ticks = []; for (int i = 0; i <= 5; i++) { ticks.add(yMin + (step * i)); } return ticks; } // 计算所有刻度位置对应的索引 List _getTickIndices() { List tickIndices = []; // 确保至少显示两个刻度(起点和终点) if (_dataPointCount <= 1) { return [0]; } // 计算合理的刻度间隔 double step = _dataPointCount / (xSegmentCount - 1); for (int i = 0; i < xSegmentCount; i++) { int index = (i * step).round(); // 确保索引在有效范围内 index = index.clamp(0, _dataPointCount - 1); // 避免重复的索引 if (tickIndices.isEmpty || index != tickIndices.last) { tickIndices.add(index); } } // 确保最后一个点是最后一个数据点 if (tickIndices.last != _dataPointCount - 1) { tickIndices.add(_dataPointCount - 1); } return tickIndices; } // 查找最大值和最小值的索引和值 Map _findMinMax() { if (dataPoints.isEmpty) return {'minIndex': -1, 'maxIndex': -1, 'minValue': 0, 'maxValue': 0}; int minIndex = -1; int maxIndex = -1; double minValue = double.infinity; double maxValue = -double.infinity; for (int i = 0; i < dataPoints.length; i++) { var point = dataPoints[i]; if (point.value != -1) { // 跳过无效数据 if (point.value < minValue) { minValue = point.value; minIndex = i; } if (point.value > maxValue) { maxValue = point.value; maxIndex = i; } } } return { 'minIndex': minIndex, 'maxIndex': maxIndex, 'minValue': minValue, 'maxValue': maxValue }; } @override Widget build(BuildContext context) { // final yTicks = _generateYAxisTicks(); final double xMax = _dataPointCount.toDouble(); final double yRange = _actualYMax - yMin; final double yInterval = yRange > 0 ? yRange / 5 : 20.0; final tickIndices = _getTickIndices(); final minMaxData = _findMinMax(); // 计算实际显示的Y轴范围 final double actualMinY = yMin - yAxisMargin; final double actualMaxY = _actualYMax + yAxisMargin; // 将数据点分割成多个连续段 List> lineSegments = []; List currentSegment = []; for (int i = 0; i < dataPoints.length; i++) { var point = dataPoints[i]; if (point.value != -1) { currentSegment.add(FlSpot( (i + 1).toDouble(), point.value, )); } else if (currentSegment.isNotEmpty) { lineSegments.add(currentSegment); currentSegment = []; } } if (currentSegment.isNotEmpty) { lineSegments.add(currentSegment); } // 创建渐变填充的线图数据 List lineBarsData = []; for (var segment in lineSegments) { if (segment.isEmpty) continue; lineBarsData.add( LineChartBarData( spots: segment, isCurved: false, color: themeController.currentColor.sc2, barWidth: 2, dotData: FlDotData(show: false), preventCurveOverShooting: true, belowBarData: BarAreaData( show: true, gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ themeController.currentColor.sc2.withOpacity(0.3), themeController.currentColor.sc2.withOpacity(0.1), Colors.transparent, ], stops: const [0.0, 1, 1.0], ), applyCutOffY: true, cutOffY: 0, ), ), ); } // 创建刻度点的数据(绿色小球) List tickSpots = []; for (int index in tickIndices) { if (index >= 0 && index < dataPoints.length) { var point = dataPoints[index]; if (point.value != -1) { tickSpots.add(FlSpot( (index + 1).toDouble(), point.value, )); } } } // 准备水平线列表 List horizontalLines = [ HorizontalLine( y: 0, color: themeController.currentColor.sc4, strokeWidth: 1.rpx, ), ]; // 如果有基准值,添加基准线 if (baseValue != null) { horizontalLines.add( HorizontalLine( y: baseValue!, color: themeController.currentColor.sc9, strokeWidth: 2.rpx, dashArray: [8, 4], // 虚线样式 label: HorizontalLineLabel( show: true, alignment: Alignment.topRight, labelResolver: (line) => "基准".tr + '${baseValue!.toStringAsFixed(0)}', style: TextStyle( color: themeController.currentColor.sc9, fontSize: 18.rpx, fontWeight: FontWeight.w500, ), ), ), ); } return AspectRatio( aspectRatio: 2, child: LayoutBuilder( builder: (context, constraints) { return Stack( children: [ LineChart( LineChartData( minX: 1, maxX: xMax + 0.5, minY: actualMinY, maxY: actualMaxY, gridData: FlGridData(show: false), extraLinesData: ExtraLinesData( horizontalLines: horizontalLines, ), titlesData: FlTitlesData( bottomTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, reservedSize: 30, interval: 1, // 让 fl_chart 自动计算合适的间隔 getTitlesWidget: (value, meta) { // 只显示我们在 tickIndices 中定义的刻度 int index = value.round() - 1; if (index >= 0 && index < _dataPointCount && tickIndices.contains(index)) { String label; if (index == 0) { label = '0'; } else if (index == _dataPointCount - 1) { label = '${_dataPointCount}'; } else { label = '${index + 1}'; } return Padding( padding: const EdgeInsets.only(top: 8.0), child: Text( label, style: TextStyle( color: themeController.currentColor.sc4, fontSize: 14.rpx, ), ), ); } return const SizedBox.shrink(); }, ), ), leftTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, reservedSize: 60.rpx, interval: yInterval, getTitlesWidget: (value, meta) { // 不显示最小值和最大值 // 判断是否是实际显示范围的最小值或最大值 if (value == actualMinY || value == actualMaxY) { return const SizedBox.shrink(); } // 检查值是否为整数(避免显示小数) double roundedValue = value.roundToDouble(); if ((value - roundedValue).abs() > 0.01) { // 如果不是整数,不显示 return const SizedBox.shrink(); } return Padding( padding: const EdgeInsets.only(right: 8.0), child: Text( value.toStringAsFixed(0), style: TextStyle( color: themeController.currentColor.sc4, fontSize: 16.rpx, ), textAlign: TextAlign.right, ), ); }, ), ), rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), ), borderData: FlBorderData( show: true, border: Border( bottom: BorderSide(color: Colors.grey.withOpacity(0.3)), left: BorderSide(color: Colors.grey.withOpacity(0.3)), right: BorderSide.none, top: BorderSide.none, ), ), lineBarsData: [ ...lineBarsData, // 添加绿色小球的线图数据 LineChartBarData( spots: tickSpots, isCurved: false, color: Colors.transparent, barWidth: 0, dotData: FlDotData( show: true, getDotPainter: (spot, percent, barData, index) { return FlDotCirclePainter( radius: 4.rpx, color: stringToColor("#5DD8C9"), strokeWidth: 1, strokeColor: stringToColor("#00C1AA"), ); }, ), preventCurveOverShooting: true, ), ], ), ), // 使用 Positioned 来绘制最大值和最小值的标签 if (minMaxData['minIndex'] != -1 || minMaxData['maxIndex'] != -1) _buildMinMaxLabels( context, constraints, minMaxData, xMax, yMin, _actualYMax), ], ); }, ), ); } Widget _buildMinMaxLabels( BuildContext context, BoxConstraints constraints, Map minMaxData, double xMax, double yMin, double yMax, ) { // 获取图表区域的实际绘制区域 // fl_chart 默认会有一些内边距,我们需要估算这些内边距 double leftPadding = 60.rpx; // 左侧留白,用于Y轴标签 double rightPadding = 10.rpx; // 右侧留白 double topPadding = 10.rpx; // 顶部留白 double bottomPadding = 30.rpx; // 底部留白,用于X轴标签 double chartWidth = constraints.maxWidth - leftPadding - rightPadding; double chartHeight = constraints.maxHeight - topPadding - bottomPadding; // X轴范围:1 到 xMax // Y轴范围:yMin - yAxisMargin 到 yMax + yAxisMargin double xMin = 1; double xMaxValue = xMax; double yMinValue = yMin - yAxisMargin; double yMaxValue = yMax + yAxisMargin; double xRange = xMaxValue - xMin; double yRange = yMaxValue - yMinValue; List labels = []; // 添加最小值标签 if (minMaxData['minIndex'] != -1) { double minX = (minMaxData['minIndex'] + 1).toDouble(); double minY = minMaxData['minValue']; // 计算在图表中的相对位置 (0-1) double relativeX = (minX - xMin) / xRange; double relativeY = (minY - yMinValue) / yRange; // 转换为像素位置 double left = leftPadding + (relativeX * chartWidth); double top = topPadding + ((1 - relativeY) * chartHeight); // 标签尺寸 double labelWidth = 38.rpx; double labelHeight = 50.rpx; labels.add( Positioned( left: left - labelWidth / 2, // 水平居中 top: top - labelHeight - 8.rpx, // 显示在点的正上方,留出8rpx间距 child: SizedBox( width: labelWidth, height: labelHeight, child: Stack( alignment: Alignment.center, children: [ // SVG图片作为背景 SvgPicture.asset( 'assets/img/icon/location.svg', fit: BoxFit.contain, color: stringToColor("#d69dd2"), ), Padding( padding: EdgeInsets.only(bottom: 12.rpx), child: Text( '${minMaxData['minValue'].toStringAsFixed(0)}', style: TextStyle( color: Colors.white, fontSize: AppConstants().smaller_text_fontSize, ), ), ), ], ), ), ), ); } // 添加最大值标签 if (minMaxData['maxIndex'] != -1 && minMaxData['maxIndex'] != minMaxData['minIndex']) { double maxX = (minMaxData['maxIndex'] + 1).toDouble(); double maxY = minMaxData['maxValue']; // 计算在图表中的相对位置 (0-1) double relativeX = (maxX - xMin) / xRange; double relativeY = (maxY - yMinValue) / yRange; // 转换为像素位置 double left = leftPadding + (relativeX * chartWidth); double top = topPadding + ((1 - relativeY) * chartHeight); // 标签尺寸 double labelWidth = 38.rpx; double labelHeight = 50.rpx; labels.add( Positioned( left: left - labelWidth / 2, // 水平居中 top: top - labelHeight - 8.rpx, // 显示在点的正上方,留出8rpx间距 child: SizedBox( width: labelWidth, height: labelHeight, child: Stack( alignment: Alignment.center, children: [ // SVG图片作为背景 SvgPicture.asset( 'assets/img/icon/location.svg', fit: BoxFit.contain, color: stringToColor("#FF9F66"), ), Padding( padding: EdgeInsets.only(bottom: 12.rpx), child: Text( '${minMaxData['maxValue'].toStringAsFixed(0)}', style: TextStyle( color: Colors.white, fontSize: AppConstants().smaller_text_fontSize, ), ), ), ], ), ), ), ); } return Stack( children: labels, ); } }