💄 Better graph card
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:fl_chart/fl_chart.dart';
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:latext/latext.dart';
|
||||||
import 'package:simple_math_calc/parser.dart';
|
import 'package:simple_math_calc/parser.dart';
|
||||||
import 'package:simple_math_calc/calculator.dart';
|
import 'package:simple_math_calc/calculator.dart';
|
||||||
import 'package:simple_math_calc/solver.dart';
|
import 'package:simple_math_calc/solver.dart';
|
||||||
@@ -25,6 +27,7 @@ class GraphCard extends StatefulWidget {
|
|||||||
|
|
||||||
class _GraphCardState extends State<GraphCard> {
|
class _GraphCardState extends State<GraphCard> {
|
||||||
final SolverService _solverService = SolverService();
|
final SolverService _solverService = SolverService();
|
||||||
|
FlSpot? _currentTouchedPoint;
|
||||||
|
|
||||||
/// 生成函数图表的点
|
/// 生成函数图表的点
|
||||||
List<FlSpot> _generatePlotPoints(String expression, double zoomFactor) {
|
List<FlSpot> _generatePlotPoints(String expression, double zoomFactor) {
|
||||||
@@ -145,6 +148,19 @@ class _GraphCardState extends State<GraphCard> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _formatAxisValue(double value) {
|
||||||
|
if (value.abs() < 1e-10) return "0";
|
||||||
|
if ((value - value.roundToDouble()).abs() < 1e-10) {
|
||||||
|
return value.round().toString();
|
||||||
|
}
|
||||||
|
double absVal = value.abs();
|
||||||
|
if (absVal >= 100) return value.toStringAsFixed(0);
|
||||||
|
if (absVal >= 10) return value.toStringAsFixed(1);
|
||||||
|
if (absVal >= 1) return value.toStringAsFixed(2);
|
||||||
|
if (absVal >= 0.1) return value.toStringAsFixed(3);
|
||||||
|
return value.toStringAsFixed(4);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListView(
|
return ListView(
|
||||||
@@ -212,23 +228,53 @@ class _GraphCardState extends State<GraphCard> {
|
|||||||
leftTitles: AxisTitles(
|
leftTitles: AxisTitles(
|
||||||
sideTitles: SideTitles(
|
sideTitles: SideTitles(
|
||||||
showTitles: true,
|
showTitles: true,
|
||||||
reservedSize: 80,
|
reservedSize: 60,
|
||||||
|
interval: (bounds.maxY - bounds.minY) / 8,
|
||||||
getTitlesWidget: (value, meta) =>
|
getTitlesWidget: (value, meta) =>
|
||||||
SideTitleWidget(
|
SideTitleWidget(
|
||||||
axisSide: meta.axisSide,
|
axisSide: meta.axisSide,
|
||||||
child: Text(value.toStringAsFixed(2)),
|
child: Text(
|
||||||
|
_formatAxisValue(value),
|
||||||
|
style: GoogleFonts.robotoFlex(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
bottomTitles: AxisTitles(
|
bottomTitles: AxisTitles(
|
||||||
sideTitles: SideTitles(
|
sideTitles: SideTitles(
|
||||||
showTitles: true,
|
showTitles: true,
|
||||||
reservedSize: 24,
|
reservedSize: 80,
|
||||||
getTitlesWidget: (value, meta) =>
|
interval: (bounds.maxX - bounds.minX) / 10,
|
||||||
SideTitleWidget(
|
getTitlesWidget: (value, meta) => SideTitleWidget(
|
||||||
axisSide: meta.axisSide,
|
axisSide: meta.axisSide,
|
||||||
child: Text(value.toStringAsFixed(2)),
|
child: Column(
|
||||||
),
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: _formatAxisValue(value)
|
||||||
|
.split('')
|
||||||
|
.map(
|
||||||
|
(char) => ['-', '.'].contains(char)
|
||||||
|
? Transform.rotate(
|
||||||
|
angle: pi / 2,
|
||||||
|
child: Text(
|
||||||
|
char,
|
||||||
|
style:
|
||||||
|
GoogleFonts.robotoFlex(
|
||||||
|
height: char == '.'
|
||||||
|
? 0.7
|
||||||
|
: 0.9,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Text(
|
||||||
|
char,
|
||||||
|
style: GoogleFonts.robotoFlex(
|
||||||
|
height: 0.9,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
topTitles: AxisTitles(
|
topTitles: AxisTitles(
|
||||||
@@ -246,6 +292,17 @@ class _GraphCardState extends State<GraphCard> {
|
|||||||
),
|
),
|
||||||
lineTouchData: LineTouchData(
|
lineTouchData: LineTouchData(
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
touchCallback: (event, response) {
|
||||||
|
if (response != null &&
|
||||||
|
response.lineBarSpots != null &&
|
||||||
|
response.lineBarSpots!.isNotEmpty) {
|
||||||
|
setState(() {
|
||||||
|
_currentTouchedPoint =
|
||||||
|
response.lineBarSpots!.first;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Keep the last touched point visible
|
||||||
|
},
|
||||||
touchTooltipData: LineTouchTooltipData(
|
touchTooltipData: LineTouchTooltipData(
|
||||||
getTooltipItems: (touchedSpots) {
|
getTooltipItems: (touchedSpots) {
|
||||||
return touchedSpots.map((spot) {
|
return touchedSpots.map((spot) {
|
||||||
@@ -276,6 +333,28 @@ class _GraphCardState extends State<GraphCard> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (_currentTouchedPoint != null)
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.only(top: 16),
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.surfaceContainerHighest,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
LaTexT(
|
||||||
|
laTeXCode: Text(
|
||||||
|
'\$\$x = ${_currentTouchedPoint!.x.toStringAsFixed(4)},\\quad y = ${_currentTouchedPoint!.y.toStringAsFixed(4)}\$\$',
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Reference in New Issue
Block a user