From f977a850ae39e9da26fe148a646d20c4326c7a4d Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 14 Nov 2020 16:41:56 +0100 Subject: [PATCH 1/6] Added methods --- lib/src/bezier_chart_widget.dart | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/src/bezier_chart_widget.dart b/lib/src/bezier_chart_widget.dart index ba347fd..bbb55a8 100644 --- a/lib/src/bezier_chart_widget.dart +++ b/lib/src/bezier_chart_widget.dart @@ -11,6 +11,7 @@ import 'package:intl/intl.dart' as intl; import 'my_single_child_scroll_view.dart'; typedef FooterValueBuilder = String Function(double value); +typedef ContentValueBuilder = String Function(double value); typedef FooterDateTimeBuilder = String Function( DateTime value, BezierChartScale scaleType); @@ -78,6 +79,8 @@ class BezierChart extends StatefulWidget { ///Notify if the `BezierChartScale` changed, it only works with date scales. final ValueChanged onScaleChanged; + final ContentValueBuilder bubbleContentBuilder; + BezierChart({ Key key, this.config, @@ -93,6 +96,7 @@ class BezierChart extends StatefulWidget { this.onDateTimeSelected, this.onValueSelected, this.selectedValue, + this.bubbleContentBuilder, this.bezierChartAggregation = BezierChartAggregation.SUM, @required this.bezierChartScale, @required this.series, @@ -879,6 +883,7 @@ class BezierChartState extends State footerDateTimeBuilder: widget.footerDateTimeBuilder, bubbleLabelDateTimeBuilder: widget.bubbleLabelDateTimeBuilder, + bubbleContentBuilder: widget.bubbleContentBuilder, onValueSelected: (val) { if (widget.onValueSelected != null) { if (_valueSelected == null) { @@ -1026,6 +1031,8 @@ class _BezierChartPainter extends CustomPainter { final ValueChanged onDateTimeSelected; final bool shouldRepaintChart; + final ContentValueBuilder bubbleContentBuilder; + _BezierChartPainter({ this.shouldRepaintChart, this.config, @@ -1046,6 +1053,7 @@ class _BezierChartPainter extends CustomPainter { this.minYValue, this.onDateTimeSelected, this.onValueSelected, + this.bubbleContentBuilder, }) : super(repaint: animation) { _maxValueY = _getMaxValueY(); _maxValueX = _getMaxValueX(); @@ -1132,7 +1140,6 @@ class _BezierChartPainter extends CustomPainter { _AxisValue lastPoint; //display each data point - double previousValue; for (int i = 0; i < xAxisDataPoints.length; i++) { double value = 0.0; @@ -1176,13 +1183,8 @@ class _BezierChartPainter extends CustomPainter { if (line.onMissingValue != null) { isMissingValue = true; value = line.onMissingValue(xAxisDataPoints[i].xAxis as DateTime); - } else if (config.displayPreviousDataPointWhenNoValue && - previousValue != null) { - isMissingValue = true; - value = previousValue; } } - previousValue = value; } final double axisY = value; @@ -1262,7 +1264,7 @@ class _BezierChartPainter extends CustomPainter { onDataPointSnap(xAxisDataPoints[i].value); _currentCustomValues.add( _CustomValue( - value: "${formatAsIntOrDouble(axisY)}", + value: bubbleContentBuilder != null ? bubbleContentBuilder(axisY) : "${formatAsIntOrDouble(axisY)}", label: line.label, color: line.lineColor, ), From 92fc77e1621f2c640d37c1d1fcc0822a0f8e0146 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 14 Nov 2020 16:43:26 +0100 Subject: [PATCH 2/6] Merged lastest pull request --- lib/src/bezier_chart_widget.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/src/bezier_chart_widget.dart b/lib/src/bezier_chart_widget.dart index bbb55a8..3b58a16 100644 --- a/lib/src/bezier_chart_widget.dart +++ b/lib/src/bezier_chart_widget.dart @@ -1140,6 +1140,7 @@ class _BezierChartPainter extends CustomPainter { _AxisValue lastPoint; //display each data point + double previousValue; for (int i = 0; i < xAxisDataPoints.length; i++) { double value = 0.0; @@ -1183,8 +1184,13 @@ class _BezierChartPainter extends CustomPainter { if (line.onMissingValue != null) { isMissingValue = true; value = line.onMissingValue(xAxisDataPoints[i].xAxis as DateTime); + } else if (config.displayPreviousDataPointWhenNoValue && + previousValue != null) { + isMissingValue = true; + value = previousValue; } } + previousValue = value; } final double axisY = value; From ec9d22b5d9b4c42e041340209f89ada3fedb51cd Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 14 Nov 2020 16:52:04 +0100 Subject: [PATCH 3/6] Added description --- lib/src/bezier_chart_widget.dart | 332 +++++++++---------------------- 1 file changed, 93 insertions(+), 239 deletions(-) diff --git a/lib/src/bezier_chart_widget.dart b/lib/src/bezier_chart_widget.dart index 3b58a16..3a608c6 100644 --- a/lib/src/bezier_chart_widget.dart +++ b/lib/src/bezier_chart_widget.dart @@ -12,8 +12,7 @@ import 'my_single_child_scroll_view.dart'; typedef FooterValueBuilder = String Function(double value); typedef ContentValueBuilder = String Function(double value); -typedef FooterDateTimeBuilder = String Function( - DateTime value, BezierChartScale scaleType); +typedef FooterDateTimeBuilder = String Function(DateTime value, BezierChartScale scaleType); class BezierChart extends StatefulWidget { ///Chart configuration @@ -79,6 +78,7 @@ class BezierChart extends StatefulWidget { ///Notify if the `BezierChartScale` changed, it only works with date scales. final ValueChanged onScaleChanged; + ///[Optional] This is used to display a custom value based on the current 'y' value inside the bubble final ContentValueBuilder bubbleContentBuilder; BezierChart({ @@ -102,46 +102,31 @@ class BezierChart extends StatefulWidget { @required this.series, this.onScaleChanged, }) : assert( - (bezierChartScale == BezierChartScale.CUSTOM && - xAxisCustomValues != null && - series != null) || - bezierChartScale != BezierChartScale.CUSTOM, + (bezierChartScale == BezierChartScale.CUSTOM && xAxisCustomValues != null && series != null) || bezierChartScale != BezierChartScale.CUSTOM, "The xAxisCustomValues and series must not be null", ), assert( - bezierChartScale == BezierChartScale.CUSTOM && - _isSorted(xAxisCustomValues) || - bezierChartScale != BezierChartScale.CUSTOM, + bezierChartScale == BezierChartScale.CUSTOM && _isSorted(xAxisCustomValues) || bezierChartScale != BezierChartScale.CUSTOM, "The xAxisCustomValues must be sorted in increasing way", ), assert( - bezierChartScale == BezierChartScale.CUSTOM && - _compareLengths(xAxisCustomValues.length, series) || + bezierChartScale == BezierChartScale.CUSTOM && _compareLengths(xAxisCustomValues.length, series) || bezierChartScale != BezierChartScale.CUSTOM, "xAxisCustomValues lenght must be equals to series length", ), assert( - (bezierChartScale == BezierChartScale.CUSTOM && - _areAllPositive(xAxisCustomValues) && - _checkCustomValues(series)) || + (bezierChartScale == BezierChartScale.CUSTOM && _areAllPositive(xAxisCustomValues) && _checkCustomValues(series)) || bezierChartScale != BezierChartScale.CUSTOM, "xAxisCustomValues and series must be positives", ), assert( - (((bezierChartScale != BezierChartScale.CUSTOM) && - fromDate != null && - toDate != null) || - (bezierChartScale == BezierChartScale.CUSTOM && - fromDate == null && - toDate == null)), + (((bezierChartScale != BezierChartScale.CUSTOM) && fromDate != null && toDate != null) || + (bezierChartScale == BezierChartScale.CUSTOM && fromDate == null && toDate == null)), "fromDate and toDate must not be null", ), assert( - (((bezierChartScale != BezierChartScale.CUSTOM) && - toDate.isAfter(fromDate)) || - (bezierChartScale == BezierChartScale.CUSTOM && - fromDate == null && - toDate == null)), + (((bezierChartScale != BezierChartScale.CUSTOM) && toDate.isAfter(fromDate)) || + (bezierChartScale == BezierChartScale.CUSTOM && fromDate == null && toDate == null)), "toDate must be after of fromDate", ), super(key: key); @@ -151,8 +136,7 @@ class BezierChart extends StatefulWidget { } @visibleForTesting -class BezierChartState extends State - with SingleTickerProviderStateMixin { +class BezierChartState extends State with SingleTickerProviderStateMixin { AnimationController _animationController; ScrollController _scrollController; GlobalKey _keyScroll = GlobalKey(); @@ -204,8 +188,7 @@ class BezierChartState extends State ///Refresh the position of the vertical/bubble void _refreshPosition(details) { - if (_animationController.status == AnimationStatus.completed && - _displayIndicator) { + if (_animationController.status == AnimationStatus.completed && _displayIndicator) { return _updatePosition(details.globalPosition); } } @@ -217,9 +200,7 @@ class BezierChartState extends State if (position == null) return; return setState( () { - final fixedPosition = Offset( - position.dx + _scrollController.offset - horizontalPadding, - position.dy); + final fixedPosition = Offset(position.dx + _scrollController.offset - horizontalPadding, position.dy); _verticalIndicatorPosition = fixedPosition; }, ); @@ -279,8 +260,7 @@ class BezierChartState extends State final newValue = line.onMissingValue(newDate); if (!_tempYValues.contains(newValue)) _tempYValues.add(newValue); //if there is no missingvalue specified we should use 0 as minimum value to avoid overlap - } else if (widget.config.startYAxisFromNonZeroValue && - line.onMissingValue == null) { + } else if (widget.config.startYAxisFromNonZeroValue && line.onMissingValue == null) { if (!_tempYValues.contains(0)) _tempYValues.add(0); } } @@ -292,9 +272,7 @@ class BezierChartState extends State _tempYValues = []; final scale = _currentBezierChartScale; if (scale == BezierChartScale.CUSTOM) { - _xAxisDataPoints = widget.xAxisCustomValues - .map((val) => DataPoint(value: val, xAxis: val)) - .toList(); + _xAxisDataPoints = widget.xAxisCustomValues.map((val) => DataPoint(value: val, xAxis: val)).toList(); } else if (scale == BezierChartScale.HOURLY) { final hours = widget.toDate.difference(widget.fromDate).inHours; for (int i = 0; i < hours; i++) { @@ -303,17 +281,14 @@ class BezierChartState extends State hours: (i + 1), ), ); - final newDate = DateTime( - tempDate.year, tempDate.month, tempDate.day, tempDate.hour, 0); + final newDate = DateTime(tempDate.year, tempDate.month, tempDate.day, tempDate.hour, 0); _xAxisDataPoints.add( DataPoint(value: (i * 5).toDouble(), xAxis: newDate), ); _checkMissingValues(newDate); } } else if (scale == BezierChartScale.WEEKLY) { - final days = _convertToDateOnly(widget.toDate) - .difference(_convertToDateOnly(widget.fromDate)) - .inDays; + final days = _convertToDateOnly(widget.toDate).difference(_convertToDateOnly(widget.fromDate)).inDays; for (int i = 0; i <= days; i++) { final newDate = widget.fromDate.add( Duration( @@ -334,9 +309,7 @@ class BezierChartState extends State widget.toDate.year, widget.toDate.month, ); - for (int i = 0; - (startDate.isBefore(endDate) || areEqualDates(startDate, endDate)); - i++) { + for (int i = 0; (startDate.isBefore(endDate) || areEqualDates(startDate, endDate)); i++) { _xAxisDataPoints.add( DataPoint(value: (i * 5).toDouble(), xAxis: startDate), ); @@ -350,9 +323,7 @@ class BezierChartState extends State DateTime endDate = DateTime( widget.toDate.year, ); - for (int i = 0; - (startDate.isBefore(endDate) || areEqualDates(startDate, endDate)); - i++) { + for (int i = 0; (startDate.isBefore(endDate) || areEqualDates(startDate, endDate)); i++) { _xAxisDataPoints.add( DataPoint(value: (i * 5).toDouble(), xAxis: startDate), ); @@ -375,21 +346,17 @@ class BezierChartState extends State double _buildContentWidth(BoxConstraints constraints) { final scale = _currentBezierChartScale; if (scale == BezierChartScale.CUSTOM) { - return widget.config.contentWidth ?? - constraints.maxWidth - 2 * horizontalPadding; + return widget.config.contentWidth ?? constraints.maxWidth - 2 * horizontalPadding; } else { if (scale == BezierChartScale.HOURLY) { horizontalSpacing = constraints.maxWidth / 7; - return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - - horizontalPadding / 2; + return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - horizontalPadding / 2; } else if (scale == BezierChartScale.WEEKLY) { horizontalSpacing = constraints.maxWidth / 7; - return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - - horizontalPadding / 2; + return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - horizontalPadding / 2; } else if (scale == BezierChartScale.MONTHLY) { horizontalSpacing = constraints.maxWidth / 12; - return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - - horizontalPadding / 2; + return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - horizontalPadding / 2; } else if (scale == BezierChartScale.YEARLY) { if (_xAxisDataPoints.length > 12) { horizontalSpacing = constraints.maxWidth / 12; @@ -398,8 +365,7 @@ class BezierChartState extends State } else { horizontalSpacing = constraints.maxWidth / _xAxisDataPoints.length; } - return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - - horizontalPadding; + return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - horizontalPadding; } return 0.0; } @@ -409,14 +375,11 @@ class BezierChartState extends State _onLayoutDone(_) { _yAxisWidth = _keyLastYAxisItem.currentContext?.size?.width; //Move to selected position - if ((widget.selectedDate != null && - _currentBezierChartScale != BezierChartScale.CUSTOM) || - (widget.selectedValue != null && - _currentBezierChartScale == BezierChartScale.CUSTOM)) { + if ((widget.selectedDate != null && _currentBezierChartScale != BezierChartScale.CUSTOM) || + (widget.selectedValue != null && _currentBezierChartScale == BezierChartScale.CUSTOM)) { int index = -1; if (_currentBezierChartScale == BezierChartScale.WEEKLY) { - index = _xAxisDataPoints.indexWhere( - (dp) => areEqualDates((dp.xAxis as DateTime), widget.selectedDate)); + index = _xAxisDataPoints.indexWhere((dp) => areEqualDates((dp.xAxis as DateTime), widget.selectedDate)); } else if (_currentBezierChartScale == BezierChartScale.HOURLY) { index = _xAxisDataPoints.indexWhere((dp) => (dp.xAxis as DateTime).year == widget.selectedDate.year && @@ -424,15 +387,12 @@ class BezierChartState extends State (dp.xAxis as DateTime).day == widget.selectedDate.day && (dp.xAxis as DateTime).hour == widget.selectedDate.hour); } else if (_currentBezierChartScale == BezierChartScale.MONTHLY) { - index = _xAxisDataPoints.indexWhere((dp) => - (dp.xAxis as DateTime).year == widget.selectedDate.year && - (dp.xAxis as DateTime).month == widget.selectedDate.month); + index = _xAxisDataPoints + .indexWhere((dp) => (dp.xAxis as DateTime).year == widget.selectedDate.year && (dp.xAxis as DateTime).month == widget.selectedDate.month); } else if (_currentBezierChartScale == BezierChartScale.YEARLY) { - index = _xAxisDataPoints.indexWhere( - (dp) => (dp.xAxis as DateTime).year == widget.selectedDate.year); + index = _xAxisDataPoints.indexWhere((dp) => (dp.xAxis as DateTime).year == widget.selectedDate.year); } else if (_currentBezierChartScale == BezierChartScale.CUSTOM) { - index = _xAxisDataPoints - .indexWhere((dp) => (dp.xAxis as double) == widget.selectedValue); + index = _xAxisDataPoints.indexWhere((dp) => (dp.xAxis as double) == widget.selectedValue); } //If it's a valid index then scroll to the date selected based on the current position @@ -440,8 +400,7 @@ class BezierChartState extends State Offset fixedPosition; if (_currentBezierChartScale == BezierChartScale.CUSTOM) { final space = (_contentWidth / _xAxisDataPoints.length); - fixedPosition = - Offset(isOnlyOneAxis ? 0.0 : (index * space) + space / 2, 0.0); + fixedPosition = Offset(isOnlyOneAxis ? 0.0 : (index * space) + space / 2, 0.0); _scrollController.jumpTo((index * space)); setState( () { @@ -456,17 +415,10 @@ class BezierChartState extends State }, ); } else { - final jumpToX = (index * horizontalSpacing) - - horizontalPadding / 2 - - _keyScroll.currentContext.size.width / 2; + final jumpToX = (index * horizontalSpacing) - horizontalPadding / 2 - _keyScroll.currentContext.size.width / 2; _scrollController.jumpTo(jumpToX); - fixedPosition = Offset( - isOnlyOneAxis - ? 0.0 - : (index * horizontalSpacing + 2 * horizontalPadding) - - _scrollController.offset, - 0.0); + fixedPosition = Offset(isOnlyOneAxis ? 0.0 : (index * horizontalSpacing + 2 * horizontalPadding) - _scrollController.offset, 0.0); _verticalIndicatorPosition = fixedPosition; _onDisplayIndicator( LongPressMoveUpdateDetails( @@ -484,8 +436,7 @@ class BezierChartState extends State } _checkIfNeedScroll() { - if (_contentWidth > - _keyScroll.currentContext.size.width - horizontalPadding * 2) { + if (_contentWidth > _keyScroll.currentContext.size.width - horizontalPadding * 2) { _isScrollable = true; } } @@ -505,13 +456,11 @@ class BezierChartState extends State for (DataPoint dataPoint in line.data) { String key; if (_currentBezierChartScale == BezierChartScale.MONTHLY) { - key = - "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')}"; + key = "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')}"; } else if (_currentBezierChartScale == BezierChartScale.YEARLY) { key = "${dataPoint.xAxis.year}"; } else if (_currentBezierChartScale == BezierChartScale.WEEKLY) { - key = - "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')},${dataPoint.xAxis.day.toString().padLeft(2, '0')}"; + key = "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')},${dataPoint.xAxis.day.toString().padLeft(2, '0')}"; } else { key = "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')},${dataPoint.xAxis.day.toString().padLeft(2, '0')},${dataPoint.xAxis.hour.toString().padLeft(2, '0')}"; @@ -526,29 +475,17 @@ class BezierChartState extends State Map valueMap = Map(); if (widget.bezierChartAggregation == BezierChartAggregation.SUM) { - valueMap = tmpMap.map((k, v) => MapEntry( - k, - v.reduce( - (c1, c2) => double.parse((c1 + c2).toStringAsFixed(2))))); - } else if (widget.bezierChartAggregation == - BezierChartAggregation.FIRST) { - valueMap = - tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1))); - } else if (widget.bezierChartAggregation == - BezierChartAggregation.AVERAGE) { - valueMap = tmpMap.map( - (k, v) => MapEntry(k, v.reduce((c1, c2) => c1 + c2) / v.length)); - } else if (widget.bezierChartAggregation == - BezierChartAggregation.COUNT) { + valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => double.parse((c1 + c2).toStringAsFixed(2))))); + } else if (widget.bezierChartAggregation == BezierChartAggregation.FIRST) { + valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1))); + } else if (widget.bezierChartAggregation == BezierChartAggregation.AVERAGE) { + valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1 + c2) / v.length)); + } else if (widget.bezierChartAggregation == BezierChartAggregation.COUNT) { valueMap = tmpMap.map((k, v) => MapEntry(k, v.length.toDouble())); - } else if (widget.bezierChartAggregation == - BezierChartAggregation.MAX) { - valueMap = tmpMap.map( - (k, v) => MapEntry(k, v.reduce((c1, c2) => c1 > c2 ? c1 : c2))); - } else if (widget.bezierChartAggregation == - BezierChartAggregation.MIN) { - valueMap = tmpMap.map( - (k, v) => MapEntry(k, v.reduce((c1, c2) => c1 < c2 ? c1 : c2))); + } else if (widget.bezierChartAggregation == BezierChartAggregation.MAX) { + valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1 > c2 ? c1 : c2))); + } else if (widget.bezierChartAggregation == BezierChartAggregation.MIN) { + valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1 < c2 ? c1 : c2))); } List> newDataPoints = []; @@ -711,8 +648,7 @@ class BezierChartState extends State } void _notifyScaleChanged(BezierChartScale lastScale) { - if (widget.onScaleChanged != null && - lastScale != _currentBezierChartScale) { + if (widget.onScaleChanged != null && lastScale != _currentBezierChartScale) { widget.onScaleChanged(_currentBezierChartScale); } } @@ -795,9 +731,7 @@ class BezierChartState extends State //https://github.com/flutter/flutter/issues/13102 return Container( decoration: BoxDecoration( - color: widget.config.backgroundGradient != null - ? null - : widget.config.backgroundColor, + color: widget.config.backgroundGradient != null ? null : widget.config.backgroundColor, gradient: widget.config.backgroundGradient, ), alignment: Alignment.center, @@ -815,9 +749,7 @@ class BezierChartState extends State } }, child: GestureDetector( - onLongPressStart: widget.config.updatePositionOnTap - ? null - : (isPinchZoomActive ? null : _onDisplayIndicator), + onLongPressStart: widget.config.updatePositionOnTap ? null : (isPinchZoomActive ? null : _onDisplayIndicator), onLongPressMoveUpdate: isPinchZoomActive ? null : _refreshPosition, onScaleStart: (_) { _previousScale = _currentScale; @@ -828,12 +760,8 @@ class BezierChartState extends State !_displayIndicator ? (details) => _onPinchZoom(_previousScale * details.scale) : null, - onTap: widget.config.updatePositionOnTap - ? null - : (isPinchZoomActive ? null : _onHideIndicator), - onTapDown: widget.config.updatePositionOnTap - ? (isPinchZoomActive ? null : _refreshPosition) - : null, + onTap: widget.config.updatePositionOnTap ? null : (isPinchZoomActive ? null : _onHideIndicator), + onTapDown: widget.config.updatePositionOnTap ? (isPinchZoomActive ? null : _refreshPosition) : null, child: LayoutBuilder( builder: (context, constraints) { _contentWidth = _buildContentWidth(constraints); @@ -842,9 +770,7 @@ class BezierChartState extends State items.add( MySingleChildScrollView( controller: _scrollController, - physics: isPinchZoomActive || !_isScrollable - ? NeverScrollableScrollPhysics() - : widget.config.physics, + physics: isPinchZoomActive || !_isScrollable ? NeverScrollableScrollPhysics() : widget.config.physics, key: _keyScroll, scrollDirection: Axis.horizontal, padding: EdgeInsets.symmetric(horizontal: horizontalPadding), @@ -875,14 +801,11 @@ class BezierChartState extends State xAxisDataPoints: _xAxisDataPoints, onDataPointSnap: _onDataPointSnap, maxWidth: MediaQuery.of(context).size.width, - scrollOffset: _scrollController.hasClients - ? _scrollController.offset - : 0.0, + scrollOffset: _scrollController.hasClients ? _scrollController.offset : 0.0, footerValueBuilder: widget.footerValueBuilder, bubbleLabelValueBuilder: widget.bubbleLabelValueBuilder, footerDateTimeBuilder: widget.footerDateTimeBuilder, - bubbleLabelDateTimeBuilder: - widget.bubbleLabelDateTimeBuilder, + bubbleLabelDateTimeBuilder: widget.bubbleLabelDateTimeBuilder, bubbleContentBuilder: widget.bubbleContentBuilder, onValueSelected: (val) { if (widget.onValueSelected != null) { @@ -924,44 +847,27 @@ class BezierChartState extends State bottom: 0, child: Container( width: _yAxisWidth + 10, - decoration: widget.config.backgroundGradient != null - ? BoxDecoration( - gradient: widget.config.backgroundGradient) - : null, - color: widget.config.backgroundGradient != null - ? null - : widget.config.backgroundColor, + decoration: widget.config.backgroundGradient != null ? BoxDecoration(gradient: widget.config.backgroundGradient) : null, + color: widget.config.backgroundGradient != null ? null : widget.config.backgroundColor, ), )); } final fontSize = widget.config.yAxisTextStyle?.fontSize ?? 8.0; - final maxValue = _yValues.last - - (widget.config.startYAxisFromNonZeroValue - ? _yValues.first - : 0.0); - final steps = widget.config.stepsYAxis != null && - widget.config.stepsYAxis > 0 - ? widget.config.stepsYAxis - : null; + final maxValue = _yValues.last - (widget.config.startYAxisFromNonZeroValue ? _yValues.first : 0.0); + final steps = widget.config.stepsYAxis != null && widget.config.stepsYAxis > 0 ? widget.config.stepsYAxis : null; _addYItem(double value, {Key key}) { items.add( Positioned( - bottom: _getRealValue( - value - - (widget.config.startYAxisFromNonZeroValue - ? _yValues.first - : 0.0), - maxHeight - widget.config.footerHeight, - maxValue) + + bottom: _getRealValue(value - (widget.config.startYAxisFromNonZeroValue ? _yValues.first : 0.0), + maxHeight - widget.config.footerHeight, maxValue) + widget.config.footerHeight + fontSize / 2, left: 10.0, child: Text( formatAsIntOrDouble(value), key: key, - style: widget.config.yAxisTextStyle ?? - TextStyle(color: Colors.white, fontSize: fontSize), + style: widget.config.yAxisTextStyle ?? TextStyle(color: Colors.white, fontSize: fontSize), ), ), ); @@ -969,21 +875,16 @@ class BezierChartState extends State if (steps != null) { final max = _yValues.last; - final min = widget.config.startYAxisFromNonZeroValue - ? _yValues.first.ceil() - : 0; + final min = widget.config.startYAxisFromNonZeroValue ? _yValues.first.ceil() : 0; for (int i = min; i < max + steps; i++) { if (i % steps == 0) { - bool isLast = - (i + steps) > max && (i + steps) >= (max + steps); - _addYItem(i.toDouble(), - key: isLast ? _keyLastYAxisItem : null); + bool isLast = (i + steps) > max && (i + steps) >= (max + steps); + _addYItem(i.toDouble(), key: isLast ? _keyLastYAxisItem : null); } } } else { for (double val in _yValues) { - _addYItem(val, - key: val == _yValues.last ? _keyLastYAxisItem : null); + _addYItem(val, key: val == _yValues.last ? _keyLastYAxisItem : null); } } } @@ -999,8 +900,7 @@ class BezierChartState extends State } ///return the real value of canvas -_getRealValue(double value, double maxConstraint, double maxValue) => - maxConstraint * value / (maxValue == 0 ? 1 : maxValue); +_getRealValue(double value, double maxConstraint, double maxValue) => maxConstraint * value / (maxValue == 0 ? 1 : maxValue); //BezierChart class _BezierChartPainter extends CustomPainter { @@ -1184,8 +1084,7 @@ class _BezierChartPainter extends CustomPainter { if (line.onMissingValue != null) { isMissingValue = true; value = line.onMissingValue(xAxisDataPoints[i].xAxis as DateTime); - } else if (config.displayPreviousDataPointWhenNoValue && - previousValue != null) { + } else if (config.displayPreviousDataPointWhenNoValue && previousValue != null) { isMissingValue = true; value = previousValue; } @@ -1202,8 +1101,7 @@ class _BezierChartPainter extends CustomPainter { ); if (config.displayLinesXAxis && series.length == 1) { - canvas.drawLine( - Offset(valueX, height), Offset(valueX, valueY), paintXLines); + canvas.drawLine(Offset(valueX, height), Offset(valueX, valueY), paintXLines); } if (lastPoint == null) { @@ -1212,8 +1110,7 @@ class _BezierChartPainter extends CustomPainter { } final double controlPointX = lastPoint.x + (valueX - lastPoint.x) / 2; - path.cubicTo( - controlPointX, lastPoint.y, controlPointX, valueY, valueX, valueY); + path.cubicTo(controlPointX, lastPoint.y, controlPointX, valueY, valueX, valueY); if (isMissingValue) { if (config.displayDataPointWhenNoValue) { dataPoints.add(Offset(valueX, valueY)); @@ -1222,9 +1119,7 @@ class _BezierChartPainter extends CustomPainter { dataPoints.add(Offset(valueX, valueY)); } - if (verticalIndicatorPosition != null && - verticalX >= lastPoint.x && - verticalX <= valueX) { + if (verticalIndicatorPosition != null && verticalX >= lastPoint.x && verticalX <= valueX) { //points to draw the info p0 = Offset(lastPoint.x, height - lastPoint.y); p1 = Offset(controlPointX, height - lastPoint.y); @@ -1252,8 +1147,7 @@ class _BezierChartPainter extends CustomPainter { } //if vertical indicator is in range then display the bubble info - if (verticalX >= valueX - (valueX - lastX) / 2 && - verticalX <= valueX + (nextX - valueX) / 2) { + if (verticalX >= valueX - (valueX - lastX) / 2 && verticalX <= valueX + (nextX - valueX) / 2) { _currentXDataPoint = xAxisDataPoints[i]; if (_currentCustomValues.length < series.length) { bool isDouble = (xAxisDataPoints[i].xAxis is double); @@ -1289,8 +1183,7 @@ class _BezierChartPainter extends CustomPainter { textPainterXAxis.layout(); textPainterXAxis.paint( canvas, - Offset(valueX - textPainterXAxis.width / 2, - height + textPainterXAxis.height / 1.5), + Offset(valueX - textPainterXAxis.width / 2, height + textPainterXAxis.height / 1.5), ); } @@ -1356,9 +1249,7 @@ class _BezierChartPainter extends CustomPainter { double offsetInfo = 42 + ((_currentCustomValues.length - 1.0) * 10.0); final centerForCircle = Offset(verticalX, height - yValue); - final center = config.verticalIndicatorFixedPosition - ? Offset(verticalX, offsetInfo) - : centerForCircle; + final center = config.verticalIndicatorFixedPosition ? Offset(verticalX, offsetInfo) : centerForCircle; if (config.showVerticalIndicator) { canvas.drawLine( @@ -1381,13 +1272,10 @@ class _BezierChartPainter extends CustomPainter { List textValues = []; List centerCircles = []; - double space = - 10 - ((infoHeight / (8.75)) * _currentCustomValues.length); - infoHeight = - infoHeight + (_currentCustomValues.length - 1) * (infoHeight / 3); + double space = 10 - ((infoHeight / (8.75)) * _currentCustomValues.length); + infoHeight = infoHeight + (_currentCustomValues.length - 1) * (infoHeight / 3); - for (_CustomValue customValue - in _currentCustomValues.reversed.toList()) { + for (_CustomValue customValue in _currentCustomValues.reversed.toList()) { textValues.add( TextSpan( text: config.bubbleIndicatorValueFormat != null @@ -1404,13 +1292,7 @@ class _BezierChartPainter extends CustomPainter { ); centerCircles.add( // Offset(center.dx - infoWidth / 2 + radiusDotIndicatorItems * 1.5, - Offset( - center.dx, - center.dy - - offsetInfo - - radiusDotIndicatorItems + - space + - (_currentCustomValues.length == 1 ? 1 : 0)), + Offset(center.dx, center.dy - offsetInfo - radiusDotIndicatorItems + space + (_currentCustomValues.length == 1 ? 1 : 0)), ); space += 12.5; } @@ -1427,20 +1309,16 @@ class _BezierChartPainter extends CustomPainter { ); textPainter.layout(); - infoWidth = - textPainter.width + radiusDotIndicatorItems * 2 + horizontalPadding; + infoWidth = textPainter.width + radiusDotIndicatorItems * 2 + horizontalPadding; ///Draw Bubble Indicator Info /// Draw shadow bubble info if (animation.isCompleted) { Path path = Path(); - path.moveTo(center.dx - infoWidth / 2 + 4, - center.dy - offsetInfo + infoHeight / 1.8); - path.lineTo(center.dx + infoWidth / 2 + 4, - center.dy - offsetInfo + infoHeight / 1.8); - path.lineTo(center.dx + infoWidth / 2 + 4, - center.dy - offsetInfo - infoHeight / 3); + path.moveTo(center.dx - infoWidth / 2 + 4, center.dy - offsetInfo + infoHeight / 1.8); + path.lineTo(center.dx + infoWidth / 2 + 4, center.dy - offsetInfo + infoHeight / 1.8); + path.lineTo(center.dx + infoWidth / 2 + 4, center.dy - offsetInfo - infoHeight / 3); //path.close(); // canvas.drawShadow(path, Colors.black, 20.0, false); canvas.drawPath(path, paintControlPoints..color = Colors.black12); @@ -1471,16 +1349,9 @@ class _BezierChartPainter extends CustomPainter { Path pathArrow = Path(); - pathArrow.moveTo(center.dx - triangleSize, - center.dy - offsetInfo * animation.value + infoHeight / 2.1); - pathArrow.lineTo( - center.dx, - center.dy - - offsetInfo * animation.value + - infoHeight / 2.1 + - triangleSize * 1.5); - pathArrow.lineTo(center.dx + triangleSize, - center.dy - offsetInfo * animation.value + infoHeight / 2.1); + pathArrow.moveTo(center.dx - triangleSize, center.dy - offsetInfo * animation.value + infoHeight / 2.1); + pathArrow.lineTo(center.dx, center.dy - offsetInfo * animation.value + infoHeight / 2.1 + triangleSize * 1.5); + pathArrow.lineTo(center.dx + triangleSize, center.dy - offsetInfo * animation.value + infoHeight / 2.1); pathArrow.close(); canvas.drawPath( pathArrow, @@ -1502,12 +1373,7 @@ class _BezierChartPainter extends CustomPainter { for (int z = 0; z < _currentCustomValues.length; z++) { _CustomValue customValue = _currentCustomValues[z]; Offset centerIndicator = centerCircles.reversed.toList()[z]; - Offset fixedCenter = Offset( - centerIndicator.dx - - infoWidth / 2 + - radiusDotIndicatorItems + - 4, - centerIndicator.dy); + Offset fixedCenter = Offset(centerIndicator.dx - infoWidth / 2 + radiusDotIndicatorItems + 4, centerIndicator.dy); canvas.drawCircle( fixedCenter, radiusDotIndicatorItems, @@ -1532,10 +1398,8 @@ class _BezierChartPainter extends CustomPainter { if (bubbleLabelValueBuilder != null && scale == BezierChartScale.CUSTOM) { return bubbleLabelValueBuilder(_currentXDataPoint.value); } - if (bubbleLabelDateTimeBuilder != null && - scale != BezierChartScale.CUSTOM) { - return bubbleLabelDateTimeBuilder( - _currentXDataPoint.xAxis as DateTime, scale); + if (bubbleLabelDateTimeBuilder != null && scale != BezierChartScale.CUSTOM) { + return bubbleLabelDateTimeBuilder(_currentXDataPoint.xAxis as DateTime, scale); } if (scale == BezierChartScale.CUSTOM) { return "${formatAsIntOrDouble(_currentXDataPoint.value)}\n"; @@ -1598,8 +1462,7 @@ class _BezierChartPainter extends CustomPainter { } else if (scale == BezierChartScale.MONTHLY) { final dateFormat = intl.DateFormat('MMM'); final dateFormatYear = intl.DateFormat('y'); - final year = - dateFormatYear.format(dataPoint.xAxis as DateTime).substring(2); + final year = dateFormatYear.format(dataPoint.xAxis as DateTime).substring(2); return "${dateFormat.format(dataPoint.xAxis as DateTime)}\n'$year"; } else if (scale == BezierChartScale.YEARLY) { final dateFormat = intl.DateFormat('y'); @@ -1626,15 +1489,11 @@ class _BezierChartPainter extends CustomPainter { //print("p0: $p0, p1: $p1, p2: $p2, p3: $p3 , t: $t"); - final y = pow(1 - t, 3) * y0 + - 3 * pow(1 - t, 2) * t * y1 + - 3 * (1 - t) * pow(t, 2) * y2 + - pow(t, 3) * y3; + final y = pow(1 - t, 3) * y0 + 3 * pow(1 - t, 2) * t * y1 + 3 * (1 - t) * pow(t, 2) * y2 + pow(t, 3) * y3; return y; } - Rect _fromCenter({Offset center, double width, double height}) => - Rect.fromLTRB( + Rect _fromCenter({Offset center, double width, double height}) => Rect.fromLTRB( center.dx - width / 2, center.dy - height / 2, center.dx + width / 2, @@ -1720,12 +1579,7 @@ class _CustomValue { } bool areEqualDates(DateTime dateTime1, DateTime dateTime2) => - dateTime1.year == dateTime2.year && - dateTime1.month == dateTime2.month && - dateTime1.day == dateTime2.day; + dateTime1.year == dateTime2.year && dateTime1.month == dateTime2.month && dateTime1.day == dateTime2.day; bool areEqualDatesIncludingHour(DateTime dateTime1, DateTime dateTime2) => - dateTime1.year == dateTime2.year && - dateTime1.month == dateTime2.month && - dateTime1.day == dateTime2.day && - dateTime1.hour == dateTime2.hour; + dateTime1.year == dateTime2.year && dateTime1.month == dateTime2.month && dateTime1.day == dateTime2.day && dateTime1.hour == dateTime2.hour; From a3bf705481f4f484b253f7047a8c3dd3572e7eec Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 14 Nov 2020 16:54:38 +0100 Subject: [PATCH 4/6] Fixed spacing --- lib/src/bezier_chart_widget.dart | 331 ++++++++++++++++++++++--------- 1 file changed, 239 insertions(+), 92 deletions(-) diff --git a/lib/src/bezier_chart_widget.dart b/lib/src/bezier_chart_widget.dart index 3a608c6..f76896b 100644 --- a/lib/src/bezier_chart_widget.dart +++ b/lib/src/bezier_chart_widget.dart @@ -12,7 +12,8 @@ import 'my_single_child_scroll_view.dart'; typedef FooterValueBuilder = String Function(double value); typedef ContentValueBuilder = String Function(double value); -typedef FooterDateTimeBuilder = String Function(DateTime value, BezierChartScale scaleType); +typedef FooterDateTimeBuilder = String Function( + DateTime value, BezierChartScale scaleType); class BezierChart extends StatefulWidget { ///Chart configuration @@ -102,31 +103,46 @@ class BezierChart extends StatefulWidget { @required this.series, this.onScaleChanged, }) : assert( - (bezierChartScale == BezierChartScale.CUSTOM && xAxisCustomValues != null && series != null) || bezierChartScale != BezierChartScale.CUSTOM, + (bezierChartScale == BezierChartScale.CUSTOM && + xAxisCustomValues != null && + series != null) || + bezierChartScale != BezierChartScale.CUSTOM, "The xAxisCustomValues and series must not be null", ), assert( - bezierChartScale == BezierChartScale.CUSTOM && _isSorted(xAxisCustomValues) || bezierChartScale != BezierChartScale.CUSTOM, + bezierChartScale == BezierChartScale.CUSTOM && + _isSorted(xAxisCustomValues) || + bezierChartScale != BezierChartScale.CUSTOM, "The xAxisCustomValues must be sorted in increasing way", ), assert( - bezierChartScale == BezierChartScale.CUSTOM && _compareLengths(xAxisCustomValues.length, series) || + bezierChartScale == BezierChartScale.CUSTOM && + _compareLengths(xAxisCustomValues.length, series) || bezierChartScale != BezierChartScale.CUSTOM, "xAxisCustomValues lenght must be equals to series length", ), assert( - (bezierChartScale == BezierChartScale.CUSTOM && _areAllPositive(xAxisCustomValues) && _checkCustomValues(series)) || + (bezierChartScale == BezierChartScale.CUSTOM && + _areAllPositive(xAxisCustomValues) && + _checkCustomValues(series)) || bezierChartScale != BezierChartScale.CUSTOM, "xAxisCustomValues and series must be positives", ), assert( - (((bezierChartScale != BezierChartScale.CUSTOM) && fromDate != null && toDate != null) || - (bezierChartScale == BezierChartScale.CUSTOM && fromDate == null && toDate == null)), + (((bezierChartScale != BezierChartScale.CUSTOM) && + fromDate != null && + toDate != null) || + (bezierChartScale == BezierChartScale.CUSTOM && + fromDate == null && + toDate == null)), "fromDate and toDate must not be null", ), assert( - (((bezierChartScale != BezierChartScale.CUSTOM) && toDate.isAfter(fromDate)) || - (bezierChartScale == BezierChartScale.CUSTOM && fromDate == null && toDate == null)), + (((bezierChartScale != BezierChartScale.CUSTOM) && + toDate.isAfter(fromDate)) || + (bezierChartScale == BezierChartScale.CUSTOM && + fromDate == null && + toDate == null)), "toDate must be after of fromDate", ), super(key: key); @@ -136,7 +152,8 @@ class BezierChart extends StatefulWidget { } @visibleForTesting -class BezierChartState extends State with SingleTickerProviderStateMixin { +class BezierChartState extends State + with SingleTickerProviderStateMixin { AnimationController _animationController; ScrollController _scrollController; GlobalKey _keyScroll = GlobalKey(); @@ -188,7 +205,8 @@ class BezierChartState extends State with SingleTickerProviderState ///Refresh the position of the vertical/bubble void _refreshPosition(details) { - if (_animationController.status == AnimationStatus.completed && _displayIndicator) { + if (_animationController.status == AnimationStatus.completed && + _displayIndicator) { return _updatePosition(details.globalPosition); } } @@ -200,7 +218,9 @@ class BezierChartState extends State with SingleTickerProviderState if (position == null) return; return setState( () { - final fixedPosition = Offset(position.dx + _scrollController.offset - horizontalPadding, position.dy); + final fixedPosition = Offset( + position.dx + _scrollController.offset - horizontalPadding, + position.dy); _verticalIndicatorPosition = fixedPosition; }, ); @@ -260,7 +280,8 @@ class BezierChartState extends State with SingleTickerProviderState final newValue = line.onMissingValue(newDate); if (!_tempYValues.contains(newValue)) _tempYValues.add(newValue); //if there is no missingvalue specified we should use 0 as minimum value to avoid overlap - } else if (widget.config.startYAxisFromNonZeroValue && line.onMissingValue == null) { + } else if (widget.config.startYAxisFromNonZeroValue && + line.onMissingValue == null) { if (!_tempYValues.contains(0)) _tempYValues.add(0); } } @@ -272,7 +293,9 @@ class BezierChartState extends State with SingleTickerProviderState _tempYValues = []; final scale = _currentBezierChartScale; if (scale == BezierChartScale.CUSTOM) { - _xAxisDataPoints = widget.xAxisCustomValues.map((val) => DataPoint(value: val, xAxis: val)).toList(); + _xAxisDataPoints = widget.xAxisCustomValues + .map((val) => DataPoint(value: val, xAxis: val)) + .toList(); } else if (scale == BezierChartScale.HOURLY) { final hours = widget.toDate.difference(widget.fromDate).inHours; for (int i = 0; i < hours; i++) { @@ -281,14 +304,17 @@ class BezierChartState extends State with SingleTickerProviderState hours: (i + 1), ), ); - final newDate = DateTime(tempDate.year, tempDate.month, tempDate.day, tempDate.hour, 0); + final newDate = DateTime( + tempDate.year, tempDate.month, tempDate.day, tempDate.hour, 0); _xAxisDataPoints.add( DataPoint(value: (i * 5).toDouble(), xAxis: newDate), ); _checkMissingValues(newDate); } } else if (scale == BezierChartScale.WEEKLY) { - final days = _convertToDateOnly(widget.toDate).difference(_convertToDateOnly(widget.fromDate)).inDays; + final days = _convertToDateOnly(widget.toDate) + .difference(_convertToDateOnly(widget.fromDate)) + .inDays; for (int i = 0; i <= days; i++) { final newDate = widget.fromDate.add( Duration( @@ -309,7 +335,9 @@ class BezierChartState extends State with SingleTickerProviderState widget.toDate.year, widget.toDate.month, ); - for (int i = 0; (startDate.isBefore(endDate) || areEqualDates(startDate, endDate)); i++) { + for (int i = 0; + (startDate.isBefore(endDate) || areEqualDates(startDate, endDate)); + i++) { _xAxisDataPoints.add( DataPoint(value: (i * 5).toDouble(), xAxis: startDate), ); @@ -323,7 +351,9 @@ class BezierChartState extends State with SingleTickerProviderState DateTime endDate = DateTime( widget.toDate.year, ); - for (int i = 0; (startDate.isBefore(endDate) || areEqualDates(startDate, endDate)); i++) { + for (int i = 0; + (startDate.isBefore(endDate) || areEqualDates(startDate, endDate)); + i++) { _xAxisDataPoints.add( DataPoint(value: (i * 5).toDouble(), xAxis: startDate), ); @@ -346,17 +376,21 @@ class BezierChartState extends State with SingleTickerProviderState double _buildContentWidth(BoxConstraints constraints) { final scale = _currentBezierChartScale; if (scale == BezierChartScale.CUSTOM) { - return widget.config.contentWidth ?? constraints.maxWidth - 2 * horizontalPadding; + return widget.config.contentWidth ?? + constraints.maxWidth - 2 * horizontalPadding; } else { if (scale == BezierChartScale.HOURLY) { horizontalSpacing = constraints.maxWidth / 7; - return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - horizontalPadding / 2; + return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - + horizontalPadding / 2; } else if (scale == BezierChartScale.WEEKLY) { horizontalSpacing = constraints.maxWidth / 7; - return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - horizontalPadding / 2; + return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - + horizontalPadding / 2; } else if (scale == BezierChartScale.MONTHLY) { horizontalSpacing = constraints.maxWidth / 12; - return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - horizontalPadding / 2; + return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - + horizontalPadding / 2; } else if (scale == BezierChartScale.YEARLY) { if (_xAxisDataPoints.length > 12) { horizontalSpacing = constraints.maxWidth / 12; @@ -365,7 +399,8 @@ class BezierChartState extends State with SingleTickerProviderState } else { horizontalSpacing = constraints.maxWidth / _xAxisDataPoints.length; } - return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - horizontalPadding; + return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - + horizontalPadding; } return 0.0; } @@ -375,11 +410,14 @@ class BezierChartState extends State with SingleTickerProviderState _onLayoutDone(_) { _yAxisWidth = _keyLastYAxisItem.currentContext?.size?.width; //Move to selected position - if ((widget.selectedDate != null && _currentBezierChartScale != BezierChartScale.CUSTOM) || - (widget.selectedValue != null && _currentBezierChartScale == BezierChartScale.CUSTOM)) { + if ((widget.selectedDate != null && + _currentBezierChartScale != BezierChartScale.CUSTOM) || + (widget.selectedValue != null && + _currentBezierChartScale == BezierChartScale.CUSTOM)) { int index = -1; if (_currentBezierChartScale == BezierChartScale.WEEKLY) { - index = _xAxisDataPoints.indexWhere((dp) => areEqualDates((dp.xAxis as DateTime), widget.selectedDate)); + index = _xAxisDataPoints.indexWhere( + (dp) => areEqualDates((dp.xAxis as DateTime), widget.selectedDate)); } else if (_currentBezierChartScale == BezierChartScale.HOURLY) { index = _xAxisDataPoints.indexWhere((dp) => (dp.xAxis as DateTime).year == widget.selectedDate.year && @@ -387,12 +425,15 @@ class BezierChartState extends State with SingleTickerProviderState (dp.xAxis as DateTime).day == widget.selectedDate.day && (dp.xAxis as DateTime).hour == widget.selectedDate.hour); } else if (_currentBezierChartScale == BezierChartScale.MONTHLY) { - index = _xAxisDataPoints - .indexWhere((dp) => (dp.xAxis as DateTime).year == widget.selectedDate.year && (dp.xAxis as DateTime).month == widget.selectedDate.month); + index = _xAxisDataPoints.indexWhere((dp) => + (dp.xAxis as DateTime).year == widget.selectedDate.year && + (dp.xAxis as DateTime).month == widget.selectedDate.month); } else if (_currentBezierChartScale == BezierChartScale.YEARLY) { - index = _xAxisDataPoints.indexWhere((dp) => (dp.xAxis as DateTime).year == widget.selectedDate.year); + index = _xAxisDataPoints.indexWhere( + (dp) => (dp.xAxis as DateTime).year == widget.selectedDate.year); } else if (_currentBezierChartScale == BezierChartScale.CUSTOM) { - index = _xAxisDataPoints.indexWhere((dp) => (dp.xAxis as double) == widget.selectedValue); + index = _xAxisDataPoints + .indexWhere((dp) => (dp.xAxis as double) == widget.selectedValue); } //If it's a valid index then scroll to the date selected based on the current position @@ -400,7 +441,8 @@ class BezierChartState extends State with SingleTickerProviderState Offset fixedPosition; if (_currentBezierChartScale == BezierChartScale.CUSTOM) { final space = (_contentWidth / _xAxisDataPoints.length); - fixedPosition = Offset(isOnlyOneAxis ? 0.0 : (index * space) + space / 2, 0.0); + fixedPosition = + Offset(isOnlyOneAxis ? 0.0 : (index * space) + space / 2, 0.0); _scrollController.jumpTo((index * space)); setState( () { @@ -415,10 +457,17 @@ class BezierChartState extends State with SingleTickerProviderState }, ); } else { - final jumpToX = (index * horizontalSpacing) - horizontalPadding / 2 - _keyScroll.currentContext.size.width / 2; + final jumpToX = (index * horizontalSpacing) - + horizontalPadding / 2 - + _keyScroll.currentContext.size.width / 2; _scrollController.jumpTo(jumpToX); - fixedPosition = Offset(isOnlyOneAxis ? 0.0 : (index * horizontalSpacing + 2 * horizontalPadding) - _scrollController.offset, 0.0); + fixedPosition = Offset( + isOnlyOneAxis + ? 0.0 + : (index * horizontalSpacing + 2 * horizontalPadding) - + _scrollController.offset, + 0.0); _verticalIndicatorPosition = fixedPosition; _onDisplayIndicator( LongPressMoveUpdateDetails( @@ -436,7 +485,8 @@ class BezierChartState extends State with SingleTickerProviderState } _checkIfNeedScroll() { - if (_contentWidth > _keyScroll.currentContext.size.width - horizontalPadding * 2) { + if (_contentWidth > + _keyScroll.currentContext.size.width - horizontalPadding * 2) { _isScrollable = true; } } @@ -456,11 +506,13 @@ class BezierChartState extends State with SingleTickerProviderState for (DataPoint dataPoint in line.data) { String key; if (_currentBezierChartScale == BezierChartScale.MONTHLY) { - key = "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')}"; + key = + "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')}"; } else if (_currentBezierChartScale == BezierChartScale.YEARLY) { key = "${dataPoint.xAxis.year}"; } else if (_currentBezierChartScale == BezierChartScale.WEEKLY) { - key = "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')},${dataPoint.xAxis.day.toString().padLeft(2, '0')}"; + key = + "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')},${dataPoint.xAxis.day.toString().padLeft(2, '0')}"; } else { key = "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')},${dataPoint.xAxis.day.toString().padLeft(2, '0')},${dataPoint.xAxis.hour.toString().padLeft(2, '0')}"; @@ -475,17 +527,29 @@ class BezierChartState extends State with SingleTickerProviderState Map valueMap = Map(); if (widget.bezierChartAggregation == BezierChartAggregation.SUM) { - valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => double.parse((c1 + c2).toStringAsFixed(2))))); - } else if (widget.bezierChartAggregation == BezierChartAggregation.FIRST) { - valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1))); - } else if (widget.bezierChartAggregation == BezierChartAggregation.AVERAGE) { - valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1 + c2) / v.length)); - } else if (widget.bezierChartAggregation == BezierChartAggregation.COUNT) { + valueMap = tmpMap.map((k, v) => MapEntry( + k, + v.reduce( + (c1, c2) => double.parse((c1 + c2).toStringAsFixed(2))))); + } else if (widget.bezierChartAggregation == + BezierChartAggregation.FIRST) { + valueMap = + tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1))); + } else if (widget.bezierChartAggregation == + BezierChartAggregation.AVERAGE) { + valueMap = tmpMap.map( + (k, v) => MapEntry(k, v.reduce((c1, c2) => c1 + c2) / v.length)); + } else if (widget.bezierChartAggregation == + BezierChartAggregation.COUNT) { valueMap = tmpMap.map((k, v) => MapEntry(k, v.length.toDouble())); - } else if (widget.bezierChartAggregation == BezierChartAggregation.MAX) { - valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1 > c2 ? c1 : c2))); - } else if (widget.bezierChartAggregation == BezierChartAggregation.MIN) { - valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1 < c2 ? c1 : c2))); + } else if (widget.bezierChartAggregation == + BezierChartAggregation.MAX) { + valueMap = tmpMap.map( + (k, v) => MapEntry(k, v.reduce((c1, c2) => c1 > c2 ? c1 : c2))); + } else if (widget.bezierChartAggregation == + BezierChartAggregation.MIN) { + valueMap = tmpMap.map( + (k, v) => MapEntry(k, v.reduce((c1, c2) => c1 < c2 ? c1 : c2))); } List> newDataPoints = []; @@ -648,7 +712,8 @@ class BezierChartState extends State with SingleTickerProviderState } void _notifyScaleChanged(BezierChartScale lastScale) { - if (widget.onScaleChanged != null && lastScale != _currentBezierChartScale) { + if (widget.onScaleChanged != null && + lastScale != _currentBezierChartScale) { widget.onScaleChanged(_currentBezierChartScale); } } @@ -731,7 +796,9 @@ class BezierChartState extends State with SingleTickerProviderState //https://github.com/flutter/flutter/issues/13102 return Container( decoration: BoxDecoration( - color: widget.config.backgroundGradient != null ? null : widget.config.backgroundColor, + color: widget.config.backgroundGradient != null + ? null + : widget.config.backgroundColor, gradient: widget.config.backgroundGradient, ), alignment: Alignment.center, @@ -749,7 +816,9 @@ class BezierChartState extends State with SingleTickerProviderState } }, child: GestureDetector( - onLongPressStart: widget.config.updatePositionOnTap ? null : (isPinchZoomActive ? null : _onDisplayIndicator), + onLongPressStart: widget.config.updatePositionOnTap + ? null + : (isPinchZoomActive ? null : _onDisplayIndicator), onLongPressMoveUpdate: isPinchZoomActive ? null : _refreshPosition, onScaleStart: (_) { _previousScale = _currentScale; @@ -760,8 +829,12 @@ class BezierChartState extends State with SingleTickerProviderState !_displayIndicator ? (details) => _onPinchZoom(_previousScale * details.scale) : null, - onTap: widget.config.updatePositionOnTap ? null : (isPinchZoomActive ? null : _onHideIndicator), - onTapDown: widget.config.updatePositionOnTap ? (isPinchZoomActive ? null : _refreshPosition) : null, + onTap: widget.config.updatePositionOnTap + ? null + : (isPinchZoomActive ? null : _onHideIndicator), + onTapDown: widget.config.updatePositionOnTap + ? (isPinchZoomActive ? null : _refreshPosition) + : null, child: LayoutBuilder( builder: (context, constraints) { _contentWidth = _buildContentWidth(constraints); @@ -770,7 +843,9 @@ class BezierChartState extends State with SingleTickerProviderState items.add( MySingleChildScrollView( controller: _scrollController, - physics: isPinchZoomActive || !_isScrollable ? NeverScrollableScrollPhysics() : widget.config.physics, + physics: isPinchZoomActive || !_isScrollable + ? NeverScrollableScrollPhysics() + : widget.config.physics, key: _keyScroll, scrollDirection: Axis.horizontal, padding: EdgeInsets.symmetric(horizontal: horizontalPadding), @@ -801,11 +876,14 @@ class BezierChartState extends State with SingleTickerProviderState xAxisDataPoints: _xAxisDataPoints, onDataPointSnap: _onDataPointSnap, maxWidth: MediaQuery.of(context).size.width, - scrollOffset: _scrollController.hasClients ? _scrollController.offset : 0.0, + scrollOffset: _scrollController.hasClients + ? _scrollController.offset + : 0.0, footerValueBuilder: widget.footerValueBuilder, bubbleLabelValueBuilder: widget.bubbleLabelValueBuilder, footerDateTimeBuilder: widget.footerDateTimeBuilder, - bubbleLabelDateTimeBuilder: widget.bubbleLabelDateTimeBuilder, + bubbleLabelDateTimeBuilder: + widget.bubbleLabelDateTimeBuilder, bubbleContentBuilder: widget.bubbleContentBuilder, onValueSelected: (val) { if (widget.onValueSelected != null) { @@ -847,27 +925,44 @@ class BezierChartState extends State with SingleTickerProviderState bottom: 0, child: Container( width: _yAxisWidth + 10, - decoration: widget.config.backgroundGradient != null ? BoxDecoration(gradient: widget.config.backgroundGradient) : null, - color: widget.config.backgroundGradient != null ? null : widget.config.backgroundColor, + decoration: widget.config.backgroundGradient != null + ? BoxDecoration( + gradient: widget.config.backgroundGradient) + : null, + color: widget.config.backgroundGradient != null + ? null + : widget.config.backgroundColor, ), )); } final fontSize = widget.config.yAxisTextStyle?.fontSize ?? 8.0; - final maxValue = _yValues.last - (widget.config.startYAxisFromNonZeroValue ? _yValues.first : 0.0); - final steps = widget.config.stepsYAxis != null && widget.config.stepsYAxis > 0 ? widget.config.stepsYAxis : null; + final maxValue = _yValues.last - + (widget.config.startYAxisFromNonZeroValue + ? _yValues.first + : 0.0); + final steps = widget.config.stepsYAxis != null && + widget.config.stepsYAxis > 0 + ? widget.config.stepsYAxis + : null; _addYItem(double value, {Key key}) { items.add( Positioned( - bottom: _getRealValue(value - (widget.config.startYAxisFromNonZeroValue ? _yValues.first : 0.0), - maxHeight - widget.config.footerHeight, maxValue) + + bottom: _getRealValue( + value - + (widget.config.startYAxisFromNonZeroValue + ? _yValues.first + : 0.0), + maxHeight - widget.config.footerHeight, + maxValue) + widget.config.footerHeight + fontSize / 2, left: 10.0, child: Text( formatAsIntOrDouble(value), key: key, - style: widget.config.yAxisTextStyle ?? TextStyle(color: Colors.white, fontSize: fontSize), + style: widget.config.yAxisTextStyle ?? + TextStyle(color: Colors.white, fontSize: fontSize), ), ), ); @@ -875,16 +970,21 @@ class BezierChartState extends State with SingleTickerProviderState if (steps != null) { final max = _yValues.last; - final min = widget.config.startYAxisFromNonZeroValue ? _yValues.first.ceil() : 0; + final min = widget.config.startYAxisFromNonZeroValue + ? _yValues.first.ceil() + : 0; for (int i = min; i < max + steps; i++) { if (i % steps == 0) { - bool isLast = (i + steps) > max && (i + steps) >= (max + steps); - _addYItem(i.toDouble(), key: isLast ? _keyLastYAxisItem : null); + bool isLast = + (i + steps) > max && (i + steps) >= (max + steps); + _addYItem(i.toDouble(), + key: isLast ? _keyLastYAxisItem : null); } } } else { for (double val in _yValues) { - _addYItem(val, key: val == _yValues.last ? _keyLastYAxisItem : null); + _addYItem(val, + key: val == _yValues.last ? _keyLastYAxisItem : null); } } } @@ -900,7 +1000,8 @@ class BezierChartState extends State with SingleTickerProviderState } ///return the real value of canvas -_getRealValue(double value, double maxConstraint, double maxValue) => maxConstraint * value / (maxValue == 0 ? 1 : maxValue); +_getRealValue(double value, double maxConstraint, double maxValue) => + maxConstraint * value / (maxValue == 0 ? 1 : maxValue); //BezierChart class _BezierChartPainter extends CustomPainter { @@ -1084,7 +1185,8 @@ class _BezierChartPainter extends CustomPainter { if (line.onMissingValue != null) { isMissingValue = true; value = line.onMissingValue(xAxisDataPoints[i].xAxis as DateTime); - } else if (config.displayPreviousDataPointWhenNoValue && previousValue != null) { + } else if (config.displayPreviousDataPointWhenNoValue && + previousValue != null) { isMissingValue = true; value = previousValue; } @@ -1101,7 +1203,8 @@ class _BezierChartPainter extends CustomPainter { ); if (config.displayLinesXAxis && series.length == 1) { - canvas.drawLine(Offset(valueX, height), Offset(valueX, valueY), paintXLines); + canvas.drawLine( + Offset(valueX, height), Offset(valueX, valueY), paintXLines); } if (lastPoint == null) { @@ -1110,7 +1213,8 @@ class _BezierChartPainter extends CustomPainter { } final double controlPointX = lastPoint.x + (valueX - lastPoint.x) / 2; - path.cubicTo(controlPointX, lastPoint.y, controlPointX, valueY, valueX, valueY); + path.cubicTo( + controlPointX, lastPoint.y, controlPointX, valueY, valueX, valueY); if (isMissingValue) { if (config.displayDataPointWhenNoValue) { dataPoints.add(Offset(valueX, valueY)); @@ -1119,7 +1223,9 @@ class _BezierChartPainter extends CustomPainter { dataPoints.add(Offset(valueX, valueY)); } - if (verticalIndicatorPosition != null && verticalX >= lastPoint.x && verticalX <= valueX) { + if (verticalIndicatorPosition != null && + verticalX >= lastPoint.x && + verticalX <= valueX) { //points to draw the info p0 = Offset(lastPoint.x, height - lastPoint.y); p1 = Offset(controlPointX, height - lastPoint.y); @@ -1147,7 +1253,8 @@ class _BezierChartPainter extends CustomPainter { } //if vertical indicator is in range then display the bubble info - if (verticalX >= valueX - (valueX - lastX) / 2 && verticalX <= valueX + (nextX - valueX) / 2) { + if (verticalX >= valueX - (valueX - lastX) / 2 && + verticalX <= valueX + (nextX - valueX) / 2) { _currentXDataPoint = xAxisDataPoints[i]; if (_currentCustomValues.length < series.length) { bool isDouble = (xAxisDataPoints[i].xAxis is double); @@ -1183,7 +1290,8 @@ class _BezierChartPainter extends CustomPainter { textPainterXAxis.layout(); textPainterXAxis.paint( canvas, - Offset(valueX - textPainterXAxis.width / 2, height + textPainterXAxis.height / 1.5), + Offset(valueX - textPainterXAxis.width / 2, + height + textPainterXAxis.height / 1.5), ); } @@ -1249,7 +1357,9 @@ class _BezierChartPainter extends CustomPainter { double offsetInfo = 42 + ((_currentCustomValues.length - 1.0) * 10.0); final centerForCircle = Offset(verticalX, height - yValue); - final center = config.verticalIndicatorFixedPosition ? Offset(verticalX, offsetInfo) : centerForCircle; + final center = config.verticalIndicatorFixedPosition + ? Offset(verticalX, offsetInfo) + : centerForCircle; if (config.showVerticalIndicator) { canvas.drawLine( @@ -1272,10 +1382,13 @@ class _BezierChartPainter extends CustomPainter { List textValues = []; List centerCircles = []; - double space = 10 - ((infoHeight / (8.75)) * _currentCustomValues.length); - infoHeight = infoHeight + (_currentCustomValues.length - 1) * (infoHeight / 3); + double space = + 10 - ((infoHeight / (8.75)) * _currentCustomValues.length); + infoHeight = + infoHeight + (_currentCustomValues.length - 1) * (infoHeight / 3); - for (_CustomValue customValue in _currentCustomValues.reversed.toList()) { + for (_CustomValue customValue + in _currentCustomValues.reversed.toList()) { textValues.add( TextSpan( text: config.bubbleIndicatorValueFormat != null @@ -1292,7 +1405,13 @@ class _BezierChartPainter extends CustomPainter { ); centerCircles.add( // Offset(center.dx - infoWidth / 2 + radiusDotIndicatorItems * 1.5, - Offset(center.dx, center.dy - offsetInfo - radiusDotIndicatorItems + space + (_currentCustomValues.length == 1 ? 1 : 0)), + Offset( + center.dx, + center.dy - + offsetInfo - + radiusDotIndicatorItems + + space + + (_currentCustomValues.length == 1 ? 1 : 0)), ); space += 12.5; } @@ -1309,16 +1428,20 @@ class _BezierChartPainter extends CustomPainter { ); textPainter.layout(); - infoWidth = textPainter.width + radiusDotIndicatorItems * 2 + horizontalPadding; + infoWidth = + textPainter.width + radiusDotIndicatorItems * 2 + horizontalPadding; ///Draw Bubble Indicator Info /// Draw shadow bubble info if (animation.isCompleted) { Path path = Path(); - path.moveTo(center.dx - infoWidth / 2 + 4, center.dy - offsetInfo + infoHeight / 1.8); - path.lineTo(center.dx + infoWidth / 2 + 4, center.dy - offsetInfo + infoHeight / 1.8); - path.lineTo(center.dx + infoWidth / 2 + 4, center.dy - offsetInfo - infoHeight / 3); + path.moveTo(center.dx - infoWidth / 2 + 4, + center.dy - offsetInfo + infoHeight / 1.8); + path.lineTo(center.dx + infoWidth / 2 + 4, + center.dy - offsetInfo + infoHeight / 1.8); + path.lineTo(center.dx + infoWidth / 2 + 4, + center.dy - offsetInfo - infoHeight / 3); //path.close(); // canvas.drawShadow(path, Colors.black, 20.0, false); canvas.drawPath(path, paintControlPoints..color = Colors.black12); @@ -1349,9 +1472,16 @@ class _BezierChartPainter extends CustomPainter { Path pathArrow = Path(); - pathArrow.moveTo(center.dx - triangleSize, center.dy - offsetInfo * animation.value + infoHeight / 2.1); - pathArrow.lineTo(center.dx, center.dy - offsetInfo * animation.value + infoHeight / 2.1 + triangleSize * 1.5); - pathArrow.lineTo(center.dx + triangleSize, center.dy - offsetInfo * animation.value + infoHeight / 2.1); + pathArrow.moveTo(center.dx - triangleSize, + center.dy - offsetInfo * animation.value + infoHeight / 2.1); + pathArrow.lineTo( + center.dx, + center.dy - + offsetInfo * animation.value + + infoHeight / 2.1 + + triangleSize * 1.5); + pathArrow.lineTo(center.dx + triangleSize, + center.dy - offsetInfo * animation.value + infoHeight / 2.1); pathArrow.close(); canvas.drawPath( pathArrow, @@ -1373,7 +1503,12 @@ class _BezierChartPainter extends CustomPainter { for (int z = 0; z < _currentCustomValues.length; z++) { _CustomValue customValue = _currentCustomValues[z]; Offset centerIndicator = centerCircles.reversed.toList()[z]; - Offset fixedCenter = Offset(centerIndicator.dx - infoWidth / 2 + radiusDotIndicatorItems + 4, centerIndicator.dy); + Offset fixedCenter = Offset( + centerIndicator.dx - + infoWidth / 2 + + radiusDotIndicatorItems + + 4, + centerIndicator.dy); canvas.drawCircle( fixedCenter, radiusDotIndicatorItems, @@ -1398,8 +1533,10 @@ class _BezierChartPainter extends CustomPainter { if (bubbleLabelValueBuilder != null && scale == BezierChartScale.CUSTOM) { return bubbleLabelValueBuilder(_currentXDataPoint.value); } - if (bubbleLabelDateTimeBuilder != null && scale != BezierChartScale.CUSTOM) { - return bubbleLabelDateTimeBuilder(_currentXDataPoint.xAxis as DateTime, scale); + if (bubbleLabelDateTimeBuilder != null && + scale != BezierChartScale.CUSTOM) { + return bubbleLabelDateTimeBuilder( + _currentXDataPoint.xAxis as DateTime, scale); } if (scale == BezierChartScale.CUSTOM) { return "${formatAsIntOrDouble(_currentXDataPoint.value)}\n"; @@ -1462,7 +1599,8 @@ class _BezierChartPainter extends CustomPainter { } else if (scale == BezierChartScale.MONTHLY) { final dateFormat = intl.DateFormat('MMM'); final dateFormatYear = intl.DateFormat('y'); - final year = dateFormatYear.format(dataPoint.xAxis as DateTime).substring(2); + final year = + dateFormatYear.format(dataPoint.xAxis as DateTime).substring(2); return "${dateFormat.format(dataPoint.xAxis as DateTime)}\n'$year"; } else if (scale == BezierChartScale.YEARLY) { final dateFormat = intl.DateFormat('y'); @@ -1489,11 +1627,15 @@ class _BezierChartPainter extends CustomPainter { //print("p0: $p0, p1: $p1, p2: $p2, p3: $p3 , t: $t"); - final y = pow(1 - t, 3) * y0 + 3 * pow(1 - t, 2) * t * y1 + 3 * (1 - t) * pow(t, 2) * y2 + pow(t, 3) * y3; + final y = pow(1 - t, 3) * y0 + + 3 * pow(1 - t, 2) * t * y1 + + 3 * (1 - t) * pow(t, 2) * y2 + + pow(t, 3) * y3; return y; } - Rect _fromCenter({Offset center, double width, double height}) => Rect.fromLTRB( + Rect _fromCenter({Offset center, double width, double height}) => + Rect.fromLTRB( center.dx - width / 2, center.dy - height / 2, center.dx + width / 2, @@ -1579,7 +1721,12 @@ class _CustomValue { } bool areEqualDates(DateTime dateTime1, DateTime dateTime2) => - dateTime1.year == dateTime2.year && dateTime1.month == dateTime2.month && dateTime1.day == dateTime2.day; + dateTime1.year == dateTime2.year && + dateTime1.month == dateTime2.month && + dateTime1.day == dateTime2.day; bool areEqualDatesIncludingHour(DateTime dateTime1, DateTime dateTime2) => - dateTime1.year == dateTime2.year && dateTime1.month == dateTime2.month && dateTime1.day == dateTime2.day && dateTime1.hour == dateTime2.hour; + dateTime1.year == dateTime2.year && + dateTime1.month == dateTime2.month && + dateTime1.day == dateTime2.day && + dateTime1.hour == dateTime2.hour; From 854c43da42d8dc5c72c4b087bc019a275fcbda37 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 14 Nov 2020 20:41:21 +0100 Subject: [PATCH 5/6] Move the end if no selected value has been defined --- lib/src/bezier_chart_widget.dart | 373 +++++++++++-------------------- 1 file changed, 136 insertions(+), 237 deletions(-) diff --git a/lib/src/bezier_chart_widget.dart b/lib/src/bezier_chart_widget.dart index f76896b..a02df3c 100644 --- a/lib/src/bezier_chart_widget.dart +++ b/lib/src/bezier_chart_widget.dart @@ -12,8 +12,7 @@ import 'my_single_child_scroll_view.dart'; typedef FooterValueBuilder = String Function(double value); typedef ContentValueBuilder = String Function(double value); -typedef FooterDateTimeBuilder = String Function( - DateTime value, BezierChartScale scaleType); +typedef FooterDateTimeBuilder = String Function(DateTime value, BezierChartScale scaleType); class BezierChart extends StatefulWidget { ///Chart configuration @@ -103,46 +102,31 @@ class BezierChart extends StatefulWidget { @required this.series, this.onScaleChanged, }) : assert( - (bezierChartScale == BezierChartScale.CUSTOM && - xAxisCustomValues != null && - series != null) || - bezierChartScale != BezierChartScale.CUSTOM, + (bezierChartScale == BezierChartScale.CUSTOM && xAxisCustomValues != null && series != null) || bezierChartScale != BezierChartScale.CUSTOM, "The xAxisCustomValues and series must not be null", ), assert( - bezierChartScale == BezierChartScale.CUSTOM && - _isSorted(xAxisCustomValues) || - bezierChartScale != BezierChartScale.CUSTOM, + bezierChartScale == BezierChartScale.CUSTOM && _isSorted(xAxisCustomValues) || bezierChartScale != BezierChartScale.CUSTOM, "The xAxisCustomValues must be sorted in increasing way", ), assert( - bezierChartScale == BezierChartScale.CUSTOM && - _compareLengths(xAxisCustomValues.length, series) || + bezierChartScale == BezierChartScale.CUSTOM && _compareLengths(xAxisCustomValues.length, series) || bezierChartScale != BezierChartScale.CUSTOM, "xAxisCustomValues lenght must be equals to series length", ), assert( - (bezierChartScale == BezierChartScale.CUSTOM && - _areAllPositive(xAxisCustomValues) && - _checkCustomValues(series)) || + (bezierChartScale == BezierChartScale.CUSTOM && _areAllPositive(xAxisCustomValues) && _checkCustomValues(series)) || bezierChartScale != BezierChartScale.CUSTOM, "xAxisCustomValues and series must be positives", ), assert( - (((bezierChartScale != BezierChartScale.CUSTOM) && - fromDate != null && - toDate != null) || - (bezierChartScale == BezierChartScale.CUSTOM && - fromDate == null && - toDate == null)), + (((bezierChartScale != BezierChartScale.CUSTOM) && fromDate != null && toDate != null) || + (bezierChartScale == BezierChartScale.CUSTOM && fromDate == null && toDate == null)), "fromDate and toDate must not be null", ), assert( - (((bezierChartScale != BezierChartScale.CUSTOM) && - toDate.isAfter(fromDate)) || - (bezierChartScale == BezierChartScale.CUSTOM && - fromDate == null && - toDate == null)), + (((bezierChartScale != BezierChartScale.CUSTOM) && toDate.isAfter(fromDate)) || + (bezierChartScale == BezierChartScale.CUSTOM && fromDate == null && toDate == null)), "toDate must be after of fromDate", ), super(key: key); @@ -152,8 +136,7 @@ class BezierChart extends StatefulWidget { } @visibleForTesting -class BezierChartState extends State - with SingleTickerProviderStateMixin { +class BezierChartState extends State with SingleTickerProviderStateMixin { AnimationController _animationController; ScrollController _scrollController; GlobalKey _keyScroll = GlobalKey(); @@ -205,8 +188,7 @@ class BezierChartState extends State ///Refresh the position of the vertical/bubble void _refreshPosition(details) { - if (_animationController.status == AnimationStatus.completed && - _displayIndicator) { + if (_animationController.status == AnimationStatus.completed && _displayIndicator) { return _updatePosition(details.globalPosition); } } @@ -218,9 +200,7 @@ class BezierChartState extends State if (position == null) return; return setState( () { - final fixedPosition = Offset( - position.dx + _scrollController.offset - horizontalPadding, - position.dy); + final fixedPosition = Offset(position.dx + _scrollController.offset - horizontalPadding, position.dy); _verticalIndicatorPosition = fixedPosition; }, ); @@ -280,8 +260,7 @@ class BezierChartState extends State final newValue = line.onMissingValue(newDate); if (!_tempYValues.contains(newValue)) _tempYValues.add(newValue); //if there is no missingvalue specified we should use 0 as minimum value to avoid overlap - } else if (widget.config.startYAxisFromNonZeroValue && - line.onMissingValue == null) { + } else if (widget.config.startYAxisFromNonZeroValue && line.onMissingValue == null) { if (!_tempYValues.contains(0)) _tempYValues.add(0); } } @@ -293,9 +272,7 @@ class BezierChartState extends State _tempYValues = []; final scale = _currentBezierChartScale; if (scale == BezierChartScale.CUSTOM) { - _xAxisDataPoints = widget.xAxisCustomValues - .map((val) => DataPoint(value: val, xAxis: val)) - .toList(); + _xAxisDataPoints = widget.xAxisCustomValues.map((val) => DataPoint(value: val, xAxis: val)).toList(); } else if (scale == BezierChartScale.HOURLY) { final hours = widget.toDate.difference(widget.fromDate).inHours; for (int i = 0; i < hours; i++) { @@ -304,17 +281,14 @@ class BezierChartState extends State hours: (i + 1), ), ); - final newDate = DateTime( - tempDate.year, tempDate.month, tempDate.day, tempDate.hour, 0); + final newDate = DateTime(tempDate.year, tempDate.month, tempDate.day, tempDate.hour, 0); _xAxisDataPoints.add( DataPoint(value: (i * 5).toDouble(), xAxis: newDate), ); _checkMissingValues(newDate); } } else if (scale == BezierChartScale.WEEKLY) { - final days = _convertToDateOnly(widget.toDate) - .difference(_convertToDateOnly(widget.fromDate)) - .inDays; + final days = _convertToDateOnly(widget.toDate).difference(_convertToDateOnly(widget.fromDate)).inDays; for (int i = 0; i <= days; i++) { final newDate = widget.fromDate.add( Duration( @@ -335,9 +309,7 @@ class BezierChartState extends State widget.toDate.year, widget.toDate.month, ); - for (int i = 0; - (startDate.isBefore(endDate) || areEqualDates(startDate, endDate)); - i++) { + for (int i = 0; (startDate.isBefore(endDate) || areEqualDates(startDate, endDate)); i++) { _xAxisDataPoints.add( DataPoint(value: (i * 5).toDouble(), xAxis: startDate), ); @@ -351,9 +323,7 @@ class BezierChartState extends State DateTime endDate = DateTime( widget.toDate.year, ); - for (int i = 0; - (startDate.isBefore(endDate) || areEqualDates(startDate, endDate)); - i++) { + for (int i = 0; (startDate.isBefore(endDate) || areEqualDates(startDate, endDate)); i++) { _xAxisDataPoints.add( DataPoint(value: (i * 5).toDouble(), xAxis: startDate), ); @@ -376,21 +346,17 @@ class BezierChartState extends State double _buildContentWidth(BoxConstraints constraints) { final scale = _currentBezierChartScale; if (scale == BezierChartScale.CUSTOM) { - return widget.config.contentWidth ?? - constraints.maxWidth - 2 * horizontalPadding; + return widget.config.contentWidth ?? constraints.maxWidth - 2 * horizontalPadding; } else { if (scale == BezierChartScale.HOURLY) { horizontalSpacing = constraints.maxWidth / 7; - return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - - horizontalPadding / 2; + return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - horizontalPadding / 2; } else if (scale == BezierChartScale.WEEKLY) { horizontalSpacing = constraints.maxWidth / 7; - return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - - horizontalPadding / 2; + return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - horizontalPadding / 2; } else if (scale == BezierChartScale.MONTHLY) { horizontalSpacing = constraints.maxWidth / 12; - return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - - horizontalPadding / 2; + return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - horizontalPadding / 2; } else if (scale == BezierChartScale.YEARLY) { if (_xAxisDataPoints.length > 12) { horizontalSpacing = constraints.maxWidth / 12; @@ -399,8 +365,7 @@ class BezierChartState extends State } else { horizontalSpacing = constraints.maxWidth / _xAxisDataPoints.length; } - return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - - horizontalPadding; + return _xAxisDataPoints.length * (horizontalSpacing * _currentScale) - horizontalPadding; } return 0.0; } @@ -410,14 +375,12 @@ class BezierChartState extends State _onLayoutDone(_) { _yAxisWidth = _keyLastYAxisItem.currentContext?.size?.width; //Move to selected position - if ((widget.selectedDate != null && - _currentBezierChartScale != BezierChartScale.CUSTOM) || - (widget.selectedValue != null && - _currentBezierChartScale == BezierChartScale.CUSTOM)) { + if ((widget.selectedDate != null && _currentBezierChartScale != BezierChartScale.CUSTOM) || + (widget.selectedValue != null && _currentBezierChartScale == BezierChartScale.CUSTOM)) { int index = -1; + if (_currentBezierChartScale == BezierChartScale.WEEKLY) { - index = _xAxisDataPoints.indexWhere( - (dp) => areEqualDates((dp.xAxis as DateTime), widget.selectedDate)); + index = _xAxisDataPoints.indexWhere((dp) => areEqualDates((dp.xAxis as DateTime), widget.selectedDate)); } else if (_currentBezierChartScale == BezierChartScale.HOURLY) { index = _xAxisDataPoints.indexWhere((dp) => (dp.xAxis as DateTime).year == widget.selectedDate.year && @@ -425,15 +388,12 @@ class BezierChartState extends State (dp.xAxis as DateTime).day == widget.selectedDate.day && (dp.xAxis as DateTime).hour == widget.selectedDate.hour); } else if (_currentBezierChartScale == BezierChartScale.MONTHLY) { - index = _xAxisDataPoints.indexWhere((dp) => - (dp.xAxis as DateTime).year == widget.selectedDate.year && - (dp.xAxis as DateTime).month == widget.selectedDate.month); + index = _xAxisDataPoints + .indexWhere((dp) => (dp.xAxis as DateTime).year == widget.selectedDate.year && (dp.xAxis as DateTime).month == widget.selectedDate.month); } else if (_currentBezierChartScale == BezierChartScale.YEARLY) { - index = _xAxisDataPoints.indexWhere( - (dp) => (dp.xAxis as DateTime).year == widget.selectedDate.year); + index = _xAxisDataPoints.indexWhere((dp) => (dp.xAxis as DateTime).year == widget.selectedDate.year); } else if (_currentBezierChartScale == BezierChartScale.CUSTOM) { - index = _xAxisDataPoints - .indexWhere((dp) => (dp.xAxis as double) == widget.selectedValue); + index = _xAxisDataPoints.indexWhere((dp) => (dp.xAxis as double) == widget.selectedValue); } //If it's a valid index then scroll to the date selected based on the current position @@ -441,8 +401,7 @@ class BezierChartState extends State Offset fixedPosition; if (_currentBezierChartScale == BezierChartScale.CUSTOM) { final space = (_contentWidth / _xAxisDataPoints.length); - fixedPosition = - Offset(isOnlyOneAxis ? 0.0 : (index * space) + space / 2, 0.0); + fixedPosition = Offset(isOnlyOneAxis ? 0.0 : (index * space) + space / 2, 0.0); _scrollController.jumpTo((index * space)); setState( () { @@ -457,17 +416,50 @@ class BezierChartState extends State }, ); } else { - final jumpToX = (index * horizontalSpacing) - - horizontalPadding / 2 - - _keyScroll.currentContext.size.width / 2; + final jumpToX = (index * horizontalSpacing) - horizontalPadding / 2 - _keyScroll.currentContext.size.width / 2; _scrollController.jumpTo(jumpToX); - fixedPosition = Offset( - isOnlyOneAxis - ? 0.0 - : (index * horizontalSpacing + 2 * horizontalPadding) - - _scrollController.offset, - 0.0); + fixedPosition = Offset(isOnlyOneAxis ? 0.0 : (index * horizontalSpacing + 2 * horizontalPadding) - _scrollController.offset, 0.0); + _verticalIndicatorPosition = fixedPosition; + _onDisplayIndicator( + LongPressMoveUpdateDetails( + globalPosition: fixedPosition, + offsetFromOrigin: fixedPosition, + ), + updatePosition: true, + ); + } + } + } else { + //Mi muovo all'ultimo item + int index = -1; + + index = _xAxisDataPoints.length - 1; + + //If it's a valid index then scroll to the date selected based on the current position + if (index >= 0) { + Offset fixedPosition; + if (_currentBezierChartScale == BezierChartScale.CUSTOM) { + final space = (_contentWidth / _xAxisDataPoints.length); + fixedPosition = Offset(isOnlyOneAxis ? 0.0 : (index * space) + space / 2, 0.0); + _scrollController.jumpTo((index * space)); + setState( + () { + _verticalIndicatorPosition = fixedPosition; + _onDisplayIndicator( + LongPressMoveUpdateDetails( + globalPosition: fixedPosition, + offsetFromOrigin: fixedPosition, + ), + updatePosition: false, + ); + }, + ); + } else { + final jumpToX = (index * horizontalSpacing) - horizontalPadding / 2 - _keyScroll.currentContext.size.width / 2; + _scrollController.jumpTo(jumpToX); + + fixedPosition = Offset(isOnlyOneAxis ? 0.0 : (index * horizontalSpacing + 2 * horizontalPadding) - _scrollController.offset, 0.0); _verticalIndicatorPosition = fixedPosition; _onDisplayIndicator( LongPressMoveUpdateDetails( @@ -478,6 +470,7 @@ class BezierChartState extends State } } } + _checkIfNeedScroll(); if (_isScrollable) { setState(() {}); @@ -485,8 +478,7 @@ class BezierChartState extends State } _checkIfNeedScroll() { - if (_contentWidth > - _keyScroll.currentContext.size.width - horizontalPadding * 2) { + if (_contentWidth > _keyScroll.currentContext.size.width - horizontalPadding * 2) { _isScrollable = true; } } @@ -506,13 +498,11 @@ class BezierChartState extends State for (DataPoint dataPoint in line.data) { String key; if (_currentBezierChartScale == BezierChartScale.MONTHLY) { - key = - "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')}"; + key = "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')}"; } else if (_currentBezierChartScale == BezierChartScale.YEARLY) { key = "${dataPoint.xAxis.year}"; } else if (_currentBezierChartScale == BezierChartScale.WEEKLY) { - key = - "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')},${dataPoint.xAxis.day.toString().padLeft(2, '0')}"; + key = "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')},${dataPoint.xAxis.day.toString().padLeft(2, '0')}"; } else { key = "${dataPoint.xAxis.year},${dataPoint.xAxis.month.toString().padLeft(2, '0')},${dataPoint.xAxis.day.toString().padLeft(2, '0')},${dataPoint.xAxis.hour.toString().padLeft(2, '0')}"; @@ -527,29 +517,17 @@ class BezierChartState extends State Map valueMap = Map(); if (widget.bezierChartAggregation == BezierChartAggregation.SUM) { - valueMap = tmpMap.map((k, v) => MapEntry( - k, - v.reduce( - (c1, c2) => double.parse((c1 + c2).toStringAsFixed(2))))); - } else if (widget.bezierChartAggregation == - BezierChartAggregation.FIRST) { - valueMap = - tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1))); - } else if (widget.bezierChartAggregation == - BezierChartAggregation.AVERAGE) { - valueMap = tmpMap.map( - (k, v) => MapEntry(k, v.reduce((c1, c2) => c1 + c2) / v.length)); - } else if (widget.bezierChartAggregation == - BezierChartAggregation.COUNT) { + valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => double.parse((c1 + c2).toStringAsFixed(2))))); + } else if (widget.bezierChartAggregation == BezierChartAggregation.FIRST) { + valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1))); + } else if (widget.bezierChartAggregation == BezierChartAggregation.AVERAGE) { + valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1 + c2) / v.length)); + } else if (widget.bezierChartAggregation == BezierChartAggregation.COUNT) { valueMap = tmpMap.map((k, v) => MapEntry(k, v.length.toDouble())); - } else if (widget.bezierChartAggregation == - BezierChartAggregation.MAX) { - valueMap = tmpMap.map( - (k, v) => MapEntry(k, v.reduce((c1, c2) => c1 > c2 ? c1 : c2))); - } else if (widget.bezierChartAggregation == - BezierChartAggregation.MIN) { - valueMap = tmpMap.map( - (k, v) => MapEntry(k, v.reduce((c1, c2) => c1 < c2 ? c1 : c2))); + } else if (widget.bezierChartAggregation == BezierChartAggregation.MAX) { + valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1 > c2 ? c1 : c2))); + } else if (widget.bezierChartAggregation == BezierChartAggregation.MIN) { + valueMap = tmpMap.map((k, v) => MapEntry(k, v.reduce((c1, c2) => c1 < c2 ? c1 : c2))); } List> newDataPoints = []; @@ -712,8 +690,7 @@ class BezierChartState extends State } void _notifyScaleChanged(BezierChartScale lastScale) { - if (widget.onScaleChanged != null && - lastScale != _currentBezierChartScale) { + if (widget.onScaleChanged != null && lastScale != _currentBezierChartScale) { widget.onScaleChanged(_currentBezierChartScale); } } @@ -796,9 +773,7 @@ class BezierChartState extends State //https://github.com/flutter/flutter/issues/13102 return Container( decoration: BoxDecoration( - color: widget.config.backgroundGradient != null - ? null - : widget.config.backgroundColor, + color: widget.config.backgroundGradient != null ? null : widget.config.backgroundColor, gradient: widget.config.backgroundGradient, ), alignment: Alignment.center, @@ -816,9 +791,7 @@ class BezierChartState extends State } }, child: GestureDetector( - onLongPressStart: widget.config.updatePositionOnTap - ? null - : (isPinchZoomActive ? null : _onDisplayIndicator), + onLongPressStart: widget.config.updatePositionOnTap ? null : (isPinchZoomActive ? null : _onDisplayIndicator), onLongPressMoveUpdate: isPinchZoomActive ? null : _refreshPosition, onScaleStart: (_) { _previousScale = _currentScale; @@ -829,12 +802,8 @@ class BezierChartState extends State !_displayIndicator ? (details) => _onPinchZoom(_previousScale * details.scale) : null, - onTap: widget.config.updatePositionOnTap - ? null - : (isPinchZoomActive ? null : _onHideIndicator), - onTapDown: widget.config.updatePositionOnTap - ? (isPinchZoomActive ? null : _refreshPosition) - : null, + onTap: widget.config.updatePositionOnTap ? null : (isPinchZoomActive ? null : _onHideIndicator), + onTapDown: widget.config.updatePositionOnTap ? (isPinchZoomActive ? null : _refreshPosition) : null, child: LayoutBuilder( builder: (context, constraints) { _contentWidth = _buildContentWidth(constraints); @@ -843,9 +812,7 @@ class BezierChartState extends State items.add( MySingleChildScrollView( controller: _scrollController, - physics: isPinchZoomActive || !_isScrollable - ? NeverScrollableScrollPhysics() - : widget.config.physics, + physics: isPinchZoomActive || !_isScrollable ? NeverScrollableScrollPhysics() : widget.config.physics, key: _keyScroll, scrollDirection: Axis.horizontal, padding: EdgeInsets.symmetric(horizontal: horizontalPadding), @@ -876,14 +843,11 @@ class BezierChartState extends State xAxisDataPoints: _xAxisDataPoints, onDataPointSnap: _onDataPointSnap, maxWidth: MediaQuery.of(context).size.width, - scrollOffset: _scrollController.hasClients - ? _scrollController.offset - : 0.0, + scrollOffset: _scrollController.hasClients ? _scrollController.offset : 0.0, footerValueBuilder: widget.footerValueBuilder, bubbleLabelValueBuilder: widget.bubbleLabelValueBuilder, footerDateTimeBuilder: widget.footerDateTimeBuilder, - bubbleLabelDateTimeBuilder: - widget.bubbleLabelDateTimeBuilder, + bubbleLabelDateTimeBuilder: widget.bubbleLabelDateTimeBuilder, bubbleContentBuilder: widget.bubbleContentBuilder, onValueSelected: (val) { if (widget.onValueSelected != null) { @@ -925,44 +889,27 @@ class BezierChartState extends State bottom: 0, child: Container( width: _yAxisWidth + 10, - decoration: widget.config.backgroundGradient != null - ? BoxDecoration( - gradient: widget.config.backgroundGradient) - : null, - color: widget.config.backgroundGradient != null - ? null - : widget.config.backgroundColor, + decoration: widget.config.backgroundGradient != null ? BoxDecoration(gradient: widget.config.backgroundGradient) : null, + color: widget.config.backgroundGradient != null ? null : widget.config.backgroundColor, ), )); } final fontSize = widget.config.yAxisTextStyle?.fontSize ?? 8.0; - final maxValue = _yValues.last - - (widget.config.startYAxisFromNonZeroValue - ? _yValues.first - : 0.0); - final steps = widget.config.stepsYAxis != null && - widget.config.stepsYAxis > 0 - ? widget.config.stepsYAxis - : null; + final maxValue = _yValues.last - (widget.config.startYAxisFromNonZeroValue ? _yValues.first : 0.0); + final steps = widget.config.stepsYAxis != null && widget.config.stepsYAxis > 0 ? widget.config.stepsYAxis : null; _addYItem(double value, {Key key}) { items.add( Positioned( - bottom: _getRealValue( - value - - (widget.config.startYAxisFromNonZeroValue - ? _yValues.first - : 0.0), - maxHeight - widget.config.footerHeight, - maxValue) + + bottom: _getRealValue(value - (widget.config.startYAxisFromNonZeroValue ? _yValues.first : 0.0), + maxHeight - widget.config.footerHeight, maxValue) + widget.config.footerHeight + fontSize / 2, left: 10.0, child: Text( formatAsIntOrDouble(value), key: key, - style: widget.config.yAxisTextStyle ?? - TextStyle(color: Colors.white, fontSize: fontSize), + style: widget.config.yAxisTextStyle ?? TextStyle(color: Colors.white, fontSize: fontSize), ), ), ); @@ -970,21 +917,16 @@ class BezierChartState extends State if (steps != null) { final max = _yValues.last; - final min = widget.config.startYAxisFromNonZeroValue - ? _yValues.first.ceil() - : 0; + final min = widget.config.startYAxisFromNonZeroValue ? _yValues.first.ceil() : 0; for (int i = min; i < max + steps; i++) { if (i % steps == 0) { - bool isLast = - (i + steps) > max && (i + steps) >= (max + steps); - _addYItem(i.toDouble(), - key: isLast ? _keyLastYAxisItem : null); + bool isLast = (i + steps) > max && (i + steps) >= (max + steps); + _addYItem(i.toDouble(), key: isLast ? _keyLastYAxisItem : null); } } } else { for (double val in _yValues) { - _addYItem(val, - key: val == _yValues.last ? _keyLastYAxisItem : null); + _addYItem(val, key: val == _yValues.last ? _keyLastYAxisItem : null); } } } @@ -1000,8 +942,7 @@ class BezierChartState extends State } ///return the real value of canvas -_getRealValue(double value, double maxConstraint, double maxValue) => - maxConstraint * value / (maxValue == 0 ? 1 : maxValue); +_getRealValue(double value, double maxConstraint, double maxValue) => maxConstraint * value / (maxValue == 0 ? 1 : maxValue); //BezierChart class _BezierChartPainter extends CustomPainter { @@ -1185,8 +1126,7 @@ class _BezierChartPainter extends CustomPainter { if (line.onMissingValue != null) { isMissingValue = true; value = line.onMissingValue(xAxisDataPoints[i].xAxis as DateTime); - } else if (config.displayPreviousDataPointWhenNoValue && - previousValue != null) { + } else if (config.displayPreviousDataPointWhenNoValue && previousValue != null) { isMissingValue = true; value = previousValue; } @@ -1203,8 +1143,7 @@ class _BezierChartPainter extends CustomPainter { ); if (config.displayLinesXAxis && series.length == 1) { - canvas.drawLine( - Offset(valueX, height), Offset(valueX, valueY), paintXLines); + canvas.drawLine(Offset(valueX, height), Offset(valueX, valueY), paintXLines); } if (lastPoint == null) { @@ -1213,8 +1152,7 @@ class _BezierChartPainter extends CustomPainter { } final double controlPointX = lastPoint.x + (valueX - lastPoint.x) / 2; - path.cubicTo( - controlPointX, lastPoint.y, controlPointX, valueY, valueX, valueY); + path.cubicTo(controlPointX, lastPoint.y, controlPointX, valueY, valueX, valueY); if (isMissingValue) { if (config.displayDataPointWhenNoValue) { dataPoints.add(Offset(valueX, valueY)); @@ -1223,9 +1161,7 @@ class _BezierChartPainter extends CustomPainter { dataPoints.add(Offset(valueX, valueY)); } - if (verticalIndicatorPosition != null && - verticalX >= lastPoint.x && - verticalX <= valueX) { + if (verticalIndicatorPosition != null && verticalX >= lastPoint.x && verticalX <= valueX) { //points to draw the info p0 = Offset(lastPoint.x, height - lastPoint.y); p1 = Offset(controlPointX, height - lastPoint.y); @@ -1253,8 +1189,7 @@ class _BezierChartPainter extends CustomPainter { } //if vertical indicator is in range then display the bubble info - if (verticalX >= valueX - (valueX - lastX) / 2 && - verticalX <= valueX + (nextX - valueX) / 2) { + if (verticalX >= valueX - (valueX - lastX) / 2 && verticalX <= valueX + (nextX - valueX) / 2) { _currentXDataPoint = xAxisDataPoints[i]; if (_currentCustomValues.length < series.length) { bool isDouble = (xAxisDataPoints[i].xAxis is double); @@ -1273,7 +1208,6 @@ class _BezierChartPainter extends CustomPainter { _CustomValue( value: bubbleContentBuilder != null ? bubbleContentBuilder(axisY) : "${formatAsIntOrDouble(axisY)}", label: line.label, - color: line.lineColor, ), ); } @@ -1290,8 +1224,7 @@ class _BezierChartPainter extends CustomPainter { textPainterXAxis.layout(); textPainterXAxis.paint( canvas, - Offset(valueX - textPainterXAxis.width / 2, - height + textPainterXAxis.height / 1.5), + Offset(valueX - textPainterXAxis.width / 2, height + textPainterXAxis.height / 1.5), ); } @@ -1357,9 +1290,7 @@ class _BezierChartPainter extends CustomPainter { double offsetInfo = 42 + ((_currentCustomValues.length - 1.0) * 10.0); final centerForCircle = Offset(verticalX, height - yValue); - final center = config.verticalIndicatorFixedPosition - ? Offset(verticalX, offsetInfo) - : centerForCircle; + final center = config.verticalIndicatorFixedPosition ? Offset(verticalX, offsetInfo) : centerForCircle; if (config.showVerticalIndicator) { canvas.drawLine( @@ -1382,13 +1313,10 @@ class _BezierChartPainter extends CustomPainter { List textValues = []; List centerCircles = []; - double space = - 10 - ((infoHeight / (8.75)) * _currentCustomValues.length); - infoHeight = - infoHeight + (_currentCustomValues.length - 1) * (infoHeight / 3); + double space = 10 - ((infoHeight / (8.75)) * _currentCustomValues.length); + infoHeight = infoHeight + (_currentCustomValues.length - 1) * (infoHeight / 3); - for (_CustomValue customValue - in _currentCustomValues.reversed.toList()) { + for (_CustomValue customValue in _currentCustomValues.reversed.toList()) { textValues.add( TextSpan( text: config.bubbleIndicatorValueFormat != null @@ -1405,13 +1333,7 @@ class _BezierChartPainter extends CustomPainter { ); centerCircles.add( // Offset(center.dx - infoWidth / 2 + radiusDotIndicatorItems * 1.5, - Offset( - center.dx, - center.dy - - offsetInfo - - radiusDotIndicatorItems + - space + - (_currentCustomValues.length == 1 ? 1 : 0)), + Offset(center.dx, center.dy - offsetInfo - radiusDotIndicatorItems + space + (_currentCustomValues.length == 1 ? 1 : 0)), ); space += 12.5; } @@ -1428,20 +1350,16 @@ class _BezierChartPainter extends CustomPainter { ); textPainter.layout(); - infoWidth = - textPainter.width + radiusDotIndicatorItems * 2 + horizontalPadding; + infoWidth = textPainter.width + radiusDotIndicatorItems * 2 + horizontalPadding; ///Draw Bubble Indicator Info /// Draw shadow bubble info if (animation.isCompleted) { Path path = Path(); - path.moveTo(center.dx - infoWidth / 2 + 4, - center.dy - offsetInfo + infoHeight / 1.8); - path.lineTo(center.dx + infoWidth / 2 + 4, - center.dy - offsetInfo + infoHeight / 1.8); - path.lineTo(center.dx + infoWidth / 2 + 4, - center.dy - offsetInfo - infoHeight / 3); + path.moveTo(center.dx - infoWidth / 2 + 4, center.dy - offsetInfo + infoHeight / 1.8); + path.lineTo(center.dx + infoWidth / 2 + 4, center.dy - offsetInfo + infoHeight / 1.8); + path.lineTo(center.dx + infoWidth / 2 + 4, center.dy - offsetInfo - infoHeight / 3); //path.close(); // canvas.drawShadow(path, Colors.black, 20.0, false); canvas.drawPath(path, paintControlPoints..color = Colors.black12); @@ -1472,16 +1390,9 @@ class _BezierChartPainter extends CustomPainter { Path pathArrow = Path(); - pathArrow.moveTo(center.dx - triangleSize, - center.dy - offsetInfo * animation.value + infoHeight / 2.1); - pathArrow.lineTo( - center.dx, - center.dy - - offsetInfo * animation.value + - infoHeight / 2.1 + - triangleSize * 1.5); - pathArrow.lineTo(center.dx + triangleSize, - center.dy - offsetInfo * animation.value + infoHeight / 2.1); + pathArrow.moveTo(center.dx - triangleSize, center.dy - offsetInfo * animation.value + infoHeight / 2.1); + pathArrow.lineTo(center.dx, center.dy - offsetInfo * animation.value + infoHeight / 2.1 + triangleSize * 1.5); + pathArrow.lineTo(center.dx + triangleSize, center.dy - offsetInfo * animation.value + infoHeight / 2.1); pathArrow.close(); canvas.drawPath( pathArrow, @@ -1500,7 +1411,7 @@ class _BezierChartPainter extends CustomPainter { ); //draw circle indicators and text - for (int z = 0; z < _currentCustomValues.length; z++) { + /*for (int z = 0; z < _currentCustomValues.length; z++) { _CustomValue customValue = _currentCustomValues[z]; Offset centerIndicator = centerCircles.reversed.toList()[z]; Offset fixedCenter = Offset( @@ -1509,7 +1420,7 @@ class _BezierChartPainter extends CustomPainter { radiusDotIndicatorItems + 4, centerIndicator.dy); - canvas.drawCircle( + canvas.drawCircle( fixedCenter, radiusDotIndicatorItems, Paint() @@ -1522,7 +1433,7 @@ class _BezierChartPainter extends CustomPainter { ..color = Colors.black ..strokeWidth = 0.5 ..style = PaintingStyle.stroke); - } + } */ } } } @@ -1533,10 +1444,8 @@ class _BezierChartPainter extends CustomPainter { if (bubbleLabelValueBuilder != null && scale == BezierChartScale.CUSTOM) { return bubbleLabelValueBuilder(_currentXDataPoint.value); } - if (bubbleLabelDateTimeBuilder != null && - scale != BezierChartScale.CUSTOM) { - return bubbleLabelDateTimeBuilder( - _currentXDataPoint.xAxis as DateTime, scale); + if (bubbleLabelDateTimeBuilder != null && scale != BezierChartScale.CUSTOM) { + return bubbleLabelDateTimeBuilder(_currentXDataPoint.xAxis as DateTime, scale); } if (scale == BezierChartScale.CUSTOM) { return "${formatAsIntOrDouble(_currentXDataPoint.value)}\n"; @@ -1599,8 +1508,7 @@ class _BezierChartPainter extends CustomPainter { } else if (scale == BezierChartScale.MONTHLY) { final dateFormat = intl.DateFormat('MMM'); final dateFormatYear = intl.DateFormat('y'); - final year = - dateFormatYear.format(dataPoint.xAxis as DateTime).substring(2); + final year = dateFormatYear.format(dataPoint.xAxis as DateTime).substring(2); return "${dateFormat.format(dataPoint.xAxis as DateTime)}\n'$year"; } else if (scale == BezierChartScale.YEARLY) { final dateFormat = intl.DateFormat('y'); @@ -1627,15 +1535,11 @@ class _BezierChartPainter extends CustomPainter { //print("p0: $p0, p1: $p1, p2: $p2, p3: $p3 , t: $t"); - final y = pow(1 - t, 3) * y0 + - 3 * pow(1 - t, 2) * t * y1 + - 3 * (1 - t) * pow(t, 2) * y2 + - pow(t, 3) * y3; + final y = pow(1 - t, 3) * y0 + 3 * pow(1 - t, 2) * t * y1 + 3 * (1 - t) * pow(t, 2) * y2 + pow(t, 3) * y3; return y; } - Rect _fromCenter({Offset center, double width, double height}) => - Rect.fromLTRB( + Rect _fromCenter({Offset center, double width, double height}) => Rect.fromLTRB( center.dx - width / 2, center.dy - height / 2, center.dx + width / 2, @@ -1721,12 +1625,7 @@ class _CustomValue { } bool areEqualDates(DateTime dateTime1, DateTime dateTime2) => - dateTime1.year == dateTime2.year && - dateTime1.month == dateTime2.month && - dateTime1.day == dateTime2.day; + dateTime1.year == dateTime2.year && dateTime1.month == dateTime2.month && dateTime1.day == dateTime2.day; bool areEqualDatesIncludingHour(DateTime dateTime1, DateTime dateTime2) => - dateTime1.year == dateTime2.year && - dateTime1.month == dateTime2.month && - dateTime1.day == dateTime2.day && - dateTime1.hour == dateTime2.hour; + dateTime1.year == dateTime2.year && dateTime1.month == dateTime2.month && dateTime1.day == dateTime2.day && dateTime1.hour == dateTime2.hour; From 80014424acbf80cda3ebaf77736882bdd2bfb8d2 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 14 Nov 2020 21:10:19 +0100 Subject: [PATCH 6/6] Fix max height graph --- lib/src/bezier_chart_widget.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/src/bezier_chart_widget.dart b/lib/src/bezier_chart_widget.dart index ba347fd..7d78819 100644 --- a/lib/src/bezier_chart_widget.dart +++ b/lib/src/bezier_chart_widget.dart @@ -1077,6 +1077,11 @@ class _BezierChartPainter extends CustomPainter { void paint(Canvas canvas, Size size) { final height = size.height - config.footerHeight; Paint paintVerticalIndicator = Paint(); + + double infoWidth = 0; //base value, modified based on the label text + double infoHeight = 40; + + try { paintVerticalIndicator ..color = config.verticalIndicatorColor @@ -1189,7 +1194,7 @@ class _BezierChartPainter extends CustomPainter { final double valueY = height - _getRealValue( axisY - (config.startYAxisFromNonZeroValue ? minYValue : 0.0), - height, + height - infoHeight, _maxValueY, ); @@ -1340,8 +1345,7 @@ class _BezierChartPainter extends CustomPainter { (verticalX - p0.dx) / (p3.dx - p0.dx), ); - double infoWidth = 0; //base value, modified based on the label text - double infoHeight = 40; + //bubble indicator padding final horizontalPadding = 28.0;