Files
fl_chart/example/lib/presentation/samples/scatter/scatter_chart_sample2.dart
zypherift c7e3f36b06
Some checks failed
Code Coverage / upload (push) Has been cancelled
Gh-Pages / build (push) Has been cancelled
Code Verification / verify (push) Has been cancelled
1.0.0
2025-08-09 18:17:34 +02:00

239 lines
7.8 KiB
Dart

import 'dart:math';
import 'package:fl_chart_app/presentation/resources/app_resources.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
class ScatterChartSample2 extends StatefulWidget {
const ScatterChartSample2({super.key});
@override
State<StatefulWidget> createState() => _ScatterChartSample2State();
}
class _ScatterChartSample2State extends State {
int touchedIndex = -1;
Color greyColor = Colors.grey;
final _availableColors = [
AppColors.contentColorGreen,
AppColors.contentColorYellow,
AppColors.contentColorPink,
AppColors.contentColorOrange,
AppColors.contentColorPurple,
AppColors.contentColorBlue,
AppColors.contentColorRed,
AppColors.contentColorCyan,
AppColors.contentColorBlue,
AppColors.contentColorGreen,
AppColors.contentColorPink,
];
List<int> selectedSpots = [];
PainterType _currentPaintType = PainterType.circle;
static FlDotPainter _getPaint(PainterType type, double size, Color color) {
switch (type) {
case PainterType.circle:
return FlDotCirclePainter(
color: color,
radius: size,
);
case PainterType.square:
return FlDotSquarePainter(
color: color,
size: size * 2,
strokeWidth: 0,
);
case PainterType.cross:
return FlDotCrossPainter(
color: color,
size: size * 2,
width: max(size / 5, 2),
);
}
}
@override
Widget build(BuildContext context) {
// (x, y, size)
final data = [
(4.0, 4.0, 4.0),
(2.0, 5.0, 12.0),
(4.0, 5.0, 8.0),
(8.0, 6.0, 20.0),
(5.0, 7.0, 14.0),
(7.0, 2.0, 18.0),
(3.0, 2.0, 36.0),
(2.0, 8.0, 22.0),
(8.0, 8.0, 32.0),
(5.0, 2.5, 24.0),
(3.0, 7.0, 18.0),
];
return AspectRatio(
aspectRatio: 1,
child: Stack(
children: [
ScatterChart(
ScatterChartData(
scatterSpots: data.asMap().entries.map((e) {
final index = e.key;
final (double x, double y, double size) = e.value;
return ScatterSpot(
x,
y,
dotPainter: _getPaint(
_currentPaintType,
size,
selectedSpots.contains(index)
? _availableColors[index % _availableColors.length]
: AppColors.contentColorWhite.withValues(alpha: 0.5),
),
);
}).toList(),
minX: 0,
maxX: 10,
minY: 0,
maxY: 10,
borderData: FlBorderData(
show: false,
),
gridData: FlGridData(
show: true,
drawHorizontalLine: true,
checkToShowHorizontalLine: (value) => true,
getDrawingHorizontalLine: (value) => const FlLine(
color: AppColors.gridLinesColor,
),
drawVerticalLine: true,
checkToShowVerticalLine: (value) => true,
getDrawingVerticalLine: (value) => const FlLine(
color: AppColors.gridLinesColor,
),
),
titlesData: const FlTitlesData(
show: false,
),
showingTooltipIndicators: selectedSpots,
scatterTouchData: ScatterTouchData(
enabled: true,
handleBuiltInTouches: false,
mouseCursorResolver:
(FlTouchEvent touchEvent, ScatterTouchResponse? response) {
return response == null || response.touchedSpot == null
? MouseCursor.defer
: SystemMouseCursors.click;
},
touchTooltipData: ScatterTouchTooltipData(
getTooltipColor: (ScatterSpot touchedBarSpot) {
return touchedBarSpot.dotPainter.mainColor;
},
getTooltipItems: (ScatterSpot touchedBarSpot) {
final bool isBgDark =
switch ((touchedBarSpot.x, touchedBarSpot.y)) {
(4.0, 4.0) => false,
(2.0, 5.0) => false,
(4.0, 5.0) => true,
(8.0, 6.0) => true,
(5.0, 7.0) => true,
(7.0, 2.0) => true,
(3.0, 2.0) => true,
(2.0, 8.0) => false,
(8.0, 8.0) => true,
(5.0, 2.5) => false,
(3.0, 7.0) => true,
_ => false,
};
final color1 = isBgDark ? Colors.grey[100] : Colors.black87;
final color2 = isBgDark ? Colors.white : Colors.black;
return ScatterTooltipItem(
'X: ',
textStyle: TextStyle(
height: 1.2,
color: color1,
fontStyle: FontStyle.italic,
),
bottomMargin: 10,
children: [
TextSpan(
text: '${touchedBarSpot.x.toInt()} \n',
style: TextStyle(
color: color2,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.bold,
),
),
TextSpan(
text: 'Y: ',
style: TextStyle(
height: 1.2,
color: color1,
fontStyle: FontStyle.italic,
),
),
TextSpan(
text: touchedBarSpot.y.toInt().toString(),
style: TextStyle(
color: color2,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.bold,
),
),
],
);
},
),
touchCallback:
(FlTouchEvent event, ScatterTouchResponse? touchResponse) {
if (touchResponse == null ||
touchResponse.touchedSpot == null) {
return;
}
if (event is FlTapUpEvent) {
final sectionIndex = touchResponse.touchedSpot!.spotIndex;
setState(() {
if (selectedSpots.contains(sectionIndex)) {
selectedSpots.remove(sectionIndex);
} else {
selectedSpots.add(sectionIndex);
}
});
}
},
),
),
),
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: DropdownButton(
value: _currentPaintType,
items: PainterType.values
.map((e) => DropdownMenuItem(
value: e,
child: Text(e.name),
))
.toList(),
onChanged: (PainterType? value) {
setState(() {
_currentPaintType = value!;
});
},
),
),
),
],
),
);
}
}
enum PainterType {
circle,
square,
cross,
}