I guess I finally found a solution to perfomance issue and replacement for fl_chart
I wish i wasn't that stupid
This commit is contained in:
parent
5c6c502a57
commit
8081755e71
|
@ -42,7 +42,7 @@ const Map<String, double> rankCutoffs = {
|
|||
"": 0.5
|
||||
};
|
||||
const Map<String, double> rankTargets = {
|
||||
"x": 24008,
|
||||
"x": 24503.75, // where that comes from?
|
||||
"u": 23038,
|
||||
"ss": 21583,
|
||||
"s+": 20128,
|
||||
|
|
|
@ -185,15 +185,17 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
topTR = requests.elementAtOrNull(3) as double?; // No TR - no Top TR
|
||||
|
||||
meAmongEveryone = teto.getCachedLeaderboardPositions(me.userId);
|
||||
if (meAmongEveryone == null && prefs.getBool("showPositions") == true){
|
||||
if (prefs.getBool("showPositions") == true){
|
||||
// Get tetra League leaderboard
|
||||
everyone = teto.getCachedLeaderboard();
|
||||
everyone ??= await teto.fetchTLLeaderboard();
|
||||
meAmongEveryone = await compute(everyone!.getLeaderboardPosition, me);
|
||||
if (meAmongEveryone != null) teto.cacheLeaderboardPositions(me.userId, meAmongEveryone!);
|
||||
if (me.tlSeason1.rank != "z") {
|
||||
thatRankCutoff = everyone!.cutoffs[me.tlSeason1.rank];
|
||||
nextRankCutoff = everyone!.cutoffs[ranks.indexOf(me.tlSeason1.rank)+1];
|
||||
if (meAmongEveryone == null){
|
||||
meAmongEveryone = await compute(everyone!.getLeaderboardPosition, me);
|
||||
if (meAmongEveryone != null) teto.cacheLeaderboardPositions(me.userId, meAmongEveryone!);
|
||||
}
|
||||
if (me.tlSeason1.gamesPlayed > 9) {
|
||||
thatRankCutoff = everyone!.cutoffs[me.tlSeason1.rank != "z" ? me.tlSeason1.rank : me.tlSeason1.percentileRank];
|
||||
nextRankCutoff = everyone!.cutoffs[ranks.elementAtOrNull(ranks.indexOf(me.tlSeason1.rank != "z" ? me.tlSeason1.rank : me.tlSeason1.percentileRank)+1)];
|
||||
nextRankCutoff = nextRankCutoff??25000;
|
||||
}
|
||||
}
|
||||
|
@ -515,7 +517,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
thatRankCutoff: thatRankCutoff,
|
||||
thatRankTarget: snapshot.data![0].tlSeason1.rank != "z" ? rankTargets[snapshot.data![0].tlSeason1.rank] : null,
|
||||
nextRankCutoff: nextRankCutoff,
|
||||
nextRankTarget: snapshot.data![0].tlSeason1.rank != "z" || snapshot.data![0].tlSeason1.rank != "x" ? rankTargets[ranks.indexOf(snapshot.data![0].tlSeason1.rank)+1] : null,
|
||||
nextRankTarget: snapshot.data![0].tlSeason1.rank != "z" || snapshot.data![0].tlSeason1.rank != "x" ? rankTargets[ranks.elementAtOrNull(ranks.indexOf(snapshot.data![0].tlSeason1.rank)+1)] : null,
|
||||
averages: rankAverages,
|
||||
lbPositions: meAmongEveryone
|
||||
),
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
|
@ -10,10 +11,13 @@ import 'package:tetra_stats/gen/strings.g.dart';
|
|||
import 'package:tetra_stats/views/main_view.dart' show MainView;
|
||||
import 'package:tetra_stats/utils/text_shadow.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
import 'package:syncfusion_flutter_charts/sparkcharts.dart';
|
||||
|
||||
var _chartsShortTitlesDropdowns = <DropdownMenuItem>[for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value),)];
|
||||
Stats _chartsX = Stats.tr;
|
||||
Stats _chartsY = Stats.apm;
|
||||
late TooltipBehavior _tooltipBehavior;
|
||||
List<DropdownMenuItem> _itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
|
||||
List<_MyScatterSpot> _spots = [];
|
||||
Stats _sortBy = Stats.tr;
|
||||
|
@ -49,7 +53,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
late double yScale;
|
||||
String headerTooltip = t.pseudoTooltipHeaderInit;
|
||||
String footerTooltip = t.pseudoTooltipFooterInit;
|
||||
int hoveredPointId = -1;
|
||||
ValueNotifier<int> hoveredPointId = ValueNotifier<int>(-1);
|
||||
double scaleFactor = 5e2;
|
||||
double dragFactor = 7e2;
|
||||
|
||||
|
@ -57,6 +61,32 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
void initState() {
|
||||
_scrollController = ScrollController();
|
||||
_tabController = TabController(length: 6, vsync: this);
|
||||
_tooltipBehavior = TooltipBehavior(
|
||||
enable: true,
|
||||
animationDuration: 0,
|
||||
builder: (dynamic data, dynamic point, dynamic series,
|
||||
int pointIndex, int seriesIndex) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: Text(
|
||||
"${data.nickname} (${data.rank.toUpperCase()})",
|
||||
style: TextStyle(color: Colors.black, fontFamily: "Eurostile Round Extended", fontSize: 20),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${_f4.format(data.x)} ${chartsShortTitles[_chartsX]}\n${_f4.format(data.y)} ${chartsShortTitles[_chartsY]}',
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){
|
||||
windowManager.getTitle().then((value) => _oldWindowTitle = value);
|
||||
windowManager.setTitle("Tetra Stats: ${widget.rank[1]["everyone"] ? t.everyoneAverages : t.rankAverages(rank: widget.rank[0].rank.toUpperCase())}");
|
||||
|
@ -113,7 +143,9 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
entry.getStatByEnum(_chartsY).toDouble(),
|
||||
entry.userId,
|
||||
entry.username,
|
||||
dotPainter: FlDotCirclePainter(color: rankColors[entry.rank]??Colors.white, radius: 3))
|
||||
entry.rank,
|
||||
rankColors[entry.rank]??Colors.white
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -328,60 +360,19 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
recalculateScales();
|
||||
});
|
||||
},
|
||||
// TODO: Figure out wtf is going on with gestures
|
||||
child: Padding(
|
||||
padding: bigScreen ? const EdgeInsets.fromLTRB(40, 40, 40, 48) : const EdgeInsets.fromLTRB(0, 40, 16, 48),
|
||||
child: Stack(
|
||||
children: [
|
||||
ScatterChart(
|
||||
key: graphKey,
|
||||
ScatterChartData(
|
||||
minX: minX,
|
||||
maxX: maxX,
|
||||
minY: minY,
|
||||
maxY: maxY,
|
||||
clipData: const FlClipData.all(),
|
||||
scatterSpots: _spots,
|
||||
scatterTouchData: ScatterTouchData(
|
||||
handleBuiltInTouches: false,
|
||||
touchCallback:(touchEvent, touchResponse) {
|
||||
if (touchEvent is FlPanUpdateEvent){
|
||||
dragHandler(touchEvent.details);
|
||||
return;
|
||||
}
|
||||
if (touchEvent is FlPointerHoverEvent){
|
||||
setState(() {
|
||||
if (touchResponse?.touchedSpot == null) {
|
||||
hoveredPointId = -1;
|
||||
} else {
|
||||
hoveredPointId = touchResponse!.touchedSpot!.spotIndex;
|
||||
_MyScatterSpot castedPoint = touchResponse.touchedSpot!.spot as _MyScatterSpot;
|
||||
headerTooltip = castedPoint.nickname;
|
||||
footerTooltip = "${_f4.format(castedPoint.x)} ${chartsShortTitles[_chartsX]}; ${_f4.format(castedPoint.y)} ${chartsShortTitles[_chartsY]}";
|
||||
}
|
||||
});
|
||||
}
|
||||
if (touchEvent is FlPointerExitEvent){
|
||||
setState(() {hoveredPointId = -1;});
|
||||
}
|
||||
if (touchEvent is FlTapUpEvent && touchResponse?.touchedSpot?.spot != null){
|
||||
_MyScatterSpot spot = touchResponse!.touchedSpot!.spot as _MyScatterSpot;
|
||||
Navigator.push(context, MaterialPageRoute(builder: (context) => MainView(player: spot.nickname), maintainState: false));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
swapAnimationDuration: const Duration(milliseconds: 150), // Optional
|
||||
swapAnimationCurve: Curves.linear, // Optional
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(graphStartX+8, padding.top/2+8, 0, 0),
|
||||
child: Column(
|
||||
children: [
|
||||
AnimatedDefaultTextStyle(style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 24, color: Color.fromARGB(hoveredPointId == -1 ? 100 : 255, 255, 255, 255), shadows: hoveredPointId != -1 ? textShadow : null), duration: Durations.medium1, curve: Curves.elasticInOut, child: Text(headerTooltip)),
|
||||
AnimatedDefaultTextStyle(style: TextStyle(fontFamily: "Eurostile Round", color: Color.fromARGB(hoveredPointId == -1 ? 100 : 255, 255, 255, 255), shadows: hoveredPointId != -1 ? textShadow : null), duration: Durations.medium1, curve: Curves.elasticInOut, child: Text(footerTooltip)),
|
||||
],
|
||||
),
|
||||
child: SfCartesianChart(
|
||||
tooltipBehavior: _tooltipBehavior,
|
||||
//primaryXAxis: CategoryAxis(),
|
||||
series: [
|
||||
ScatterSeries(
|
||||
enableTooltip: true,
|
||||
dataSource: _spots,
|
||||
animationDuration: 0,
|
||||
pointColorMapper: (data, _) => data.color,
|
||||
xValueMapper: (data, _) => data.x,
|
||||
yValueMapper: (data, _) => data.y
|
||||
)
|
||||
],
|
||||
),
|
||||
|
@ -642,10 +633,12 @@ class _ListEntry extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
class _MyScatterSpot extends ScatterSpot {
|
||||
class _MyScatterSpot{
|
||||
num x;
|
||||
num y;
|
||||
String id;
|
||||
String nickname;
|
||||
//Color color;
|
||||
//FlDotPainter painter = FlDotCirclePainter(color: color, radius: 2);
|
||||
_MyScatterSpot(super.x, super.y, this.id, this.nickname, {super.dotPainter});
|
||||
String rank;
|
||||
Color color;
|
||||
_MyScatterSpot(this.x, this.y, this.id, this.nickname, this.rank, this.color);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:syncfusion_flutter_gauges/gauges.dart';
|
||||
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||
import 'package:tetra_stats/gen/strings.g.dart';
|
||||
import 'package:tetra_stats/utils/numers_formats.dart';
|
||||
|
||||
class TLProgress extends StatelessWidget{
|
||||
final double tr;
|
||||
|
@ -20,16 +23,15 @@ class TLProgress extends StatelessWidget{
|
|||
const TLProgress({super.key, required this.tr, required this.rank, required this.position, required this.nextRankPosition, required this.previousRankPosition, this.nextRank, this.previousRank, this.nextRankTRcutoff, this.previousRankTRcutoff, this.nextRankTRcutoffTarget, this.previousRankTRcutoffTarget});
|
||||
|
||||
double getBarPosition(){
|
||||
return 1 - (position - nextRankPosition)/(previousRankPosition - nextRankPosition);
|
||||
return min(max(0, 1 - (position - nextRankPosition)/(previousRankPosition - nextRankPosition)), 1);
|
||||
}
|
||||
|
||||
double? getBarTR(){
|
||||
return null;
|
||||
double? getBarTR(double tr){
|
||||
return min(max(0, (tr - previousRankTRcutoff!)/(nextRankTRcutoff! - previousRankTRcutoff!)), 1);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
print(getBarPosition());
|
||||
// return Container(
|
||||
// alignment: Alignment.centerLeft,
|
||||
// height: 50,
|
||||
|
@ -47,11 +49,27 @@ class TLProgress extends StatelessWidget{
|
|||
minimum: 0,
|
||||
maximum: 1,
|
||||
interval: 1,
|
||||
ranges: [LinearGaugeRange(endValue: getBarPosition(), color: Colors.cyanAccent,)],
|
||||
markerPointers: [LinearShapePointer(value: getBarPosition(), position: LinearElementPosition.inside, shapeType: LinearShapePointerType.triangle, color: Colors.white, height: 20),
|
||||
LinearWidgetPointer(offset: 4, position: LinearElementPosition.outside, value: getBarPosition(), child: Text(NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 0).format(position)))],
|
||||
ranges: [
|
||||
if (previousRankTRcutoff != null && nextRankTRcutoff != null) LinearGaugeRange(endValue: getBarTR(tr)!, color: Colors.cyanAccent, position: LinearElementPosition.cross),
|
||||
if (position != -1) LinearGaugeRange(endValue: getBarPosition(), color: Colors.cyanAccent, position: LinearElementPosition.cross),
|
||||
if (previousRankTRcutoff != null && previousRankTRcutoffTarget != null) LinearGaugeRange(endValue: getBarTR(previousRankTRcutoffTarget!)!, color: Colors.greenAccent, position: LinearElementPosition.inside),
|
||||
if (nextRankTRcutoff != null && nextRankTRcutoffTarget != null) LinearGaugeRange(startValue: getBarTR(nextRankTRcutoffTarget!)!, endValue: 1, color: Colors.yellowAccent, position: LinearElementPosition.inside)
|
||||
],
|
||||
markerPointers: [
|
||||
LinearShapePointer(value: getBarPosition(), position: LinearElementPosition.cross, shapeType: LinearShapePointerType.diamond, color: Colors.white, height: 20),
|
||||
LinearWidgetPointer(offset: 4, position: LinearElementPosition.outside, value: getBarPosition(), child: Text("№ ${NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 0).format(position)}"))
|
||||
],
|
||||
isMirrored: true,
|
||||
showTicks: true,
|
||||
axisLabelStyle: TextStyle(),
|
||||
onGenerateLabels: () => [
|
||||
LinearAxisLabel(text: "№ ${f0.format(previousRankPosition)}\n ${intf.format(previousRankTRcutoff)} TR", value: 0),
|
||||
LinearAxisLabel(text: "№ ${f0.format(nextRankPosition)}\n ${intf.format(nextRankTRcutoff)} TR", value: 1),
|
||||
],
|
||||
// labelFormatterCallback: (value) {
|
||||
// if (value == "0") return "${f0.format(previousRankPosition)}\n 26,700 TR";
|
||||
// else return f0.format(nextRankPosition);
|
||||
// },
|
||||
showLabels: true
|
||||
)
|
||||
);
|
||||
|
|
|
@ -140,7 +140,8 @@ class _TLThingyState extends State<TLThingy> {
|
|||
),
|
||||
],
|
||||
),
|
||||
if (currentTl.gamesPlayed >= 10 && currentTl.rd! < 100 && currentTl.nextAt >=0 && currentTl.prevAt >= 0)
|
||||
if (currentTl.gamesPlayed > 9)
|
||||
// if (currentTl.gamesPlayed >= 10 && currentTl.rd! < 100 && currentTl.nextAt >=0 && currentTl.prevAt >= 0)
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.all(8.0),
|
||||
// child: SfLinearGauge(
|
||||
|
@ -161,7 +162,7 @@ class _TLThingyState extends State<TLThingy> {
|
|||
// ),
|
||||
TLProgress(
|
||||
tr: currentTl.rating,
|
||||
rank: currentTl.rank,
|
||||
rank: currentTl.rank != "z" ? currentTl.rank : currentTl.percentileRank,
|
||||
position: currentTl.standing,
|
||||
nextRankPosition: currentTl.nextAt,
|
||||
previousRankPosition: currentTl.prevAt,
|
||||
|
|
|
@ -866,6 +866,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
syncfusion_flutter_charts:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: syncfusion_flutter_charts
|
||||
sha256: ab73109c586f5ec2b01adc2672026a1fb3f93b2b5f6061ba8d7126c119061002
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "24.2.9"
|
||||
syncfusion_flutter_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -43,6 +43,7 @@ dependencies:
|
|||
flutter_markdown: ^0.6.18
|
||||
flutter_colorpicker: ^1.0.3
|
||||
go_router: ^13.0.0
|
||||
syncfusion_flutter_charts: ^24.2.9
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
Loading…
Reference in New Issue