123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- import 'dart:math';
- import 'dart:ui' as ui;
- import 'package:flutter/material.dart';
- import 'package:sport/pages/run/run_page.dart';
- class RunChart extends StatelessWidget {
- final List<double> values;
- final bool gradient;
- const RunChart({Key? key, required this.values, required this.gradient}) : super(key: key);
- @override
- Widget build(BuildContext context) {
- return Padding(
- padding: const EdgeInsets.only(top: 24.0),
- child: CustomPaint(
- painter: _Chart(values: this.values, gradient: this.gradient),
- child: Container(
- height: 150.0,
- ),
- ),
- );
- }
- }
- class _Chart extends CustomPainter {
- final List<double> values;
- final bool gradient;
- _Chart({
- required this.values,
- this.gradient = false,
- });
- final Paint _paint = Paint()
- ..color = const Color(0xffDCDCDC)
- ..strokeWidth = 0.5
- ..isAntiAlias = true;
- final Paint _dataPaint = Paint()
- ..color = const Color(0xffFFC400)
- ..strokeWidth = 2
- ..style = PaintingStyle.stroke
- ..isAntiAlias = true;
- final ui.ParagraphStyle _valueStyle = ui.ParagraphStyle(
- textAlign: TextAlign.right,
- fontSize: 8,
- );
- final ui.ParagraphStyle _labelStyle = ui.ParagraphStyle(
- textAlign: TextAlign.left,
- fontSize: 8,
- );
- final Path path = Path();
- double _zero = 0;
- double _max = 0;
- double _min = 0;
- double _paddingLeft = 30;
- double _paddingRight = 10;
- double _labelHeight = 30;
- double _total = 0;
- @override
- void paint(Canvas canvas, Size size) {
- double zero = _zero = size.height - _labelHeight;
- double zeroX = _paddingLeft;
- if (values.isEmpty == true) {
- _min = 0;
- _max = 100;
- } else {
- _max = 0;
- values.forEach((element) {
- _max = max(_max, element);
- _min = min(_min, element);
- });
- _max = _min.abs() + _max.abs();
- }
- int count = 4;
- double split = _max / count;
- int length = split.round().toString().length;
- int one = int.parse("1" + List.filled(max(0, length - 2), 0).join(""));
- int p = one;
- while (p < split) {
- p += one;
- }
- // print("max $max $p $split");
- List<double> yAxis = List.generate(count + 1, (index) => _min + index * p.toDouble());
- // print("1111111111111111 values = $values $_max $split $length $p $yAxis");
- // print("1111111111111111 max = $_max $split $length $p $yAxis");
- _total = _min < 0 ? yAxis.last * 2 : yAxis.last;
- // draw 值 行数
- int valuePadding = 10;
- // ui.ParagraphBuilder pb = ui.ParagraphBuilder(_valueStyle)
- // ..pushStyle(ui.TextStyle(color: Color(0xff999999)))
- // ..addText("0");
- // ui.ParagraphConstraints constraints = ui.ParagraphConstraints(width: _paddingLeft - valuePadding);
- // ui.Paragraph paragraph = pb.build()..layout(constraints);
- // paragraph.computeLineMetrics().forEach((element) {
- // canvas.drawParagraph(paragraph, Offset(0, zero - element.baseline / 2));
- // });
- // canvas.drawLine(Offset(zeroX, zero), Offset(size.width, zero), _paint);
- canvas.drawLine(Offset(zeroX, zero), Offset(zeroX, 0), _paint);
- double rowHeight = zero / (yAxis.length - 1);
- // double valueSpace = (size.height - _labelHeight) / valueSize;
- // print("11111111111111 height ${size.height} $_labelHeight ${size.height - _labelHeight}");
- for (var i = 0; i < yAxis.length; i++) {
- // canvas.drawLine(Offset(_paddingLeft, valueSpace * i), Offset(size.width, valueSpace * i), _paint);
- double dy = zero - i * rowHeight;
- var value = yAxis[i];
- var label = value.toInt();
- if (i == 0) canvas.drawLine(Offset(zeroX, dy), Offset(size.width, dy), _paint);
- // print("11111111111111 value ${(_total) ~/ valueSize} ${(valueSize - i)} $value i $i y $y ${i * (_total) ~/ valueSize}");
- ui.ParagraphBuilder pb = ui.ParagraphBuilder(_valueStyle)
- ..pushStyle(ui.TextStyle(color: Color(0xff999999)))
- ..addText(label.abs() < 1000 ? "$label" : "${formatNum(label / 1000, 1)}k");
- ui.ParagraphConstraints constraints = ui.ParagraphConstraints(width: _paddingLeft - valuePadding);
- ui.Paragraph paragraph = pb.build()..layout(constraints);
- paragraph.computeLineMetrics().forEach((element) {
- canvas.drawParagraph(paragraph, Offset(0, dy - element.baseline / 2));
- });
- }
- if (values.length > 0) {
- int orgLength = values.length;
- int difflength = orgLength % 10;
- int length = max(orgLength, orgLength - difflength + (difflength == 0 ? 0 : 10));
- // print("222222222222222222 $orgLength $length $difflength");
- int maxGrid = length ~/ 10;
- final int grid = max(maxGrid, length ~/ maxGrid);
- double preY = calValue(values[0] + (_min < 0 ? _max : 0));
- double _x = zeroX;
- double preX = _x;
- path.reset();
- if (this.gradient == true) {
- path.moveTo(_x, zero);
- path.lineTo(_x, preY);
- } else {
- path.moveTo(_x, preY);
- }
- // path.moveTo(preX, preY);
- double space = (size.width - _x) / length;
- for (int i = 1; i < values.length; i++) {
- int index = i + 1;
- double x = _x + index * space;
- // if (index % grid == 0 || index == values.length) {
- double y = calValue(values[i] + (_min < 0 ? _max : 0));
- // print("11111111111111 y $y $preY ${values[i]} zero: $zero");
- double controlX = (preX + x) / 2;
- path.cubicTo(controlX, preY, controlX, y, x, y);
- // path.lineTo(x, y);
- //
- // path.lineTo(x, y);
- preX = x;
- preY = y;
- // }
- if (index % grid == 0) {
- ui.ParagraphBuilder pb = ui.ParagraphBuilder(_labelStyle)
- ..pushStyle(ui.TextStyle(color: const Color(0xff999999)))
- ..addText("$index");
- ui.ParagraphConstraints constraints = ui.ParagraphConstraints(width: 20.0);
- ui.Paragraph paragraph = pb.build()..layout(constraints);
- paragraph.computeLineMetrics().forEach((element) {
- var lx = x - element.width / 2;
- var y = zero + 5;
- canvas.drawParagraph(paragraph, Offset(lx, y));
- // canvas.drawLine(Offset(x, zero), Offset(x, 0), _paint);
- });
- }
- }
- if (values.length % grid != 0) {
- ui.ParagraphBuilder pb = ui.ParagraphBuilder(_labelStyle)
- ..pushStyle(ui.TextStyle(color: const Color(0xff999999)))
- ..addText("${values.length + grid - values.length % grid}");
- ui.ParagraphConstraints constraints = ui.ParagraphConstraints(width: 20.0);
- ui.Paragraph paragraph = pb.build()..layout(constraints);
- paragraph.computeLineMetrics().forEach((element) {
- var x = size.width - element.width / 2;
- var y = zero + 5;
- canvas.drawParagraph(paragraph, Offset(x, y));
- // canvas.drawLine(Offset(size.width, zero), Offset(size.width, 0), _paint);
- });
- }
- if (this.gradient == true) {
- double x = preX;
- double y = zero;
- double controlX = (preX + x) / 2;
- path.cubicTo(controlX, preY, controlX, y, x, y);
- Paint valuePaint = Paint()
- ..shader = LinearGradient(
- begin: Alignment.bottomCenter,
- end: Alignment.topCenter,
- colors: <Color>[Color(0x30FFC400), Color(0xccFFC400)],
- ).createShader(path.getBounds());
- canvas.drawPath(path, valuePaint);
- } else {
- canvas.drawPath(path, _dataPaint);
- }
- }
- }
- @override
- bool shouldRepaint(_Chart oldDelegate) => false;
- double calValue(num value) {
- if (value == null) return _zero;
- if (_total == 0) return _zero;
- return max(0, _zero - _zero * value / _total);
- }
- }
|