Skip to content

Rustem/time_labels #11

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

Merged
merged 26 commits into from
Aug 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c5dfdf6
Fix grid epochs for 24h interval
ruskakimov Jul 24, 2020
9e456b8
Include left bound epoch for day intervals
ruskakimov Jul 24, 2020
9137927
Refactor to represent interval as Duration
ruskakimov Jul 24, 2020
a96330b
Fix broken tests
ruskakimov Jul 24, 2020
ad8fa41
Update comment
ruskakimov Jul 24, 2020
2b69b79
Use daysPerWeek static const instead of a literal
ruskakimov Jul 27, 2020
b3ad79d
Enforce output epochs to be sorted
ruskakimov Jul 27, 2020
01f7ab1
Add green tests
ruskakimov Jul 27, 2020
471ee9a
Add green tests for 2h interval
ruskakimov Jul 27, 2020
02cf249
Add green tests for 4h interval
ruskakimov Jul 27, 2020
368fdc2
Return start of Mondays for week interval
ruskakimov Jul 27, 2020
77a492d
Minor refactor
ruskakimov Jul 27, 2020
0e35d3f
Refactor
ruskakimov Jul 28, 2020
e36c69c
Return as DateTime objects instead of epochs
ruskakimov Jul 28, 2020
ce11538
Add month interval
ruskakimov Jul 29, 2020
fa0b78d
Calc days until monday instead of while loop
ruskakimov Jul 29, 2020
1aff029
Add year, month and date time labels
ruskakimov Jul 29, 2020
bf86318
Update test name
ruskakimov Jul 29, 2020
014a6f0
Update flutter-deriv-api
ruskakimov Jul 30, 2020
2a703d7
Requested changes
ruskakimov Jul 30, 2020
1ec40dd
Refactor to use DateTime constructor cleverness
ruskakimov Jul 30, 2020
e6b3896
Switch to UTC
ruskakimov Aug 3, 2020
3d7c2b3
Merge and resolve conflicts
ruskakimov Aug 3, 2020
44bb0bd
Missed UTC conversion
ruskakimov Aug 3, 2020
908770d
Remove function names from test names, simplify test names
ruskakimov Aug 3, 2020
ecec273
Merge branch 'dev' into time_labels
ruskakimov Aug 11, 2020
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: 4 additions & 4 deletions lib/src/chart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ class _ChartState extends State<Chart> with TickerProviderStateMixin {
CustomPaint(
size: canvasSize,
painter: GridPainter(
gridLineEpochs: _getGridLineEpochs(),
gridTimestamps: _getGridLineTimestamps(),
gridLineQuotes: _getGridLineQuotes(),
pipSize: widget.pipSize,
quoteLabelsAreaWidth: quoteLabelsAreaWidth,
Expand Down Expand Up @@ -477,9 +477,9 @@ class _ChartState extends State<Chart> with TickerProviderStateMixin {
);
}

List<int> _getGridLineEpochs() {
return gridEpochs(
timeGridInterval: timeGridIntervalInSeconds(msPerPx) * 1000,
List<DateTime> _getGridLineTimestamps() {
return gridTimestamps(
timeGridInterval: timeGridInterval(msPerPx),
leftBoundEpoch:
rightBoundEpoch - pxToMs(canvasSize.width, msPerPx: msPerPx),
rightBoundEpoch: rightBoundEpoch,
Expand Down
123 changes: 88 additions & 35 deletions lib/src/logic/time_grid.dart
Original file line number Diff line number Diff line change
@@ -1,58 +1,111 @@
import 'package:intl/intl.dart' show DateFormat;
import 'package:meta/meta.dart';

import 'conversion.dart';

List<int> gridEpochs({
@required int timeGridInterval,
const _day = Duration(days: 1);
const _week = Duration(days: DateTime.daysPerWeek);
const month = Duration(days: 30);

List<DateTime> gridTimestamps({
@required Duration timeGridInterval,
@required int leftBoundEpoch,
@required int rightBoundEpoch,
}) {
final firstRight =
(rightBoundEpoch - rightBoundEpoch % timeGridInterval).toInt();
final epochs = <int>[];
for (int epoch = firstRight;
epoch >= leftBoundEpoch;
epoch -= timeGridInterval) {
epochs.add(epoch);
final timestamps = <DateTime>[];
final rightBoundTime =
DateTime.fromMillisecondsSinceEpoch(rightBoundEpoch, isUtc: true);

var t = _gridEpochStart(timeGridInterval, leftBoundEpoch);

while (t.compareTo(rightBoundTime) <= 0) {
timestamps.add(t);
t = timeGridInterval == month ? _addMonth(t) : t.add(timeGridInterval);
}
return epochs;
return timestamps;
}

int timeGridIntervalInSeconds(
DateTime _gridEpochStart(Duration timeGridInterval, int leftBoundEpoch) {
if (timeGridInterval == month) {
return _closestFutureMonthStart(leftBoundEpoch);
} else if (timeGridInterval == _week) {
final t = _closestFutureDayStart(leftBoundEpoch);
final daysUntilMonday = (8 - t.weekday) % 7;
return t.add(Duration(days: daysUntilMonday));
} else if (timeGridInterval == _day) {
return _closestFutureDayStart(leftBoundEpoch);
} else {
final diff = timeGridInterval.inMilliseconds;
final firstLeft = (leftBoundEpoch / diff).ceil() * diff;
return DateTime.fromMillisecondsSinceEpoch(firstLeft, isUtc: true);
}
}

DateTime _closestFutureDayStart(int epoch) {
final time = DateTime.fromMillisecondsSinceEpoch(epoch, isUtc: true);
final dayStart =
DateTime.utc(time.year, time.month, time.day); // time 00:00:00
return dayStart.isBefore(time) ? dayStart.add(_day) : dayStart;
}

DateTime _closestFutureMonthStart(int epoch) {
final time = DateTime.fromMillisecondsSinceEpoch(epoch, isUtc: true);
final monthStart =
DateTime.utc(time.year, time.month); // day 1, time 00:00:00
return monthStart.isBefore(time) ? _addMonth(monthStart) : monthStart;
}

DateTime _addMonth(DateTime time) {
return DateTime.utc(time.year, time.month + 1);
}

Duration timeGridInterval(
double msPerPx, {
double minDistanceBetweenLines = 100,
List<int> intervalsInSeconds = const [
5, // 5 sec
10, // 10 sec
30, // 30 sec
60, // 1 min
120, // 2 min
180, // 3 min
300, // 5 min
600, // 10 min
900, // 15 min
1800, // 30 min
3600, // 1 hour
7200, // 2 hours
14400, // 4 hours
28800, // 8 hours
86400, // 24 hours
172800, // 2 days
259200, // 3 days
604800, // 1 week
2419200, // 4 weeks
List<Duration> intervals = const [
Duration(seconds: 5),
Duration(seconds: 10),
Duration(seconds: 30),
Duration(minutes: 1),
Duration(minutes: 2),
Duration(minutes: 3),
Duration(minutes: 5),
Duration(minutes: 10),
Duration(minutes: 15),
Duration(minutes: 30),
Duration(hours: 1),
Duration(hours: 2),
Duration(hours: 4),
Duration(hours: 8),
_day,
_week,
month,
],
}) {
bool hasEnoughDistanceBetweenLines(int intervalInSeconds) {
bool hasEnoughDistanceBetweenLines(Duration interval) {
final distanceBetweenLines = msToPx(
intervalInSeconds * 1000,
interval.inMilliseconds,
msPerPx: msPerPx,
);
return distanceBetweenLines >= minDistanceBetweenLines;
}

return intervalsInSeconds.firstWhere(
return intervals.firstWhere(
hasEnoughDistanceBetweenLines,
orElse: () => intervalsInSeconds.last,
orElse: () => intervals.last,
);
}

String timeLabel(DateTime time) {
final is0h0m0s = time.hour == 0 && time.minute == 0 && time.second == 0;
if (time.month == 1 && time.day == 1 && is0h0m0s) {
return DateFormat('y').format(time);
}
if (time.day == 1 && is0h0m0s) {
return DateFormat('MMMM').format(time);
}
if (is0h0m0s) {
return DateFormat('d MMM').format(time);
}
return DateFormat('Hms').format(time);
}
15 changes: 7 additions & 8 deletions lib/src/painters/grid_painter.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import 'package:intl/intl.dart' show DateFormat;
import 'package:deriv_chart/src/logic/time_grid.dart';
import 'package:flutter/material.dart';

import '../paint/paint_grid.dart';

class GridPainter extends CustomPainter {
GridPainter({
@required this.gridLineEpochs,
@required this.gridTimestamps,
@required this.gridLineQuotes,
@required this.quoteLabelsAreaWidth,
@required this.pipSize,
Expand All @@ -15,7 +15,7 @@ class GridPainter extends CustomPainter {

final int pipSize;

final List<int> gridLineEpochs;
final List<DateTime> gridTimestamps;
final List<double> gridLineQuotes;

/// Width of the area where quote labels and current tick arrow are painted.
Expand All @@ -29,14 +29,13 @@ class GridPainter extends CustomPainter {
paintGrid(
canvas,
size,
timeLabels: gridLineEpochs.map((epoch) {
final time = DateTime.fromMillisecondsSinceEpoch(epoch);
return DateFormat('Hms').format(time);
}).toList(),
timeLabels: gridTimestamps.map((time) => timeLabel(time)).toList(),
quoteLabels: gridLineQuotes
.map((quote) => quote.toStringAsFixed(pipSize))
.toList(),
xCoords: gridLineEpochs.map((epoch) => epochToCanvasX(epoch)).toList(),
xCoords: gridTimestamps
.map((time) => epochToCanvasX(time.millisecondsSinceEpoch))
.toList(),
yCoords: gridLineQuotes.map((quote) => quoteToCanvasY(quote)).toList(),
quoteLabelsAreaWidth: quoteLabelsAreaWidth,
);
Expand Down
Loading