241 lines
5.8 KiB
Dart
241 lines
5.8 KiB
Dart
import 'dart:math';
|
|
|
|
import 'dart:ui' as ui;
|
|
|
|
import 'package:dash_painter/dash_painter.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/scheduler.dart';
|
|
import 'package:flutter/services.dart';
|
|
|
|
/// create by 张风捷特烈 on 2020/11/5
|
|
/// contact me by email 1981462002@qq.com
|
|
/// 说明:
|
|
|
|
class Paper extends StatefulWidget {
|
|
const Paper({Key? key}) : super(key: key);
|
|
|
|
@override
|
|
State<Paper> createState() => _PaperState();
|
|
}
|
|
|
|
class _PaperState extends State<Paper>
|
|
with SingleTickerProviderStateMixin {
|
|
Line line = Line(start: const Offset(20, 20), end: const Offset(50, 80));
|
|
|
|
late AnimationController ctrl;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
ctrl = AnimationController(
|
|
vsync: this,
|
|
duration: const Duration(seconds: 3),
|
|
)..addListener(_updateLine);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
line.dispose();
|
|
ctrl.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
|
|
return Center(
|
|
child: GestureDetector(
|
|
onTap: () {
|
|
// line.record();
|
|
ctrl.forward(from: 0);
|
|
},
|
|
child: CustomPaint(
|
|
painter: AnglePainter(line: line
|
|
// linker: linker
|
|
),
|
|
child: Container(
|
|
color: Colors.grey.withOpacity(0.1),
|
|
height: 200,
|
|
width: 200,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
void _updateLine() {
|
|
// print("${ctrl.value * 2 * pi}");
|
|
Offset center = line.percent(0.2);
|
|
line.rotate(ctrl.value * 2 * pi, centre: center);
|
|
// line.rotate(ctrl.value * 2* pi);
|
|
}
|
|
}
|
|
|
|
class AnglePainter extends CustomPainter {
|
|
final DashPainter dashPainter = const DashPainter(span: 4, step: 4);
|
|
|
|
AnglePainter({required this.line}) : super(repaint: line);
|
|
|
|
final Paint pointPaint = Paint()
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = 1;
|
|
|
|
final Paint helpPaint = Paint()
|
|
..style = PaintingStyle.stroke
|
|
..color = Colors.lightBlue
|
|
..strokeWidth = 1;
|
|
|
|
final TextPainter textPainter = TextPainter(
|
|
textAlign: TextAlign.center,
|
|
textDirection: TextDirection.ltr,
|
|
);
|
|
|
|
final Line line;
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
canvas.translate(size.width / 2, size.height / 2);
|
|
drawHelp(canvas, size);
|
|
line.paint(canvas);
|
|
}
|
|
|
|
void drawHelp(Canvas canvas, Size size) {
|
|
Path helpPath = Path()
|
|
..moveTo(-size.width / 2, 0)
|
|
..relativeLineTo(size.width, 0)
|
|
..moveTo(0, -size.height / 2)
|
|
..relativeLineTo(0, size.height);
|
|
dashPainter.paint(canvas, helpPath, helpPaint);
|
|
|
|
drawHelpText('0°', canvas, Offset(size.width / 2 - 20, 0));
|
|
drawHelpText('p0', canvas, line.start.translate(-20, 0));
|
|
drawHelpText('p1', canvas, line.end.translate(-20, 0));
|
|
|
|
// drawHelpText('p2', canvas, Offset(60, 40).translate(10, 0));
|
|
// drawAnchor(canvas, Offset(60, 40));
|
|
drawAnchor(canvas, line.percent(0.2));
|
|
// drawAnchor(canvas, line.percent(0.5));
|
|
|
|
// drawAnchor(canvas, line.percent(0.8));
|
|
|
|
drawHelpText(
|
|
'角度: ${(line.positiveRad * 180 / pi).toStringAsFixed(2)}°',
|
|
canvas,
|
|
Offset(
|
|
-size.width / 2 + 10,
|
|
-size.height / 2 + 10,
|
|
),
|
|
);
|
|
|
|
|
|
|
|
// canvas.drawArc(
|
|
// Rect.fromCenter(center: line.start, width: 20, height: 20),
|
|
// 0,
|
|
// line.positiveRad,
|
|
// false,
|
|
// helpPaint,
|
|
// );
|
|
|
|
// canvas.save();
|
|
// Offset center = const Offset(60, 60);
|
|
// canvas.translate(center.dx, center.dy);
|
|
// canvas.rotate(line.positiveRad);
|
|
// canvas.translate(-center.dx, -center.dy);
|
|
// canvas.drawCircle(center, 4, helpPaint);
|
|
// canvas.drawRect(
|
|
// Rect.fromCenter(center: center, width: 30, height: 60), helpPaint);
|
|
// canvas.restore();
|
|
}
|
|
|
|
void drawAnchor(Canvas canvas, Offset offset) {
|
|
canvas.drawCircle(offset, 4, pointPaint..style = PaintingStyle.stroke);
|
|
canvas.drawCircle(offset, 2, pointPaint..style = PaintingStyle.fill);
|
|
}
|
|
|
|
void drawHelpText(
|
|
String text,
|
|
Canvas canvas,
|
|
Offset offset, {
|
|
Color color = Colors.lightBlue,
|
|
}) {
|
|
textPainter.text = TextSpan(
|
|
text: text,
|
|
style: TextStyle(fontSize: 12, color: color),
|
|
);
|
|
textPainter.layout(maxWidth: 200);
|
|
textPainter.paint(canvas, offset);
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(covariant CustomPainter oldDelegate) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
class Line with ChangeNotifier {
|
|
Line({
|
|
this.start = Offset.zero,
|
|
this.end = Offset.zero,
|
|
});
|
|
|
|
Offset start;
|
|
Offset end;
|
|
|
|
final Paint pointPaint = Paint()
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = 1;
|
|
|
|
void paint(Canvas canvas) {
|
|
canvas.drawLine(start, end, pointPaint);
|
|
drawAnchor(canvas, start);
|
|
drawAnchor(canvas, end);
|
|
}
|
|
|
|
double get rad => (end - start).direction;
|
|
|
|
double get positiveRad => rad < 0 ? 2 * pi + rad : rad;
|
|
|
|
double get length => (end - start).distance;
|
|
|
|
void drawAnchor(Canvas canvas, Offset offset) {
|
|
canvas.drawCircle(offset, 4, pointPaint..style = PaintingStyle.stroke);
|
|
canvas.drawCircle(offset, 2, pointPaint..style = PaintingStyle.fill);
|
|
}
|
|
|
|
double detaRotate = 0;
|
|
|
|
void rotate(double rotate, {Offset? centre}) {
|
|
detaRotate = rotate - detaRotate;
|
|
centre = centre ?? start;
|
|
Line p2p0 = Line(start: centre, end: start);
|
|
Line p2p1 = Line(start: centre, end: end);
|
|
p2p0._rotateByStart(detaRotate);
|
|
p2p1._rotateByStart(detaRotate);
|
|
start = p2p0.end;
|
|
end = p2p1.end;
|
|
detaRotate = rotate;
|
|
notifyListeners();
|
|
}
|
|
|
|
|
|
|
|
Offset percent(double percent){
|
|
return Offset(
|
|
length*percent*cos(rad),
|
|
length*percent*sin(rad),
|
|
)+start;
|
|
}
|
|
|
|
void _rotateByStart(double rotate) {
|
|
end = Offset(
|
|
length * cos(rad + rotate),
|
|
length * sin(rad + rotate),
|
|
) +
|
|
start;
|
|
}
|
|
|
|
void tick() {
|
|
notifyListeners();
|
|
}
|
|
} |