Skip to content

Commit

Permalink
Set start/end point of TouchLine
Browse files Browse the repository at this point in the history
  • Loading branch information
liangxianzhe committed Mar 15, 2021
1 parent 64562c0 commit d2b7d6f
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 30 deletions.
12 changes: 12 additions & 0 deletions example/lib/line_chart/line_chart_page3.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';

import 'samples/line_chart_sample6.dart';
import 'samples/line_chart_sample9.dart';

class LineChartPage3 extends StatelessWidget {
@override
Expand All @@ -20,6 +21,17 @@ class LineChartPage3 extends StatelessWidget {
height: 52,
),
LineChartSample6(),
const SizedBox(
height: 52,
),
const Text(
'LineChart (positive and negative values)',
style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold, color: Colors.black),
),
const SizedBox(
height: 52,
),
LineChartSample9(),
],
),
),
Expand Down
99 changes: 99 additions & 0 deletions example/lib/line_chart/samples/line_chart_sample9.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'dart:math';

// ignore: must_be_immutable
class LineChartSample9 extends StatelessWidget {
final spots = List.generate(101, (i) => (i - 50) / 10)
.map((x) => FlSpot(x, sin(x)))
.toList();

LineChartSample9() {}

@override
Widget build(BuildContext context) {
return Container(
child: Padding(
padding: const EdgeInsets.only(right: 22.0, bottom: 20),
child: SizedBox(
width: 400,
height: 400,
child: LineChart(
LineChartData(
lineTouchData: LineTouchData(
touchTooltipData: LineTouchTooltipData(
maxContentWidth: 100,
tooltipBgColor: Colors.orange,
getTooltipItems: (touchedSpots) {
return touchedSpots.map((LineBarSpot touchedSpot) {
final textStyle = TextStyle(
color: touchedSpot.bar.colors[0],
fontWeight: FontWeight.bold,
fontSize: 14,
);
return LineTooltipItem(
'${touchedSpot.x}, ${touchedSpot.y.toStringAsFixed(2)}',
textStyle);
}).toList();
}),
handleBuiltInTouches: true,
getTouchLineStart: (data, index) => 0,
),
lineBarsData: [
LineChartBarData(
colors: [
Colors.black,
],
spots: spots,
isCurved: true,
isStrokeCapRound: true,
barWidth: 3,
belowBarData: BarAreaData(
show: false,
),
dotData: FlDotData(show: false),
),
],
minY: -1.5,
maxY: 1.5,
titlesData: FlTitlesData(
leftTitles: SideTitles(
showTitles: true,
getTextStyles: (value) => const TextStyle(
color: Colors.blueGrey,
fontWeight: FontWeight.bold,
fontSize: 18),
margin: 16,
),
rightTitles: SideTitles(showTitles: false),
bottomTitles: SideTitles(
showTitles: true,
getTextStyles: (value) => const TextStyle(
color: Colors.blueGrey,
fontWeight: FontWeight.bold,
fontSize: 18),
margin: 16,
),
topTitles: SideTitles(showTitles: false),
),
gridData: FlGridData(
show: true,
drawHorizontalLine: true,
drawVerticalLine: true,
horizontalInterval: 1.5,
verticalInterval: 5,
checkToShowHorizontalLine: (value) {
return value.toInt() == 0;
},
checkToShowVerticalLine: (value) {
return value.toInt() == 0;
},
),
borderData: FlBorderData(show: false),
),
),
),
),
);
}
}
57 changes: 43 additions & 14 deletions lib/src/chart/line_chart/line_chart_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -781,10 +781,10 @@ class FlDotData with EquatableMixin {

/// This class contains the interface that all DotPainters should conform to.
abstract class FlDotPainter with EquatableMixin {
/// This method should be overriden to draw the dot shape.
/// This method should be overridden to draw the dot shape.
void draw(Canvas canvas, FlSpot spot, Offset offsetInCanvas);

/// This method should be overriden to return the size of the shape.
/// This method should be overridden to return the size of the shape.
Size getSize(FlSpot spot);
}

Expand Down Expand Up @@ -1304,9 +1304,17 @@ class LineTouchData extends FlTouchData with EquatableMixin {
/// [LineTouchResponse] shows a tooltip popup above the touched spot.
final bool handleBuiltInTouches;

/// Sets the indicator line full height, from bottom to top of the chart,
/// and goes through the targeted spot.
final bool fullHeightTouchLine;
/// The starting point on y axis of the touch line. By default, line starts on the bottom of
/// the chart.
final GetTouchLineY getTouchLineStart;

/// The end point on y axis of the touch line. By default, line ends at the touched point.
/// Though the line's length will be reduce to avoid overlap with the dot if
/// [touchLineEndAtDot] is true.
final GetTouchLineY getTouchLineEnd;

/// Sets to avoid the touch line to overlap with the dot. Default is true.
final bool touchLineEndAtDot;

/// Informs the touchResponses
final Function(LineTouchResponse)? touchCallback;
Expand All @@ -1316,10 +1324,8 @@ class LineTouchData extends FlTouchData with EquatableMixin {
/// touch occurs (or you can show it manually using, [LineChartData.showingTooltipIndicators])
/// and also it shows an indicator (contains a thicker line and larger dot on the targeted spot),
/// You can define how this indicator looks like through [getTouchedSpotIndicator] callback,
/// You can customize this tooltip using [touchTooltipData], indicator lines starts from bottom
/// of the chart to the targeted spot, you can change this behavior by [fullHeightTouchLine],
/// if [fullHeightTouchLine] sets true, the line goes from bottom to top of the chart,
/// and goes through the targeted spot.
/// You can customize this tooltip using [touchTooltipData], indicator lines starts from position
/// controlled by [getTouchLineStart] and ends at position controlled by [getTouchLineEnd].
/// If you need to have a distance threshold for handling touches, use [touchSpotThreshold].
///
/// You can listen to touch events using [touchCallback],
Expand All @@ -1330,14 +1336,18 @@ class LineTouchData extends FlTouchData with EquatableMixin {
LineTouchTooltipData? touchTooltipData,
GetTouchedSpotIndicator? getTouchedSpotIndicator,
double? touchSpotThreshold,
bool? fullHeightTouchLine,
bool? handleBuiltInTouches,
GetTouchLineY? getTouchLineStart,
GetTouchLineY? getTouchLineEnd,
bool? touchLineEndAtDot,
Function(LineTouchResponse)? touchCallback,
}) : touchTooltipData = touchTooltipData ?? LineTouchTooltipData(),
getTouchedSpotIndicator = getTouchedSpotIndicator ?? defaultTouchedIndicators,
touchSpotThreshold = touchSpotThreshold ?? 10,
fullHeightTouchLine = fullHeightTouchLine ?? false,
handleBuiltInTouches = handleBuiltInTouches ?? true,
getTouchLineStart = getTouchLineStart ?? defaultGetTouchLineStart,
getTouchLineEnd = getTouchLineEnd ?? defaultGetTouchLineEnd,
touchLineEndAtDot = touchLineEndAtDot ?? true,
touchCallback = touchCallback,
super(enabled ?? true);

Expand All @@ -1348,7 +1358,9 @@ class LineTouchData extends FlTouchData with EquatableMixin {
LineTouchTooltipData? touchTooltipData,
GetTouchedSpotIndicator? getTouchedSpotIndicator,
double? touchSpotThreshold,
bool? fullHeightTouchLine,
GetTouchLineY? getTouchLineStart,
GetTouchLineY? getTouchLineEnd,
bool? touchLineEndAtDot,
bool? handleBuiltInTouches,
Function(LineTouchResponse)? touchCallback,
}) {
Expand All @@ -1357,7 +1369,9 @@ class LineTouchData extends FlTouchData with EquatableMixin {
touchTooltipData: touchTooltipData ?? this.touchTooltipData,
getTouchedSpotIndicator: getTouchedSpotIndicator ?? this.getTouchedSpotIndicator,
touchSpotThreshold: touchSpotThreshold ?? this.touchSpotThreshold,
fullHeightTouchLine: fullHeightTouchLine ?? this.fullHeightTouchLine,
getTouchLineStart: getTouchLineStart ?? this.getTouchLineStart,
getTouchLineEnd: getTouchLineEnd ?? this.getTouchLineEnd,
touchLineEndAtDot: touchLineEndAtDot ?? this.touchLineEndAtDot,
handleBuiltInTouches: handleBuiltInTouches ?? this.handleBuiltInTouches,
touchCallback: touchCallback ?? this.touchCallback,
);
Expand All @@ -1370,7 +1384,9 @@ class LineTouchData extends FlTouchData with EquatableMixin {
getTouchedSpotIndicator,
touchSpotThreshold,
handleBuiltInTouches,
fullHeightTouchLine,
getTouchLineStart,
getTouchLineEnd,
touchLineEndAtDot,
touchCallback,
enabled,
];
Expand All @@ -1385,6 +1401,9 @@ class LineTouchData extends FlTouchData with EquatableMixin {
typedef GetTouchedSpotIndicator = List<TouchedSpotIndicatorData?> Function(
LineChartBarData barData, List<int> spotIndexes);

/// Used for determine the touch indicator line's starting/end point.
typedef GetTouchLineY = double Function(LineChartBarData barData, int spotIndex);

/// Default presentation of touched indicators.
List<TouchedSpotIndicatorData> defaultTouchedIndicators(
LineChartBarData barData, List<int> indicators) {
Expand All @@ -1410,6 +1429,16 @@ List<TouchedSpotIndicatorData> defaultTouchedIndicators(
}).toList();
}

/// By default line starts from the bottom of the chart.
double defaultGetTouchLineStart(LineChartBarData barData, int spotIndex) {
return -double.infinity;
}

/// By default line ends at the touched point.
double defaultGetTouchLineEnd(LineChartBarData barData, int spotIndex) {
return barData.spots[spotIndex].y;
}

/// Holds representation data for showing tooltip popup on top of spots.
class LineTouchTooltipData with EquatableMixin {
/// The tooltip background color.
Expand Down
22 changes: 15 additions & 7 deletions lib/src/chart/line_chart/line_chart_painter.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:math';
import 'dart:ui' as ui;
import 'dart:ui';

Expand Down Expand Up @@ -297,19 +298,26 @@ class LineChartPainter extends AxisChartPainter<LineChartData>
}

/// For drawing the indicator line
final bottom = Offset(touchedSpot.dx, getTopOffsetDrawSize() + chartViewSize.height);
final top = Offset(getPixelX(spot.x, chartViewSize), getTopOffsetDrawSize());

/// Draw to top or to the touchedSpot
final lineEnd =
data.lineTouchData.fullHeightTouchLine ? top : touchedSpot + Offset(0, dotHeight / 2);
final lineStartY =
min(data.maxY, max(data.minY, data.lineTouchData.getTouchLineStart(barData, index)));
final lineEndY =
min(data.maxY, max(data.minY, data.lineTouchData.getTouchLineEnd(barData, index)));
final lineStart = Offset(touchedSpot.dx, getPixelY(lineStartY, chartViewSize));
var lineEnd = Offset(touchedSpot.dx, getPixelY(lineEndY, chartViewSize));
if (data.lineTouchData.touchLineEndAtDot) {
if (lineStart.dy < lineEnd.dy) {
lineEnd -= Offset(0, dotHeight / 2);
} else {
lineEnd += Offset(0, dotHeight / 2);
}
}

_touchLinePaint.color = indicatorData.indicatorBelowLine.color;
_touchLinePaint.strokeWidth = indicatorData.indicatorBelowLine.strokeWidth;
_touchLinePaint.transparentIfWidthIsZero();

canvasWrapper.drawDashedLine(
bottom, lineEnd, _touchLinePaint, indicatorData.indicatorBelowLine.dashArray);
lineStart, lineEnd, _touchLinePaint, indicatorData.indicatorBelowLine.dashArray);

/// Draw the indicator dot
if (showingDots) {
Expand Down
4 changes: 3 additions & 1 deletion repo_files/documentations/line_chart.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@ LineChart(
|getTouchedSpotIndicator| a callback that retrieves list of [TouchedSpotIndicatorData](#TouchedSpotIndicatorData) by the given list of [LineBarSpot](#LineBarSpot) for showing the indicators on touched spots|defaultTouchedIndicators|
|touchSpotThreshold|the threshold of the touch accuracy|10|
|handleBuiltInTouches| set this true if you want the built in touch handling (show a tooltip bubble and an indicator on touched spots) | true|
|fullHeightTouchLine| set `true` to show the line in full height mode | false|
|getTouchLineStart| controls where the line starts, default is bottom of the chart| defaultGetTouchLineStart|
|getTouchLineEnd| controls where the line ends, default is the touch point| defaultGetTouchLineEnd|
|touchLineEndAtDot| whether to avoid the touch line to overlap with the dot| true|
|touchCallback| listen to this callback to retrieve touch events, it gives you a [LineTouchResponse](#LineTouchResponse)| null|


Expand Down
10 changes: 2 additions & 8 deletions test/chart/data_pool.dart
Original file line number Diff line number Diff line change
Expand Up @@ -988,7 +988,6 @@ final LineTouchData lineTouchData1 = LineTouchData(
handleBuiltInTouches: false,
touchSpotThreshold: 12,
touchTooltipData: lineTouchTooltipData1,
fullHeightTouchLine: false,
);
final LineTouchData lineTouchData1Clone = LineTouchData(
enabled: true,
Expand All @@ -997,7 +996,6 @@ final LineTouchData lineTouchData1Clone = LineTouchData(
handleBuiltInTouches: false,
touchSpotThreshold: 12,
touchTooltipData: lineTouchTooltipData1,
fullHeightTouchLine: false,
);

final LineTouchData lineTouchData2 = LineTouchData(
Expand All @@ -1007,7 +1005,6 @@ final LineTouchData lineTouchData2 = LineTouchData(
handleBuiltInTouches: false,
touchSpotThreshold: 12,
touchTooltipData: lineTouchTooltipData1,
fullHeightTouchLine: false,
);
final LineTouchData lineTouchData3 = LineTouchData(
enabled: true,
Expand All @@ -1016,7 +1013,6 @@ final LineTouchData lineTouchData3 = LineTouchData(
handleBuiltInTouches: false,
touchSpotThreshold: 12,
touchTooltipData: lineTouchTooltipData1,
fullHeightTouchLine: false,
);
final LineTouchData lineTouchData4 = LineTouchData(
enabled: true,
Expand All @@ -1025,7 +1021,6 @@ final LineTouchData lineTouchData4 = LineTouchData(
handleBuiltInTouches: false,
touchSpotThreshold: 12,
touchTooltipData: null,
fullHeightTouchLine: false,
);
final LineTouchData lineTouchData5 = LineTouchData(
enabled: true,
Expand All @@ -1034,7 +1029,6 @@ final LineTouchData lineTouchData5 = LineTouchData(
handleBuiltInTouches: false,
touchSpotThreshold: 12.001,
touchTooltipData: lineTouchTooltipData1,
fullHeightTouchLine: false,
);
final LineTouchData lineTouchData6 = LineTouchData(
enabled: true,
Expand All @@ -1043,7 +1037,6 @@ final LineTouchData lineTouchData6 = LineTouchData(
handleBuiltInTouches: true,
touchSpotThreshold: 12,
touchTooltipData: lineTouchTooltipData1,
fullHeightTouchLine: false,
);
final LineTouchData lineTouchData7 = LineTouchData(
enabled: true,
Expand All @@ -1052,7 +1045,8 @@ final LineTouchData lineTouchData7 = LineTouchData(
handleBuiltInTouches: false,
touchSpotThreshold: 12,
touchTooltipData: lineTouchTooltipData1,
fullHeightTouchLine: true,
getTouchLineEnd: (barData, index) => double.infinity,
touchLineEndAtDot: false,
);

final String Function(HorizontalLine) horizontalLabelResolver = (horizontalLine) => 'test';
Expand Down

0 comments on commit d2b7d6f

Please sign in to comment.