Skip to content
Open
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
8 changes: 6 additions & 2 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,19 @@ class MyApp extends StatelessWidget {
data: smallDataList,
chartType: ChartType.amount,
viewMode: ViewMode.weekly,
barColor: Colors.deepPurple,
chartStyle: ChartStyle(
barColor: Colors.deepPurple
),
),
sizedBox,
const Text('Monthly amount chart'),
TimeChart(
data: smallDataList,
chartType: ChartType.amount,
viewMode: ViewMode.monthly,
barColor: Colors.deepPurple,
chartStyle: ChartStyle(
barColor: Colors.deepPurple
)
),
],
),
Expand Down
81 changes: 30 additions & 51 deletions lib/src/chart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:linked_scroll_controller/linked_scroll_controller.dart';
import 'package:touchable/touchable.dart';

import '../time_chart.dart';
import 'components/chart_style.dart';
import 'components/painter/amount_chart/amount_x_label_painter.dart';
import 'components/painter/amount_chart/amount_y_label_painter.dart';
import 'components/painter/time_chart/time_x_label_painter.dart';
Expand All @@ -26,43 +27,44 @@ import 'components/translations/translations.dart';
import 'components/utils/context_utils.dart';

class Chart extends StatefulWidget {
const Chart({
Chart({
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here

Suggested change
Chart({
const Chart({

Key? key,
required this.chartType,
required this.width,
required this.height,
required this.barColor,
required this.data,
required this.timeChartSizeAnimationDuration,
required this.tooltipDuration,
required this.tooltipBackgroundColor,
required this.tooltipStart,
required this.tooltipEnd,
required this.activeTooltip,
required this.viewMode,
required this.defaultPivotHour,
}) : super(key: key);
this.chartStyle,
}) : super(key: key) {
kLineColor3 = chartStyle?.verticalGridColor ?? kLineColor3;
kLineColor1 = chartStyle?.horizontalGridColor ?? kLineColor1;
kTextColor = chartStyle?.labelColor ?? kLineColor3;
}

final ChartType chartType;
final double width;
final double height;
final Color? barColor;
final List<DateTimeRange> data;
final Duration timeChartSizeAnimationDuration;
final Duration tooltipDuration;
final Color? tooltipBackgroundColor;
final String tooltipStart;
final String tooltipEnd;
final bool activeTooltip;
final ViewMode viewMode;
final int defaultPivotHour;
final ChartStyle? chartStyle;

@override
ChartState createState() => ChartState();
}

class ChartState extends State<Chart>
with TickerProviderStateMixin, TimeDataProcessor {
class ChartState extends State<Chart> with TickerProviderStateMixin, TimeDataProcessor {
static const Duration _tooltipFadeInDuration = Duration(milliseconds: 150);
static const Duration _tooltipFadeOutDuration = Duration(milliseconds: 75);

Expand Down Expand Up @@ -147,24 +149,20 @@ class ChartState extends State<Chart>
_sizeController.dispose();
_tooltipController.dispose();
_cancelTimer();
GestureBinding.instance.pointerRouter
.removeGlobalRoute(_handlePointerEvent);
GestureBinding.instance.pointerRouter.removeGlobalRoute(_handlePointerEvent);
super.dispose();
}

DateTime _getFirstItemDate({Duration addition = Duration.zero}) {
return widget.data.isEmpty
? DateTime.now()
: widget.data.first.end.dateWithoutTime().add(addition);
return widget.data.isEmpty ? DateTime.now() : widget.data.first.end.dateWithoutTime().add(addition);
}

void _addScrollNotifier() {
WidgetsBinding.instance.addPostFrameCallback((_) {
final minDifference = _blockWidth!;

_scrollControllerGroup.addOffsetChangedListener(() {
final difference =
(_scrollControllerGroup.offset - _previousScrollOffset).abs();
final difference = (_scrollControllerGroup.offset - _previousScrollOffset).abs();

if (difference >= minDifference) {
_scrollOffsetNotifier.value = _scrollControllerGroup.offset;
Expand Down Expand Up @@ -204,8 +202,7 @@ class ChartState extends State<Chart>
}

// 현재 보이는 툴팁이 다시 호출되면 무시한다.
if ((_tooltipHideTimer?.isActive ?? false) &&
_currentVisibleTooltipRect == rect) return;
if ((_tooltipHideTimer?.isActive ?? false) && _currentVisibleTooltipRect == rect) return;
_currentVisibleTooltipRect = rect;

HapticFeedback.vibrate();
Expand Down Expand Up @@ -239,16 +236,13 @@ class ChartState extends State<Chart>
final chartType = amount == null ? ChartType.time : ChartType.amount;
// 현재 위젯의 위치를 얻는다.
final widgetOffset = context.getRenderBoxOffset()!;
final tooltipSize =
chartType == ChartType.time ? kTimeTooltipSize : kAmountTooltipSize;
final tooltipSize = chartType == ChartType.time ? kTimeTooltipSize : kAmountTooltipSize;

final candidateTop = rect.top +
widgetOffset.dy -
tooltipSize.height / 2 +
kTimeChartTopPadding +
(chartType == ChartType.time
? (rect.bottom - rect.top) / 2
: kTooltipArrowHeight / 2);
(chartType == ChartType.time ? (rect.bottom - rect.top) / 2 : kTooltipArrowHeight / 2);

final scrollPixels = position.maxScrollExtent - position.pixels;
final localLeft = rect.left + widgetOffset.dx - scrollPixels;
Expand All @@ -272,7 +266,7 @@ class ChartState extends State<Chart>
curve: Curves.fastOutSlowIn,
),
child: TooltipOverlay(
backgroundColor: widget.tooltipBackgroundColor,
backgroundColor: widget.chartStyle?.tooltipBackgroundColor,
chartType: chartType,
bottomHour: bottomHour,
timeRange: range,
Expand Down Expand Up @@ -303,10 +297,7 @@ class ChartState extends State<Chart>
final TextPainter tp = TextPainter(
text: TextSpan(
text: translations.formatHourOnly(12),
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Colors.white38),
style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: Colors.white38),
),
textDirection: TextDirection.ltr,
);
Expand All @@ -324,8 +315,7 @@ class ChartState extends State<Chart>
if (notification is ScrollStartNotification) {
_cancelTimer();
} else if (notification is ScrollEndNotification) {
_pivotHourUpdatingTimer =
Timer(const Duration(milliseconds: 800), _timerCallback);
_pivotHourUpdatingTimer = Timer(const Duration(milliseconds: 800), _timerCallback);
}
return true;
}
Expand All @@ -335,10 +325,8 @@ class ChartState extends State<Chart>
final beforeTopHour = topHour;
final beforeBottomHour = bottomHour;

final blockIndex =
getCurrentBlockIndex(_barController.position, _blockWidth!).toInt();
final needsToAdaptScrollPosition =
blockIndex > 0 && isFirstDataMovedNextDay;
final blockIndex = getCurrentBlockIndex(_barController.position, _blockWidth!).toInt();
final needsToAdaptScrollPosition = blockIndex > 0 && isFirstDataMovedNextDay;
final scrollPositionDuration = Duration(
days: -blockIndex + (needsToAdaptScrollPosition ? 1 : 0),
);
Expand All @@ -362,24 +350,19 @@ class ChartState extends State<Chart>
double get heightWithoutLabel => widget.height - kXLabelHeight;

void _runHeightAnimation(int beforeTopHour, int beforeBottomHour) {
final beforeDiff =
hourDiffBetween(beforeTopHour, beforeBottomHour).toDouble();
final beforeDiff = hourDiffBetween(beforeTopHour, beforeBottomHour).toDouble();
final currentDiff = hourDiffBetween(topHour, bottomHour).toDouble();

final candidateUpward = diffBetween(beforeTopHour, topHour!);
final candidateDownWard = -diffBetween(topHour!, beforeTopHour);

// (candidate)중에서 current top-bottom hour 범위에 들어오는 것을 선택한다.
final topDiff =
isDirUpward(beforeTopHour, beforeBottomHour, topHour!, bottomHour!)
? candidateUpward
: candidateDownWard;
isDirUpward(beforeTopHour, beforeBottomHour, topHour!, bottomHour!) ? candidateUpward : candidateDownWard;

setState(() {
_animationBeginHeight =
(currentDiff / beforeDiff) * heightWithoutLabel + kXLabelHeight;
_heightForAlignTop = (_animationBeginHeight - widget.height) / 2 +
(topDiff / beforeDiff) * heightWithoutLabel;
_animationBeginHeight = (currentDiff / beforeDiff) * heightWithoutLabel + kXLabelHeight;
_heightForAlignTop = (_animationBeginHeight - widget.height) / 2 + (topDiff / beforeDiff) * heightWithoutLabel;
});
_sizeController.reverse(from: 1.0);
}
Expand Down Expand Up @@ -523,8 +506,7 @@ class ChartState extends State<Chart>
double bottomPadding = 0.0,
Function(BuildContext, double)? builder,
}) {
assert(
(child != null && builder == null) || child == null && builder != null);
assert((child != null && builder == null) || child == null && builder != null);

final heightAnimation = Tween<double>(
begin: widget.height,
Expand All @@ -538,9 +520,7 @@ class ChartState extends State<Chart>
return AnimatedBuilder(
animation: _sizeAnimation,
builder: (context, child) {
final topPosition = (widget.height - heightAnimation.value) / 2 +
heightForAlignTopAnimation.value +
topPadding;
final topPosition = (widget.height - heightAnimation.value) / 2 + heightForAlignTopAnimation.value + topPadding;
return Positioned(
right: 0,
top: topPosition,
Expand Down Expand Up @@ -582,8 +562,7 @@ class ChartState extends State<Chart>
}

CustomPainter _buildXLabelPainter(BuildContext context) {
final firstValueDateTime =
processedData.isEmpty ? DateTime.now() : processedData.first.end;
final firstValueDateTime = processedData.isEmpty ? DateTime.now() : processedData.first.end;
switch (widget.chartType) {
case ChartType.time:
return TimeXLabelPainter(
Expand Down Expand Up @@ -616,7 +595,7 @@ class ChartState extends State<Chart>
context: context,
tooltipCallback: _tooltipCallback,
dataList: processedData,
barColor: widget.barColor,
barColor: widget.chartStyle?.barColor,
topHour: topHour!,
bottomHour: bottomHour!,
dayCount: dayCount,
Expand All @@ -628,7 +607,7 @@ class ChartState extends State<Chart>
repaint: _scrollOffsetNotifier,
context: context,
dataList: processedData,
barColor: widget.barColor,
barColor: widget.chartStyle?.barColor,
topHour: topHour!,
bottomHour: bottomHour!,
tooltipCallback: _tooltipCallback,
Expand Down
17 changes: 17 additions & 0 deletions lib/src/components/chart_style.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'dart:ui';

class ChartStyle {
final Color? barColor;
final Color? tooltipBackgroundColor;
final Color? labelColor;
final Color? verticalGridColor;
final Color? horizontalGridColor;

ChartStyle({
this.barColor,
this.tooltipBackgroundColor,
this.labelColor,
this.verticalGridColor,
this.horizontalGridColor,
});
}
8 changes: 4 additions & 4 deletions lib/src/components/painter/chart_engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ const double kLineStrokeWidth = 0.8;
const double kBarWidthRatio = 0.7;
const double kBarPaddingWidthRatio = (1 - kBarWidthRatio) / 2;

const Color kLineColor1 = Color(0x44757575);
const Color kLineColor2 = Color(0x77757575);
const Color kLineColor3 = Color(0xAA757575);
const Color kTextColor = Color(0xFF757575);
Color kLineColor1 = Color(0x44757575);
Color kLineColor2 = Color(0x77757575);
Color kLineColor3 = Color(0xAA757575);
Color kTextColor = Color(0xFF757575);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you change here as const and then pass the style prop to the child component? I think it's not good using global mutable variables.


abstract class ChartEngine extends CustomPainter {
static const int toleranceDay = 1;
Expand Down
Loading