丈夫志四海,万里犹比邻。——曹植
绘制范围(x、y轴最大或最小偏移量)
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo Chart',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Chart Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Container(
color: Colors.white.withOpacity(0.4),
child: CustomPaint(
size: Size(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height / 2),
painter: CharLinePainter(),
),
),
);
}
}
初始化边界
class CharLinePainter extends CustomPainter {
static const double basePadding = 16;//基础边界
double startX, endX;//相对于原点x轴方向最小和最大偏移量(相对于原点的偏移量)
double startY, endY;//相对于原点y轴方向最大和最小偏移量(相对于原点的偏移量)
double _fixedWidth;//x轴方向:最大偏移量-最小偏移量(相对于原点的偏移量)
double _fixedHeight;//y轴方向:最大偏移量-最小偏移量(相对于原点的偏移量)
@override
void paint(Canvas canvas, Size size) {
_initBorder(size);
}
/// 初始化边界
void _initBorder(Size size) {
startX = basePadding * 2;
endX = size.width - basePadding * 2;
startY = size.height - basePadding * 2;
endY = basePadding * 2;
_fixedWidth = endX - startX;
_fixedHeight = startY - endY;
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
绘制xy轴
class CharLinePainter extends CustomPainter {
static const double basePadding = 16;//基础边界
double startX, endX;//相对于原点x轴方向最小和最大偏移量(相对于原点的偏移量)
double startY, endY;//相对于原点y轴方向最大和最小偏移量(相对于原点的偏移量)
double _fixedWidth;//x轴方向:最大偏移量-最小偏移量(相对于原点的偏移量)
double _fixedHeight;//y轴方向:最大偏移量-最小偏移量(相对于原点的偏移量)
@override
void paint(Canvas canvas, Size size) {
_initBorder(size);
_drawXy(canvas);
}
/// 初始化边界
void _initBorder(Size size) {
startX = basePadding * 2;
endX = size.width - basePadding * 2;
startY = size.height - basePadding * 2;
endY = basePadding * 2;
_fixedWidth = endX - startX;
_fixedHeight = startY - endY;
}
///绘制xy轴
///绘制x轴-y轴偏移量不变(y轴坐标点不变)
///绘制y轴-x轴偏移量不变(x轴坐标点不变)
void _drawXy(Canvas canvas){
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 1.0
..strokeCap = StrokeCap.square
..color = Colors.white
..style = PaintingStyle.stroke;
canvas.drawLine(Offset(startX, startY), Offset(endX , startY), paint); //x轴
canvas.drawLine(Offset(startX, startY), Offset(startX, endY), paint); //y轴
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
绘制xy刻度
class CharLinePainter extends CustomPainter {
static const double basePadding = 16;//基础边界
double startX, endX;//相对于原点x轴方向最小和最大偏移量(相对于原点的偏移量)
double startY, endY;//相对于原点y轴方向最大和最小偏移量(相对于原点的偏移量)
double _fixedWidth;//x轴方向:最大偏移量-最小偏移量(相对于原点的偏移量)
double _fixedHeight;//y轴方向:最大偏移量-最小偏移量(相对于原点的偏移量)
@override
void paint(Canvas canvas, Size size) {
_initBorder(size);
_drawXy(canvas);
_drawXRuler(canvas);
}
/// 初始化边界
void _initBorder(Size size) {
startX = basePadding * 2;
endX = size.width - basePadding * 2;
startY = size.height - basePadding * 2;
endY = basePadding * 2;
_fixedWidth = endX - startX;
_fixedHeight = startY - endY;
}
///绘制xy轴
///绘制x轴-y轴偏移量不变(y轴坐标点不变)
///绘制y轴-x轴偏移量不变(x轴坐标点不变)
void _drawXy(Canvas canvas){
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 1.0
..strokeCap = StrokeCap.square
..color = Colors.white
..style = PaintingStyle.stroke;
canvas.drawLine(Offset(startX, startY), Offset(endX , startY), paint); //x轴
canvas.drawLine(Offset(startX, startY), Offset(startX, endY), paint); //y轴
}
///绘制x轴刻度
void _drawXRuler(Canvas canvas){
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 1.0
..strokeCap = StrokeCap.square
..color = Colors.white
..style = PaintingStyle.stroke;
///临时刻度数量
int rulerCount=16;
///x、y轴方向每个刻度的间距
double xRulerW = _fixedWidth /rulerCount; //x方向两个点之间的距离(刻度长)
double yRulerH=_fixedHeight/rulerCount;//y轴方向亮点之间的距离(刻度高)
for (int i = 1; i <=rulerCount; i++) {
canvas.drawLine(Offset(startX + xRulerW * i, startY), Offset(startX + xRulerW * i, startY - yRulerH), paint);
canvas.drawLine(Offset(startX, startY-i*yRulerH), Offset(startX + xRulerW, startY-i*yRulerH), paint);
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
调整刻度线高度或长度
///绘制x轴刻度
void _drawXRuler(Canvas canvas) {
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 1.0
..strokeCap = StrokeCap.square
..color = Colors.white
..style = PaintingStyle.stroke;
///临时刻度数量
int rulerCount = 16;
///x、y轴方向每个刻度的间距
double xRulerW = _fixedWidth / rulerCount; //x方向两个点之间的距离(刻度长)
double yRulerH = _fixedHeight / rulerCount; //y轴方向亮点之间的距离(刻度高)
///减小刻度线高度或长度
double reduceRuler=10.0;
for (int i = 1; i <= rulerCount; i++) {
canvas.drawLine(Offset(startX + xRulerW * i, startY), Offset(startX + xRulerW * i, startY - yRulerH+reduceRuler), paint);
canvas.drawLine(Offset(startX, startY - i * yRulerH), Offset(startX + xRulerW-reduceRuler, startY - i * yRulerH), paint);
}
}
绘制xy刻度文本
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class CharLinePainter extends CustomPainter {
static const double basePadding = 16; //基础边界
double startX, endX; //相对于原点x轴方向最小和最大偏移量(相对于原点的偏移量)
double startY, endY; //相对于原点y轴方向最大和最小偏移量(相对于原点的偏移量)
double _fixedWidth; //x轴方向:最大偏移量-最小偏移量(相对于原点的偏移量)
double _fixedHeight; //y轴方向:最大偏移量-最小偏移量(相对于原点的偏移量)
@override
void paint(Canvas canvas, Size size) {
_initBorder(size);
_drawXy(canvas);
_drawXYRulerText(canvas);
}
/// 初始化边界
void _initBorder(Size size) {
startX = basePadding * 2;
endX = size.width - basePadding * 2;
startY = size.height - basePadding * 2;
endY = basePadding * 2;
_fixedWidth = endX - startX;
_fixedHeight = startY - endY;
}
///绘制xy轴
///绘制x轴-y轴偏移量不变(y轴坐标点不变)
///绘制y轴-x轴偏移量不变(x轴坐标点不变)
void _drawXy(Canvas canvas) {
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 1.0
..strokeCap = StrokeCap.square
..color = Colors.white
..style = PaintingStyle.stroke;
canvas.drawLine(Offset(startX, startY), Offset(endX, startY), paint); //x轴
canvas.drawLine(Offset(startX, startY), Offset(startX, endY), paint); //y轴
}
///绘制xy轴刻度+文本
void _drawXYRulerText(Canvas canvas) {
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 1.0
..strokeCap = StrokeCap.square
..color = Colors.white
..style = PaintingStyle.stroke;
///临时刻度数量
int rulerCount = 16;
///x、y轴方向每个刻度的间距
double xRulerW = _fixedWidth / rulerCount; //x方向两个点之间的距离(刻度长)
double yRulerH = _fixedHeight / rulerCount; //y轴方向亮点之间的距离(刻度高)
///减小刻度线高度或长度
double reduceRuler = 10.0;
for (int i = 1; i <= rulerCount; i++) {
_drawXRuler(canvas, xRulerW, yRulerH, reduceRuler, i, paint);
_drawYRuler(canvas, xRulerW, yRulerH, reduceRuler, i, paint);
_drawXText(canvas, xRulerW, i);
_drawYText(canvas, yRulerH, i);
}
}
///绘制x轴刻度
void _drawXRuler(Canvas canvas, double xRulerW, double yRulerH,
double reduceRuler, int i, var paint) {
double drawRulerSx = startX + xRulerW * i;
double drawRulerSy = startY;
double drawRulerEx = startX + xRulerW * i;
double drawRulerEy = startY - yRulerH + reduceRuler;
canvas.drawLine(Offset(drawRulerSx, drawRulerSy),
Offset(drawRulerEx, drawRulerEy), paint);
}
///绘制y轴刻度
void _drawYRuler(Canvas canvas, double xRulerW, double yRulerH,
double reduceRuler, int i, var paint) {
double drawRulerSx = startX;
double drawRulerSy = startY - i * yRulerH;
double drawRulerEx = startX + xRulerW - reduceRuler;
double drawRulerEy = startY - i * yRulerH;
canvas.drawLine(Offset(drawRulerSx, drawRulerSy),
Offset(drawRulerEx, drawRulerEy), paint);
}
///绘制x轴文本
void _drawXText(Canvas canvas,double xRulerW,int i) {
TextPainter(
textAlign: TextAlign.center,
ellipsis: '.',
text: TextSpan(
text: (i).toString(),
style: TextStyle(color: Colors.white, fontSize: 12.0)),
textDirection: TextDirection.ltr)
..layout(minWidth: xRulerW, maxWidth: xRulerW)
..paint(canvas, Offset(startX + xRulerW * (i - 1) - xRulerW / 2, startY+basePadding/2));
}
///绘制y轴文本
void _drawYText(Canvas canvas,double yRulerH,int i) {
TextPainter(
textAlign: TextAlign.center,
ellipsis: '.',
text: TextSpan(
text: (i-1).toString(),
style: TextStyle(color: Colors.white, fontSize: 12.0)),
textDirection: TextDirection.ltr)
..layout(minWidth: yRulerH, maxWidth: yRulerH)
..paint(canvas, Offset(startX-basePadding/2*3,startY - yRulerH * (i - 1) - yRulerH / 2));
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
绘制折线图
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class CharLinePainter extends CustomPainter {
static const double basePadding = 24; //基础边界
double startX, endX; //相对于原点x轴方向最小和最大偏移量(相对于原点的偏移量)
double startY, endY; //相对于原点y轴方向最大和最小偏移量(相对于原点的偏移量)
double _fixedWidth; //x轴方向:最大偏移量-最小偏移量(相对于原点的偏移量)
double _fixedHeight; //y轴方向:最大偏移量-最小偏移量(相对于原点的偏移量)
Path _path = new Path();
@override
void paint(Canvas canvas, Size size) {
_initBorder(size);
_drawXy(canvas);
_drawXYRulerText(canvas);
_drawLine(canvas);
}
/// 初始化边界
void _initBorder(Size size) {
startX = basePadding * 2;
endX = size.width - basePadding * 2;
startY = size.height - basePadding * 2;
endY = basePadding * 2;
_fixedWidth = endX - startX;
_fixedHeight = startY - endY;
}
///绘制xy轴
///绘制x轴-y轴偏移量不变(y轴坐标点不变)
///绘制y轴-x轴偏移量不变(x轴坐标点不变)
void _drawXy(Canvas canvas) {
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 1.0
..strokeCap = StrokeCap.square
..color = Colors.white
..style = PaintingStyle.stroke;
canvas.drawLine(Offset(startX, startY), Offset(endX, startY), paint); //x轴
canvas.drawLine(Offset(startX, startY), Offset(startX, endY), paint); //y轴
}
///绘制xy轴刻度+文本
void _drawXYRulerText(Canvas canvas) {
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 1.0
..strokeCap = StrokeCap.square
..color = Colors.white
..style = PaintingStyle.stroke;
///临时刻度数量
int rulerCount = 10;
///x、y轴方向每个刻度的间距
double xRulerW = _fixedWidth / rulerCount; //x方向两个点之间的距离(刻度长)
double yRulerH = _fixedHeight / rulerCount; //y轴方向亮点之间的距离(刻度高)
///减小刻度线高度或长度
double reduceRuler = 20.0;
for (int i = 1; i <= rulerCount; i++) {
_drawXRuler(canvas, xRulerW, yRulerH, reduceRuler, i, paint);
_drawYRuler(canvas, xRulerW, yRulerH, reduceRuler, i, paint);
_drawXText(canvas, xRulerW, i);
_drawYText(canvas, yRulerH, i);
_initPath(i-1, xRulerW, yRulerH);
}
}
///绘制x轴刻度
void _drawXRuler(Canvas canvas, double xRulerW, double yRulerH,
double reduceRuler, int i, var paint) {
double drawRulerSx = startX + xRulerW * i;
double drawRulerSy = startY;
double drawRulerEx = startX + xRulerW * i;
double drawRulerEy = startY - yRulerH + reduceRuler;
canvas.drawLine(Offset(drawRulerSx, drawRulerSy),
Offset(drawRulerEx, drawRulerEy), paint);
}
///绘制y轴刻度
void _drawYRuler(Canvas canvas, double xRulerW, double yRulerH,
double reduceRuler, int i, var paint) {
double drawRulerSx = startX;
double drawRulerSy = startY - i * yRulerH;
double drawRulerEx = startX + xRulerW - reduceRuler;
double drawRulerEy = startY - i * yRulerH;
canvas.drawLine(Offset(drawRulerSx, drawRulerSy),
Offset(drawRulerEx, drawRulerEy), paint);
}
///绘制x轴文本
void _drawXText(Canvas canvas, double xRulerW, int i) {
TextPainter(
textAlign: TextAlign.center,
ellipsis: '.',
text: TextSpan(
text: ((i - 1) * xRulerW).toString(),
style: TextStyle(color: Colors.white, fontSize: 9.0)),
textDirection: TextDirection.ltr)
..layout(minWidth: xRulerW, maxWidth: xRulerW)
..paint(
canvas,
Offset(startX + xRulerW * (i - 1) - xRulerW / 2,
startY + basePadding / 2));
}
///绘制y轴文本
void _drawYText(Canvas canvas, double yRulerH, int i) {
TextPainter(
textAlign: TextAlign.center,
ellipsis: '.',
text: TextSpan(
text: ((i - 1) * yRulerH).toString(),
style: TextStyle(color: Colors.white, fontSize: 9.0)),
textDirection: TextDirection.ltr)
..layout(minWidth: yRulerH, maxWidth: yRulerH)
..paint(
canvas,
Offset(startX - basePadding / 2 * 3,
startY - yRulerH * (i - 1) - yRulerH / 2));
}
///计算path
void _initPath(int i, double xRulerW, double yRulerH) {
if (i == 0) {
var key = startX;
var value = startY;
_path.moveTo(key, value);
} else {
double currentX = startX + xRulerW * i;
double currentY = (startY - (i%2==0?yRulerH:yRulerH*4));
_path.lineTo(currentX, currentY);
}
}
///绘制直线
void _drawLine(canvas) {
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 2.0
..strokeCap = StrokeCap.round
..color = Colors.red
..style = PaintingStyle.stroke;
var pathMetrics = _path.computeMetrics(forceClosed: false);
var list = pathMetrics.toList();
var length = list.length.toInt();
Path linePath = new Path();
for (int i = 0; i < length; i++) {
var extractPath = list[i].extractPath(0, list[i].length, startWithMoveTo: true);
linePath.addPath(extractPath, Offset(0, 0));
}
canvas.drawPath(linePath, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
绘制曲线图
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class CharLinePainter extends CustomPainter {
static const double basePadding = 24; //基础边界
double startX, endX; //相对于原点x轴方向最小和最大偏移量(相对于原点的偏移量)
double startY, endY; //相对于原点y轴方向最大和最小偏移量(相对于原点的偏移量)
double _fixedWidth; //x轴方向:最大偏移量-最小偏移量(相对于原点的偏移量)
double _fixedHeight; //y轴方向:最大偏移量-最小偏移量(相对于原点的偏移量)
Path _path = new Path();
@override
void paint(Canvas canvas, Size size) {
_initBorder(size);
_drawXy(canvas);
_drawXYRulerText(canvas);
_drawLine(canvas);
}
/// 初始化边界
void _initBorder(Size size) {
startX = basePadding * 2;
endX = size.width - basePadding * 2;
startY = size.height - basePadding * 2;
endY = basePadding * 2;
_fixedWidth = endX - startX;
_fixedHeight = startY - endY;
}
///绘制xy轴
///绘制x轴-y轴偏移量不变(y轴坐标点不变)
///绘制y轴-x轴偏移量不变(x轴坐标点不变)
void _drawXy(Canvas canvas) {
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 1.0
..strokeCap = StrokeCap.square
..color = Colors.white
..style = PaintingStyle.stroke;
canvas.drawLine(Offset(startX, startY), Offset(endX, startY), paint); //x轴
canvas.drawLine(Offset(startX, startY), Offset(startX, endY), paint); //y轴
}
///绘制xy轴刻度+文本
void _drawXYRulerText(Canvas canvas) {
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 1.0
..strokeCap = StrokeCap.square
..color = Colors.white
..style = PaintingStyle.stroke;
///临时刻度数量
int rulerCount = 10;
///x、y轴方向每个刻度的间距
double xRulerW = _fixedWidth / rulerCount; //x方向两个点之间的距离(刻度长)
double yRulerH = _fixedHeight / rulerCount; //y轴方向亮点之间的距离(刻度高)
///减小刻度线高度或长度
double reduceRuler = 20.0;
for (int i = 1; i <= rulerCount; i++) {
_drawXRuler(canvas, xRulerW, yRulerH, reduceRuler, i, paint);
_drawYRuler(canvas, xRulerW, yRulerH, reduceRuler, i, paint);
_drawXText(canvas, xRulerW, i);
_drawYText(canvas, yRulerH, i);
_initCurvePath(i-1, xRulerW, yRulerH);
}
}
///绘制x轴刻度
void _drawXRuler(Canvas canvas, double xRulerW, double yRulerH,
double reduceRuler, int i, var paint) {
double drawRulerSx = startX + xRulerW * i;
double drawRulerSy = startY;
double drawRulerEx = startX + xRulerW * i;
double drawRulerEy = startY - yRulerH + reduceRuler;
canvas.drawLine(Offset(drawRulerSx, drawRulerSy),
Offset(drawRulerEx, drawRulerEy), paint);
}
///绘制y轴刻度
void _drawYRuler(Canvas canvas, double xRulerW, double yRulerH,
double reduceRuler, int i, var paint) {
double drawRulerSx = startX;
double drawRulerSy = startY - i * yRulerH;
double drawRulerEx = startX + xRulerW - reduceRuler;
double drawRulerEy = startY - i * yRulerH;
canvas.drawLine(Offset(drawRulerSx, drawRulerSy),
Offset(drawRulerEx, drawRulerEy), paint);
}
///绘制x轴文本
void _drawXText(Canvas canvas, double xRulerW, int i) {
TextPainter(
textAlign: TextAlign.center,
ellipsis: '.',
text: TextSpan(
text: ((i - 1) * xRulerW).toString(),
style: TextStyle(color: Colors.white, fontSize: 9.0)),
textDirection: TextDirection.ltr)
..layout(minWidth: xRulerW, maxWidth: xRulerW)
..paint(
canvas,
Offset(startX + xRulerW * (i - 1) - xRulerW / 2,
startY + basePadding / 2));
}
///绘制y轴文本
void _drawYText(Canvas canvas, double yRulerH, int i) {
TextPainter(
textAlign: TextAlign.center,
ellipsis: '.',
text: TextSpan(
text: ((i - 1) * yRulerH).toString(),
style: TextStyle(color: Colors.white, fontSize: 9.0)),
textDirection: TextDirection.ltr)
..layout(minWidth: yRulerH, maxWidth: yRulerH)
..paint(
canvas,
Offset(startX - basePadding / 2 * 3,
startY - yRulerH * (i - 1) - yRulerH / 2));
}
///计算曲线path
void _initCurvePath(int i, double xRulerW, double yRulerH) {
if (i == 0) {
var key = startX;
var value = startY;
_path.moveTo(key, value);
} else {
double preX = startX + xRulerW * (i-1);
double preY = (startY - (i%2!=0?yRulerH:yRulerH*6));
double currentX = startX + xRulerW * i;
double currentY = (startY - (i%2==0?yRulerH:yRulerH*6));
_path.cubicTo((preX + currentX) / 2, preY, (preX + currentX) / 2, currentY, currentX, currentY);
}
}
///绘制直线或曲线
void _drawLine(canvas) {
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 2.0
..strokeCap = StrokeCap.round
..color = Colors.red
..style = PaintingStyle.stroke;
var pathMetrics = _path.computeMetrics(forceClosed: false);
var list = pathMetrics.toList();
var length = list.length.toInt();
Path linePath = new Path();
for (int i = 0; i < length; i++) {
var extractPath = list[i].extractPath(0, list[i].length, startWithMoveTo: true);
linePath.addPath(extractPath, Offset(0, 0));
}
canvas.drawPath(linePath, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
绘制阴影
class CharLinePainter extends CustomPainter {
static const double basePadding = 24; //基础边界
double startX, endX; //相对于原点x轴方向最小和最大偏移量(相对于原点的偏移量)
double startY, endY; //相对于原点y轴方向最大和最小偏移量(相对于原点的偏移量)
double _fixedWidth; //x轴方向:最大偏移量-最小偏移量(相对于原点的偏移量)
double _fixedHeight; //y轴方向:最大偏移量-最小偏移量(相对于原点的偏移量)
Path _path = new Path();
@override
void paint(Canvas canvas, Size size) {
_initBorder(size);
_drawXy(canvas);
_drawXYRulerText(canvas);
_drawLine(canvas);
}
/// 初始化边界
void _initBorder(Size size) {
startX = basePadding * 2;
endX = size.width - basePadding * 2;
startY = size.height - basePadding * 2;
endY = basePadding * 2;
_fixedWidth = endX - startX;
_fixedHeight = startY - endY;
}
///绘制xy轴
///绘制x轴-y轴偏移量不变(y轴坐标点不变)
///绘制y轴-x轴偏移量不变(x轴坐标点不变)
void _drawXy(Canvas canvas) {
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 1.0
..strokeCap = StrokeCap.square
..color = Colors.white
..style = PaintingStyle.stroke;
canvas.drawLine(Offset(startX, startY), Offset(endX, startY), paint); //x轴
canvas.drawLine(Offset(startX, startY), Offset(startX, endY), paint); //y轴
}
///绘制xy轴刻度+文本
void _drawXYRulerText(Canvas canvas) {
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 1.0
..strokeCap = StrokeCap.square
..color = Colors.white
..style = PaintingStyle.stroke;
///临时刻度数量
int rulerCount = 10;
///x、y轴方向每个刻度的间距
double xRulerW = _fixedWidth / rulerCount; //x方向两个点之间的距离(刻度长)
double yRulerH = _fixedHeight / rulerCount; //y轴方向亮点之间的距离(刻度高)
///减小刻度线高度或长度
double reduceRuler = 20.0;
for (int i = 1; i <= rulerCount; i++) {
_drawXRuler(canvas, xRulerW, yRulerH, reduceRuler, i, paint);
_drawYRuler(canvas, xRulerW, yRulerH, reduceRuler, i, paint);
_drawXText(canvas, xRulerW, i);
_drawYText(canvas, yRulerH, i);
_initCurvePath(i - 1, xRulerW, yRulerH);
}
}
///绘制x轴刻度
void _drawXRuler(Canvas canvas, double xRulerW, double yRulerH,
double reduceRuler, int i, var paint) {
double drawRulerSx = startX + xRulerW * i;
double drawRulerSy = startY;
double drawRulerEx = startX + xRulerW * i;
double drawRulerEy = startY - yRulerH + reduceRuler;
canvas.drawLine(Offset(drawRulerSx, drawRulerSy),
Offset(drawRulerEx, drawRulerEy), paint);
}
///绘制y轴刻度
void _drawYRuler(Canvas canvas, double xRulerW, double yRulerH,
double reduceRuler, int i, var paint) {
double drawRulerSx = startX;
double drawRulerSy = startY - i * yRulerH;
double drawRulerEx = startX + xRulerW - reduceRuler;
double drawRulerEy = startY - i * yRulerH;
canvas.drawLine(Offset(drawRulerSx, drawRulerSy),
Offset(drawRulerEx, drawRulerEy), paint);
}
///绘制x轴文本
void _drawXText(Canvas canvas, double xRulerW, int i) {
TextPainter(
textAlign: TextAlign.center,
ellipsis: '.',
text: TextSpan(
text: ((i - 1) * xRulerW).toString(),
style: TextStyle(color: Colors.white, fontSize: 9.0)),
textDirection: TextDirection.ltr)
..layout(minWidth: xRulerW, maxWidth: xRulerW)
..paint(
canvas,
Offset(startX + xRulerW * (i - 1) - xRulerW / 2,
startY + basePadding / 2));
}
///绘制y轴文本
void _drawYText(Canvas canvas, double yRulerH, int i) {
TextPainter(
textAlign: TextAlign.center,
ellipsis: '.',
text: TextSpan(
text: ((i - 1) * yRulerH).toString(),
style: TextStyle(color: Colors.white, fontSize: 9.0)),
textDirection: TextDirection.ltr)
..layout(minWidth: yRulerH, maxWidth: yRulerH)
..paint(
canvas,
Offset(startX - basePadding / 2 * 3,
startY - yRulerH * (i - 1) - yRulerH / 2));
}
///计算曲线path
void _initCurvePath(int i, double xRulerW, double yRulerH) {
if (i == 0) {
var key = startX;
var value = startY;
_path.moveTo(key, value);
} else {
double preX = startX + xRulerW * i;
double preY = (startY - (i % 2 != 0 ? yRulerH : yRulerH * 6));
double currentX = startX + xRulerW * (i+1);
double currentY = (startY - (i % 2 == 0 ? yRulerH : yRulerH * 6));
_path.cubicTo((preX + currentX) / 2, preY, (preX + currentX) / 2, currentY, currentX, currentY);
}
}
///绘制直线或曲线
void _drawLine(canvas) {
var paint = Paint()
..isAntiAlias = true
..strokeWidth = 2.0
..strokeCap = StrokeCap.round
..color = Colors.red
..style = PaintingStyle.stroke;
var pathMetrics = _path.computeMetrics(forceClosed: false);
var list = pathMetrics.toList();
var length = list.length.toInt();
Path linePath = new Path();
Path shadowPath = new Path();
for (int i = 0; i < length; i++) {
var extractPath = list[i].extractPath(0, list[i].length, startWithMoveTo: true);
shadowPath = extractPath;
linePath.addPath(extractPath, Offset(0, 0));
}
_drawShader(canvas, shadowPath);
canvas.drawPath(linePath, paint);
}
///绘制阴影
void _drawShader(canvas, shadowPath) {
var shader = LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
tileMode: TileMode.repeated,
colors: [
Colors.deepPurple.withOpacity(0.5),
Colors.red.withOpacity(0.5),
Colors.cyan.withOpacity(0.5),
Colors.deepPurpleAccent.withOpacity(0.5),
]).createShader(Rect.fromLTRB(startX, endY, startX, startY));
///从path的最后一个点连接起始点,形成一个闭环
shadowPath
..lineTo(startX + _fixedWidth, startY)
..lineTo(startX, startY)
..close();
canvas
..drawPath(
shadowPath,
new Paint()
..shader = shader
..isAntiAlias = true
..style = PaintingStyle.fill);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}