Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting start/end point of the TouchLine #604

Merged
merged 5 commits into from
Mar 23, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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(),
imaNNeo marked this conversation as resolved.
Show resolved Hide resolved
],
),
),
Expand Down
3 changes: 2 additions & 1 deletion example/lib/line_chart/samples/line_chart_sample8.dart
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ class _LineChartSample8State extends State<LineChartSample8> {
),
),
lineTouchData: LineTouchData(
fullHeightTouchLine: true,
getTouchLineEnd: (data, index) => double.infinity,
touchLineEndAtDot: false,
getTouchedSpotIndicator: (LineChartBarData barData, List<int> spotIndexes) {
return spotIndexes.map((spotIndex) {
return TouchedSpotIndicatorData(
Expand Down
92 changes: 92 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,92 @@
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,
imaNNeo marked this conversation as resolved.
Show resolved Hide resolved
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;
imaNNeo marked this conversation as resolved.
Show resolved Hide resolved
}

/// 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) {
imaNNeo marked this conversation as resolved.
Show resolved Hide resolved
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