make graphs scalable to handle values greater than the heigh of the canvas
This commit is contained in:
parent
0b2caaaf87
commit
0cdb3db45f
@ -34,38 +34,40 @@ class MyHomePage extends StatefulWidget {
|
|||||||
class _MyHomePageState extends State<MyHomePage> {
|
class _MyHomePageState extends State<MyHomePage> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final stream = getDataStream().asBroadcastStream();
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(widget.title),
|
title: Text(widget.title),
|
||||||
),
|
),
|
||||||
body: Column(
|
body: SizedBox(
|
||||||
children: [
|
width: double.maxFinite,
|
||||||
Flexible(
|
child: Column(
|
||||||
child: Container(
|
children: [
|
||||||
color: Colors.red,
|
Expanded(
|
||||||
width: MediaQuery.of(context).size.width,
|
child: Container(
|
||||||
height: MediaQuery.of(context).size.width,
|
color: Colors.green,
|
||||||
child: RealTimeGraph(
|
child: RealTimeGraph(
|
||||||
stream: getDataStream(),
|
stream: stream,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(
|
||||||
const SizedBox(
|
height: 32,
|
||||||
height: 32,
|
child: Divider(color: Colors.grey,),
|
||||||
),
|
),
|
||||||
Flexible(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.red,
|
color: Colors.green,
|
||||||
width: MediaQuery.of(context).size.width,
|
child: RealTimeGraph(
|
||||||
height: MediaQuery.of(context).size.width,
|
stream: stream,
|
||||||
child: RealTimeGraph(
|
displayMode: ChartDisplay.points,
|
||||||
stream: getDataStream(),
|
),
|
||||||
displayMode: ChartDisplay.points,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -75,7 +77,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
|
|
||||||
Stream<double> getDataStream() {
|
Stream<double> getDataStream() {
|
||||||
return Stream.periodic(const Duration(milliseconds: 500), (_) {
|
return Stream.periodic(const Duration(milliseconds: 500), (_) {
|
||||||
return Random().nextInt(300).toDouble();
|
return Random().nextInt(500).toDouble();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:ui';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
@ -73,9 +73,9 @@ class RealTimeGraphState extends State<RealTimeGraph>
|
|||||||
width: constraints.maxHeight,
|
width: constraints.maxHeight,
|
||||||
child: CustomPaint(
|
child: CustomPaint(
|
||||||
painter: widget.displayMode == ChartDisplay.points
|
painter: widget.displayMode == ChartDisplay.points
|
||||||
? _PointsGraphPainter(
|
? _PointGraphPainter(
|
||||||
data: _data,
|
data: _data,
|
||||||
pointsSpacing: widget.pointsSpacing,
|
pointSpacing: 3,
|
||||||
)
|
)
|
||||||
: _LineGraphPainter(
|
: _LineGraphPainter(
|
||||||
data: _data,
|
data: _data,
|
||||||
@ -100,47 +100,64 @@ class RealTimeGraphState extends State<RealTimeGraph>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PointsGraphPainter extends CustomPainter {
|
class _PointGraphPainter extends CustomPainter {
|
||||||
final List<Point<double>> data;
|
final List<Point<double>> data;
|
||||||
|
final double pointSpacing;
|
||||||
|
|
||||||
_PointsGraphPainter({
|
_PointGraphPainter({required this.data, required this.pointSpacing});
|
||||||
required this.data,
|
|
||||||
required this.pointsSpacing,
|
|
||||||
});
|
|
||||||
|
|
||||||
final double pointsSpacing;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
final paint = Paint()
|
final paint = Paint()
|
||||||
..style = PaintingStyle.stroke
|
..style = PaintingStyle.fill
|
||||||
..strokeWidth = 1.5
|
..strokeWidth = 1.5
|
||||||
..color = Colors.white;
|
..color = Colors.white;
|
||||||
|
|
||||||
|
// Find the maximum y value in the data
|
||||||
|
double maxY = 0;
|
||||||
|
|
||||||
|
// Calculate the scaling factor for the y values
|
||||||
|
double yScale = 1;
|
||||||
|
|
||||||
// Iterate over the data points and add intermediate points if necessary
|
// Iterate over the data points and add intermediate points if necessary
|
||||||
|
if (data.isNotEmpty) {
|
||||||
|
maxY = data.map((point) => point.y).reduce(max);
|
||||||
|
yScale = (maxY > size.height) ? (size.height / maxY) : 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < data.length - 1; i++) {
|
for (int i = 0; i < data.length - 1; i++) {
|
||||||
final y1 = size.height - data[i].y;
|
double y1 = data[i].y * yScale;
|
||||||
final x1 = data[i].x + size.width;
|
double x1 = data[i].x + size.width;
|
||||||
final y2 = size.height - data[i + 1].y;
|
double y2 = data[i + 1].y * yScale;
|
||||||
final x2 = data[i + 1].x + size.width;
|
double x2 = data[i + 1].x + size.width;
|
||||||
final yDiff = (y2 - y1).abs();
|
double yDiff = (y2 - y1).abs();
|
||||||
|
|
||||||
// If the difference in y values is small, add intermediate points
|
// If the difference in y values is small, add intermediate points
|
||||||
if (yDiff >= pointsSpacing) {
|
if (yDiff >= pointSpacing) {
|
||||||
int numOfIntermediatePoints = (yDiff / pointsSpacing).round();
|
int numOfIntermediatePoints = (yDiff / pointSpacing).round();
|
||||||
final yInterval = (y2 - y1) / numOfIntermediatePoints;
|
double yInterval = (y2 - y1) / numOfIntermediatePoints;
|
||||||
final xInterval = (x2 - x1) / numOfIntermediatePoints;
|
double xInterval = (x2 - x1) / numOfIntermediatePoints;
|
||||||
for (int j = 0; j <= numOfIntermediatePoints; j++) {
|
for (int j = 0; j <= numOfIntermediatePoints; j++) {
|
||||||
final intermediateY = y1 + yInterval * j;
|
double intermediateY = y1 + yInterval * j;
|
||||||
final intermediateX = x1 + xInterval * j;
|
double intermediateX = x1 + xInterval * j;
|
||||||
canvas.drawPoints(
|
canvas.drawCircle(
|
||||||
PointMode.points,
|
Offset(intermediateX, size.height - intermediateY),
|
||||||
[Offset(intermediateX, intermediateY)],
|
1,
|
||||||
paint,
|
paint,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
canvas.drawCircle(
|
||||||
|
Offset(x1, size.height - y1),
|
||||||
|
1,
|
||||||
|
paint,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
canvas.drawCircle(
|
||||||
|
Offset(data.last.x + size.width, size.height - data.last.y * yScale),
|
||||||
|
1,
|
||||||
|
paint,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -159,16 +176,28 @@ class _LineGraphPainter extends CustomPainter {
|
|||||||
..strokeWidth = 1.5
|
..strokeWidth = 1.5
|
||||||
..color = Colors.white;
|
..color = Colors.white;
|
||||||
Path path = Path();
|
Path path = Path();
|
||||||
|
// Find the maximum y value in the data
|
||||||
|
double maxY = 0;
|
||||||
|
|
||||||
|
// Calculate the scaling factor for the y values
|
||||||
|
double yScale = 1;
|
||||||
|
|
||||||
// Iterate over the data points and add intermediate points if necessary
|
// Iterate over the data points and add intermediate points if necessary
|
||||||
if (data.isNotEmpty) {
|
if (data.isNotEmpty) {
|
||||||
path.moveTo(data.first.x + size.width, size.height - data.first.y);
|
maxY = data.map((point) => point.y).reduce(max);
|
||||||
|
yScale = (maxY > size.height) ? (size.height / maxY) : 1;
|
||||||
|
path.moveTo(
|
||||||
|
data.first.x + size.width,
|
||||||
|
(size.height - data.first.y * yScale),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < data.length - 1; i++) {
|
for (int i = 0; i < data.length - 1; i++) {
|
||||||
double y = size.height - data[i].y;
|
double y = data[i + 1].y * yScale;
|
||||||
double x = data[i].x + size.width;
|
double x = data[i + 1].x + size.width;
|
||||||
path.lineTo(x, y);
|
|
||||||
|
path.lineTo(x, size.height - y);
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.drawPath(path, paint);
|
canvas.drawPath(path, paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user