books
This commit is contained in:
1
packages/idraw/lib/p21/p21.dart
Normal file
1
packages/idraw/lib/p21/p21.dart
Normal file
@@ -0,0 +1 @@
|
||||
export 'p21_page.dart';
|
||||
21
packages/idraw/lib/p21/p21_page.dart
Normal file
21
packages/idraw/lib/p21/p21_page.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:components/components.dart';
|
||||
import 's01.dart' as s1;
|
||||
import 's02.dart' as s2;
|
||||
|
||||
class P21Page extends StatelessWidget {
|
||||
const P21Page({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const DemoShower(
|
||||
srcCodeDir: 'draw/p21',
|
||||
|
||||
demos: [
|
||||
s1.Paper(),
|
||||
s2.Paper(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
241
packages/idraw/lib/p21/s01.dart
Normal file
241
packages/idraw/lib/p21/s01.dart
Normal file
@@ -0,0 +1,241 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
291
packages/idraw/lib/p21/s02.dart
Normal file
291
packages/idraw/lib/p21/s02.dart
Normal file
@@ -0,0 +1,291 @@
|
||||
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();
|
||||
|
||||
late AnimationController ctrl;
|
||||
ui.Image? _image;
|
||||
ui.Image? _bgImage;
|
||||
|
||||
void _loadImage() async {
|
||||
ByteData data = await rootBundle.load('assets/images/hand.webp');
|
||||
List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
|
||||
_image = await decodeImageFromList(Uint8List.fromList(bytes));
|
||||
line.attachImage(ImageZone(
|
||||
rect: const Rect.fromLTRB(0, 93, 104, 212),
|
||||
image: _image!,
|
||||
));
|
||||
}
|
||||
|
||||
void _loadImage2() async {
|
||||
ByteData bgData = await rootBundle.load('assets/images/body.webp');
|
||||
List<int> bgBytes = bgData.buffer.asUint8List(bgData.offsetInBytes, bgData.lengthInBytes);
|
||||
_bgImage = await decodeImageFromList(Uint8List.fromList(bgBytes));
|
||||
setState(() {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
ctrl = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(seconds: 1),
|
||||
)..addListener(_updateLine)..forward();
|
||||
_loadImage();
|
||||
_loadImage2();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
line.dispose();
|
||||
ctrl.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// line.start = Offset.zero;
|
||||
// line.end = Offset(40, 0);
|
||||
// line.rotate(2.4085543677521746);
|
||||
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
// line.record();
|
||||
ctrl.repeat(reverse: true);
|
||||
},
|
||||
child:
|
||||
CustomPaint(
|
||||
painter: AnglePainter(line: line,
|
||||
// linker: linker
|
||||
image:_bgImage),
|
||||
child: Container(
|
||||
// color: Colors.grey.withOpacity(0.1),
|
||||
// height: 200,
|
||||
// width: 200,
|
||||
),
|
||||
),
|
||||
),
|
||||
), // This trailing comma makes auto-formatting nicer for build methods.
|
||||
);
|
||||
}
|
||||
|
||||
void _updateLine() {
|
||||
// print("${ctrl.value * 2 * pi}");
|
||||
line.rotate(ctrl.value * 2* pi/50);
|
||||
}
|
||||
}
|
||||
class ImageZone {
|
||||
final ui.Image image;
|
||||
final Rect rect;
|
||||
|
||||
Line? _line;
|
||||
|
||||
final Paint imagePaint = Paint()..filterQuality = FilterQuality.high;
|
||||
|
||||
ImageZone({required this.image, this.rect = Rect.zero});
|
||||
|
||||
Line get line {
|
||||
if (_line != null) {
|
||||
return _line!;
|
||||
}
|
||||
Offset start = Offset(
|
||||
-(image.width / 2 - rect.right), -(image.height / 2 - rect.bottom));
|
||||
Offset end = start.translate(-rect.width, -rect.height);
|
||||
_line = Line(start: start, end: end);
|
||||
return _line!;
|
||||
}
|
||||
|
||||
void paint(Canvas canvas, Line line) {
|
||||
canvas.save();
|
||||
canvas.translate(line.start.dx, line.start.dy);
|
||||
canvas.rotate(line.positiveRad - this.line.positiveRad);
|
||||
canvas.translate(-line.start.dx, -line.start.dy);
|
||||
canvas.drawImageRect(
|
||||
image,
|
||||
rect,
|
||||
rect.translate(-image.width / 2, -image.height / 2),
|
||||
imagePaint,
|
||||
);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
class AnglePainter extends CustomPainter {
|
||||
final DashPainter dashPainter = const DashPainter(span: 4, step: 4);
|
||||
ui.Image? image;
|
||||
|
||||
AnglePainter({required this.line, this.image}) : super(repaint: line);
|
||||
|
||||
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);
|
||||
line.paint(canvas);
|
||||
// drawHelp(canvas, size);
|
||||
|
||||
if (image != null) {
|
||||
canvas.drawImage(
|
||||
image!, Offset(-image!.width / 2, -image!.height / 2), Paint());
|
||||
// drawHelp(canvas, Size(image!.width.toDouble() , image!.height.toDouble()));
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
// '角度: ${(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 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 AnglePainter oldDelegate) {
|
||||
return oldDelegate.image != image;
|
||||
}
|
||||
}
|
||||
|
||||
class Line with ChangeNotifier {
|
||||
Line({
|
||||
this.start = Offset.zero,
|
||||
this.end = Offset.zero,
|
||||
});
|
||||
|
||||
Offset start;
|
||||
Offset end;
|
||||
ImageZone? _zone;
|
||||
|
||||
void attachImage(ImageZone zone) {
|
||||
_zone = zone;
|
||||
start = zone.line.start;
|
||||
end = zone.line.end;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
final Paint pointPaint = Paint()
|
||||
..style = PaintingStyle.fill
|
||||
..color = Colors.red
|
||||
..strokeWidth = 1;
|
||||
|
||||
void paint(Canvas canvas) {
|
||||
_zone?.paint(canvas, this);
|
||||
// canvas.save();
|
||||
// canvas.translate(start.dx, start.dy);
|
||||
// canvas.rotate(positiveRad);
|
||||
// Path arrowPath = Path();
|
||||
// arrowPath
|
||||
// ..relativeLineTo(length - 10, 3)
|
||||
// ..relativeLineTo(0, 2)
|
||||
// ..lineTo(length, 0)
|
||||
// ..relativeLineTo(-10, -5)
|
||||
// ..relativeLineTo(0, 2)
|
||||
// ..close();
|
||||
// canvas.drawPath(arrowPath, pointPaint);
|
||||
// canvas.restore();
|
||||
}
|
||||
|
||||
double get rad => (end - start).direction;
|
||||
|
||||
double get positiveRad => rad < 0 ? 2 * pi + rad : rad;
|
||||
|
||||
double get length => (end - start).distance;
|
||||
|
||||
double detaRotate = 0;
|
||||
|
||||
void rotate(double rotate) {
|
||||
detaRotate = rotate - detaRotate;
|
||||
end = Offset(
|
||||
length * cos(rad + detaRotate),
|
||||
length * sin(rad + detaRotate),
|
||||
) +
|
||||
start;
|
||||
detaRotate = rotate;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void tick() {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user