History graph now is zoomable and draggable.
Also fixed missing finesse data in old endcontexts
This commit is contained in:
parent
a6b3a0282a
commit
14def01b57
|
@ -548,13 +548,13 @@ class EndContextSingle {
|
||||||
late Duration finalTime;
|
late Duration finalTime;
|
||||||
late int tSpins;
|
late int tSpins;
|
||||||
late Clears clears;
|
late Clears clears;
|
||||||
late Finesse finesse;
|
late Finesse? finesse;
|
||||||
|
|
||||||
double get pps => piecesPlaced / (finalTime.inMicroseconds / 1000000);
|
double get pps => piecesPlaced / (finalTime.inMicroseconds / 1000000);
|
||||||
double get kpp => inputs / piecesPlaced;
|
double get kpp => inputs / piecesPlaced;
|
||||||
double get spp => score / piecesPlaced;
|
double get spp => score / piecesPlaced;
|
||||||
double get kps => inputs / (finalTime.inMicroseconds / 1000000);
|
double get kps => inputs / (finalTime.inMicroseconds / 1000000);
|
||||||
double get finessePercentage => finesse.perfectPieces / piecesPlaced;
|
double get finessePercentage => finesse != null ? finesse!.perfectPieces / piecesPlaced : 0;
|
||||||
|
|
||||||
EndContextSingle(
|
EndContextSingle(
|
||||||
{required this.gameType,
|
{required this.gameType,
|
||||||
|
@ -585,7 +585,7 @@ class EndContextSingle {
|
||||||
tSpins = json['tspins'];
|
tSpins = json['tspins'];
|
||||||
piecesPlaced = json['piecesplaced'];
|
piecesPlaced = json['piecesplaced'];
|
||||||
clears = Clears.fromJson(json['clears']);
|
clears = Clears.fromJson(json['clears']);
|
||||||
finesse = Finesse.fromJson(json['finesse']);
|
finesse = json.containsKey("finesse") ? Finesse.fromJson(json['finesse']) : null;
|
||||||
gameType = json['gametype'];
|
gameType = json['gametype'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,7 +602,7 @@ class EndContextSingle {
|
||||||
data['tspins'] = tSpins;
|
data['tspins'] = tSpins;
|
||||||
data['piecesplaced'] = piecesPlaced;
|
data['piecesplaced'] = piecesPlaced;
|
||||||
data['clears'] = clears.toJson();
|
data['clears'] = clears.toJson();
|
||||||
data['finesse'] = finesse.toJson();
|
if (finesse != null) data['finesse'] = finesse!.toJson();
|
||||||
data['finalTime'] = finalTime;
|
data['finalTime'] = finalTime;
|
||||||
data['gametype'] = gameType;
|
data['gametype'] = gameType;
|
||||||
return data;
|
return data;
|
||||||
|
|
|
@ -312,13 +312,13 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
||||||
onRefresh: () {
|
onRefresh: () {
|
||||||
return Future(() => changePlayer(snapshot.data![0].userId));
|
return Future(() => changePlayer(snapshot.data![0].userId));
|
||||||
},
|
},
|
||||||
notificationPredicate: (notification) {
|
// notificationPredicate: (notification) {
|
||||||
// with NestedScrollView local(depth == 2) OverscrollNotification are not sent
|
// // with NestedScrollView local(depth == 2) OverscrollNotification are not sent
|
||||||
if (!kIsWeb && (notification is OverscrollNotification || Platform.isIOS)) {
|
// if (!kIsWeb && (notification is OverscrollNotification || Platform.isIOS)) {
|
||||||
return notification.depth == 2;
|
// return notification.depth == 2;
|
||||||
}
|
// }
|
||||||
return notification.depth == 0;
|
// return notification.depth == 0;
|
||||||
},
|
// },
|
||||||
child: NestedScrollView(
|
child: NestedScrollView(
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
|
@ -617,7 +617,9 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
|
||||||
late double minX;
|
late double minX;
|
||||||
late double maxX;
|
late double maxX;
|
||||||
late double minY;
|
late double minY;
|
||||||
|
late double actualMinY;
|
||||||
late double maxY;
|
late double maxY;
|
||||||
|
late double actualMaxY;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState(){
|
void initState(){
|
||||||
|
@ -640,11 +642,25 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
}).y;
|
}).y;
|
||||||
|
actualMaxY = maxY;
|
||||||
|
actualMinY = minY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose(){
|
||||||
|
super.dispose();
|
||||||
|
actualMinY = 0;
|
||||||
|
minY = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
GlobalKey graphKey = GlobalKey();
|
||||||
double xScale = maxX - minX;
|
double xScale = maxX - minX;
|
||||||
|
double yScale = maxY - minY;
|
||||||
|
double scaleFactor = 5e2;
|
||||||
|
double dragFactor = 7e2;
|
||||||
double xInterval = widget.bigScreen ? max(1, xScale / 6) : max(1, xScale / 3);
|
double xInterval = widget.bigScreen ? max(1, xScale / 6) : max(1, xScale / 3);
|
||||||
EdgeInsets padding = widget.bigScreen ? const EdgeInsets.fromLTRB(40, 30, 40, 30) : const EdgeInsets.fromLTRB(0, 40, 16, 48);
|
EdgeInsets padding = widget.bigScreen ? const EdgeInsets.fromLTRB(40, 30, 40, 30) : const EdgeInsets.fromLTRB(0, 40, 16, 48);
|
||||||
double graphStartX = padding.left+widget.leftSpace;
|
double graphStartX = padding.left+widget.leftSpace;
|
||||||
|
@ -653,35 +669,48 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
|
||||||
width: MediaQuery.of(context).size.width,
|
width: MediaQuery.of(context).size.width,
|
||||||
height: MediaQuery.of(context).size.height - 104,
|
height: MediaQuery.of(context).size.height - 104,
|
||||||
child: Listener(
|
child: Listener(
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
onPointerSignal: (signal) {
|
onPointerSignal: (signal) {
|
||||||
if (signal is PointerScrollEvent) {
|
if (signal is PointerScrollEvent) {
|
||||||
|
RenderBox graphBox = graphKey.currentContext?.findRenderObject() as RenderBox;
|
||||||
|
Offset graphPosition = graphBox.localToGlobal(Offset.zero);
|
||||||
double scrollPosRelativeX = (signal.position.dx - graphStartX) / (graphEndX - graphStartX);
|
double scrollPosRelativeX = (signal.position.dx - graphStartX) / (graphEndX - graphStartX);
|
||||||
double newMinX, newMaxX;
|
double scrollPosRelativeY = (signal.position.dy - graphPosition.dy) / (graphBox.size.height - 30); // size - bottom titles height
|
||||||
newMinX = minX - (xScale / 5e2) * signal.scrollDelta.dy * scrollPosRelativeX;
|
double newMinX, newMaxX, newMinY, newMaxY;
|
||||||
newMaxX = maxX + (xScale / 5e2) * signal.scrollDelta.dy * (1-scrollPosRelativeX);
|
newMinX = minX - (xScale / scaleFactor) * signal.scrollDelta.dy * scrollPosRelativeX;
|
||||||
|
newMaxX = maxX + (xScale / scaleFactor) * signal.scrollDelta.dy * (1-scrollPosRelativeX);
|
||||||
|
newMinY = minY - (yScale / scaleFactor) * signal.scrollDelta.dy * (1-scrollPosRelativeY);
|
||||||
|
newMaxY = maxY + (yScale / scaleFactor) * signal.scrollDelta.dy * scrollPosRelativeY;
|
||||||
if ((newMaxX - newMinX).isNegative) return;
|
if ((newMaxX - newMinX).isNegative) return;
|
||||||
|
if ((newMaxY - newMinY).isNegative) return;
|
||||||
setState(() {
|
setState(() {
|
||||||
minX = max(newMinX, widget.data.first.x);
|
minX = max(newMinX, widget.data.first.x);
|
||||||
maxX = min(newMaxX, widget.data.last.x);
|
maxX = min(newMaxX, widget.data.last.x);
|
||||||
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
|
minY = max(newMinY, actualMinY);
|
||||||
|
maxY = min(newMaxY, actualMaxY);
|
||||||
|
_scrollController.jumpTo(_scrollController.position.maxScrollExtent - signal.scrollDelta.dy);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child:
|
child:
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
onDoubleTap: () {
|
onDoubleTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
minX = widget.data.first.x;
|
minX = widget.data.first.x;
|
||||||
maxX = widget.data.last.x;
|
maxX = widget.data.last.x;
|
||||||
|
minY = actualMinY;
|
||||||
|
maxY = actualMaxY;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onHorizontalDragUpdate: (dragUpdDet) {
|
onPanUpdate: (dragUpdDet) {
|
||||||
var horizontalDistance = dragUpdDet.primaryDelta ?? 0;
|
print(dragUpdDet);
|
||||||
if (horizontalDistance == 0) return;
|
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
minX -= (xScale / 7e2) * horizontalDistance;
|
minX -= (xScale / dragFactor) * dragUpdDet.delta.dx;
|
||||||
maxX -= (xScale / 7e2) * horizontalDistance;
|
maxX -= (xScale / dragFactor) * dragUpdDet.delta.dx;
|
||||||
|
minY += (yScale / dragFactor) * dragUpdDet.delta.dy;
|
||||||
|
maxY += (yScale / dragFactor) * dragUpdDet.delta.dy;
|
||||||
|
|
||||||
if (minX < widget.data.first.x) {
|
if (minX < widget.data.first.x) {
|
||||||
minX = widget.data.first.x;
|
minX = widget.data.first.x;
|
||||||
|
@ -693,8 +722,10 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
child: AbsorbPointer(
|
||||||
child: Padding( padding: padding,
|
child: Padding( padding: padding,
|
||||||
child: LineChart(
|
child: LineChart(
|
||||||
|
key: graphKey,
|
||||||
LineChartData(
|
LineChartData(
|
||||||
lineBarsData: [LineChartBarData(spots: widget.data)],
|
lineBarsData: [LineChartBarData(spots: widget.data)],
|
||||||
clipData: const FlClipData.all(),
|
clipData: const FlClipData.all(),
|
||||||
|
@ -702,6 +733,8 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
|
||||||
gridData: FlGridData(verticalInterval: xInterval),
|
gridData: FlGridData(verticalInterval: xInterval),
|
||||||
minX: minX,
|
minX: minX,
|
||||||
maxX: maxX,
|
maxX: maxX,
|
||||||
|
minY: minY,
|
||||||
|
maxY: maxY,
|
||||||
titlesData: FlTitlesData(topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
titlesData: FlTitlesData(topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
||||||
rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
||||||
bottomTitles: AxisTitles(sideTitles: SideTitles(interval: xInterval, showTitles: true, reservedSize: 30, getTitlesWidget: (double value, TitleMeta meta){
|
bottomTitles: AxisTitles(sideTitles: SideTitles(interval: xInterval, showTitles: true, reservedSize: 30, getTitlesWidget: (double value, TitleMeta meta){
|
||||||
|
@ -723,6 +756,7 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -810,12 +844,12 @@ class _RecordThingy extends StatelessWidget {
|
||||||
fractionDigits: 2,
|
fractionDigits: 2,
|
||||||
isScreenBig: bigScreen,
|
isScreenBig: bigScreen,
|
||||||
higherIsBetter: true,),
|
higherIsBetter: true,),
|
||||||
StatCellNum(
|
if (record!.endContext!.finesse != null) StatCellNum(
|
||||||
playerStat: record!.endContext!.finesse.faults,
|
playerStat: record!.endContext!.finesse!.faults,
|
||||||
playerStatLabel: t.statCellNum.finesseFaults,
|
playerStatLabel: t.statCellNum.finesseFaults,
|
||||||
isScreenBig: bigScreen,
|
isScreenBig: bigScreen,
|
||||||
higherIsBetter: false,),
|
higherIsBetter: false,),
|
||||||
StatCellNum(
|
if (record!.endContext!.finesse != null) StatCellNum(
|
||||||
playerStat:
|
playerStat:
|
||||||
record!.endContext!.finessePercentage * 100,
|
record!.endContext!.finessePercentage * 100,
|
||||||
playerStatLabel: t.statCellNum.finessePercentage,
|
playerStatLabel: t.statCellNum.finessePercentage,
|
||||||
|
|
Loading…
Reference in New Issue