books
This commit is contained in:
@@ -14,12 +14,11 @@ class Coordinate {
|
||||
|
||||
Coordinate(
|
||||
{this.step = 20,
|
||||
this.strokeWidth = .5,
|
||||
this.axisColor = Colors.blue,
|
||||
this.gridColor = Colors.grey});
|
||||
this.strokeWidth = .5,
|
||||
this.axisColor = Colors.blue,
|
||||
this.gridColor = Colors.grey});
|
||||
|
||||
final Paint _gridPaint = Paint();
|
||||
final Path _gridPath = Path();
|
||||
|
||||
void paint(Canvas canvas, Size size) {
|
||||
canvas.save();
|
||||
@@ -30,6 +29,8 @@ class Coordinate {
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _drawAxis(Canvas canvas, Size size) {
|
||||
_gridPaint
|
||||
..color = Colors.blue
|
||||
@@ -49,28 +50,30 @@ class Coordinate {
|
||||
}
|
||||
|
||||
void _drawGridLine(Canvas canvas, Size size) {
|
||||
final Path path = Path();
|
||||
|
||||
_gridPaint
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = .5
|
||||
..color = Colors.grey;
|
||||
|
||||
for (int i = 0; i < size.width / 2 / step; i++) {
|
||||
_gridPath.moveTo(step * i, -size.height / 2 );
|
||||
_gridPath.relativeLineTo(0, size.height);
|
||||
path.moveTo(step * i, -size.height / 2 );
|
||||
path.relativeLineTo(0, size.height);
|
||||
|
||||
_gridPath.moveTo(-step * i, -size.height / 2 );
|
||||
_gridPath.relativeLineTo(0, size.height);
|
||||
path.moveTo(-step * i, -size.height / 2 );
|
||||
path.relativeLineTo(0, size.height);
|
||||
}
|
||||
|
||||
for (int i = 0; i < size.height / 2 / step; i++) {
|
||||
_gridPath.moveTo(-size.width / 2,step * i );
|
||||
_gridPath.relativeLineTo(size.width,0 );
|
||||
path.moveTo(-size.width / 2,step * i );
|
||||
path.relativeLineTo(size.width,0 );
|
||||
|
||||
_gridPath.moveTo(-size.width / 2,-step * i, );
|
||||
_gridPath.relativeLineTo(size.width,0 );
|
||||
path.moveTo(-size.width / 2,-step * i, );
|
||||
path.relativeLineTo(size.width,0 );
|
||||
}
|
||||
|
||||
canvas.drawPath(_gridPath, _gridPaint);
|
||||
canvas.drawPath(path, _gridPaint);
|
||||
}
|
||||
|
||||
void _drawAxisText(Canvas canvas, String str,
|
||||
@@ -160,4 +163,3 @@ class Coordinate {
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,3 +11,10 @@ export 'p08/p08.dart';
|
||||
export 'p09/p09.dart';
|
||||
export 'p10/p10.dart';
|
||||
export 'p11/p11.dart';
|
||||
export 'p12/p12.dart';
|
||||
export 'p13/p13.dart';
|
||||
export 'p14/p14.dart';
|
||||
export 'p15/p15.dart';
|
||||
export 'p16/p16.dart';
|
||||
export 'p17/p17.dart';
|
||||
export 'p18/p18.dart';
|
||||
|
||||
1
packages/idraw/lib/p12/p12.dart
Normal file
1
packages/idraw/lib/p12/p12.dart
Normal file
@@ -0,0 +1 @@
|
||||
export 'p12_page.dart';
|
||||
25
packages/idraw/lib/p12/p12_page.dart
Normal file
25
packages/idraw/lib/p12/p12_page.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:components/components.dart';
|
||||
import 's01.dart' as s1;
|
||||
import 's02.dart' as s2;
|
||||
import 's03.dart' as s3;
|
||||
import 's04.dart' as s4;
|
||||
|
||||
class P12Page extends StatelessWidget {
|
||||
const P12Page({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const DemoShower(
|
||||
srcCodeDir: 'draw/p12',
|
||||
|
||||
demos: [
|
||||
s1.Paper(),
|
||||
s2.Paper(),
|
||||
s3.Paper(),
|
||||
s4.Paper(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
66
packages/idraw/lib/p12/s01.dart
Normal file
66
packages/idraw/lib/p12/s01.dart
Normal file
@@ -0,0 +1,66 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/3
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: HandleWidget(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class HandleWidget extends StatefulWidget {
|
||||
final double size;
|
||||
final double handleRadius;
|
||||
|
||||
HandleWidget({Key? key, this.size = 160.0, this.handleRadius = 20.0})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_HandleWidgetState createState() => _HandleWidgetState();
|
||||
}
|
||||
|
||||
class _HandleWidgetState extends State<HandleWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomPaint(
|
||||
size: Size(widget.size, widget.size),
|
||||
painter: _HandlePainter(handleR: widget.handleRadius));
|
||||
}
|
||||
}
|
||||
|
||||
class _HandlePainter extends CustomPainter {
|
||||
var _paint = Paint();
|
||||
|
||||
var handleR;
|
||||
|
||||
_HandlePainter({this.handleR}) {
|
||||
_paint
|
||||
..color = Colors.blue
|
||||
..style = PaintingStyle.fill
|
||||
..isAntiAlias = true;
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
canvas.clipRect(Offset.zero & size);
|
||||
|
||||
final bgR = size.width / 2 - handleR;
|
||||
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
_paint.color = _paint.color.withAlpha(100);
|
||||
canvas.drawCircle(Offset(0, 0), bgR, _paint);
|
||||
_paint.color = _paint.color.withAlpha(150);
|
||||
canvas.drawCircle(Offset(0, 0), handleR, _paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_HandlePainter oldDelegate) =>
|
||||
oldDelegate.handleR != handleR;
|
||||
}
|
||||
109
packages/idraw/lib/p12/s02.dart
Normal file
109
packages/idraw/lib/p12/s02.dart
Normal file
@@ -0,0 +1,109 @@
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../components/coordinate_pro.dart';
|
||||
/// create by 张风捷特烈 on 2020-03-19
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明: 纸
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: HandleWidget(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class HandleWidget extends StatefulWidget {
|
||||
final double size;
|
||||
final double handleRadius;
|
||||
|
||||
HandleWidget({Key? key, this.size = 160, this.handleRadius = 20.0})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_HandleWidgetState createState() => _HandleWidgetState();
|
||||
}
|
||||
|
||||
class _HandleWidgetState extends State<HandleWidget> {
|
||||
ValueNotifier<Offset> _offset = ValueNotifier(Offset.zero);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onPanEnd: reset,
|
||||
onPanUpdate: parser,
|
||||
child: CustomPaint(
|
||||
size: Size(widget.size, widget.size),
|
||||
painter: _HandlePainter(
|
||||
color: Colors.green,
|
||||
handleR: widget.handleRadius,
|
||||
offset: _offset)));
|
||||
}
|
||||
|
||||
reset(DragEndDetails details) {
|
||||
_offset.value = Offset.zero;
|
||||
}
|
||||
|
||||
parser(DragUpdateDetails details) {
|
||||
final offset = details.localPosition;
|
||||
double dx = 0.0;
|
||||
double dy = 0.0;
|
||||
|
||||
dx = offset.dx - widget.size / 2;
|
||||
dy = offset.dy - widget.size / 2;
|
||||
var rad = atan2(dx, dy);
|
||||
if (dx < 0) {
|
||||
rad += 2 * pi;
|
||||
}
|
||||
var bgR = widget.size / 2 - widget.handleRadius;
|
||||
var thta = rad - pi / 2; //旋转坐标系90度
|
||||
if (sqrt(dx * dx + dy * dy) > bgR) {
|
||||
dx = bgR * cos(thta);
|
||||
dy = -bgR * sin(thta);
|
||||
}
|
||||
_offset.value = Offset(dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
class _HandlePainter extends CustomPainter {
|
||||
final _paint = Paint();
|
||||
final ValueNotifier<Offset> offset;
|
||||
final Color color;
|
||||
|
||||
var handleR;
|
||||
|
||||
_HandlePainter({this.handleR,required this.offset, this.color = Colors.blue})
|
||||
: super(repaint: offset) ;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
canvas.clipRect(Offset.zero & size);
|
||||
|
||||
final bgR = size.width / 2 - handleR;
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
|
||||
_paint.style = PaintingStyle.fill;
|
||||
_paint.color = color.withAlpha(100);
|
||||
|
||||
canvas.drawCircle(Offset(0, 0), bgR, _paint);
|
||||
|
||||
_paint.color = color.withAlpha(150);
|
||||
|
||||
canvas.drawCircle(
|
||||
Offset(offset.value.dx, offset.value.dy), handleR, _paint);
|
||||
|
||||
_paint.color = color;
|
||||
_paint.style = PaintingStyle.stroke;
|
||||
canvas.drawLine(Offset.zero, offset.value, _paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_HandlePainter oldDelegate) =>
|
||||
oldDelegate.offset != offset ||
|
||||
oldDelegate.color != color ||
|
||||
oldDelegate.handleR != handleR;
|
||||
}
|
||||
153
packages/idraw/lib/p12/s03.dart
Normal file
153
packages/idraw/lib/p12/s03.dart
Normal file
@@ -0,0 +1,153 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
import 'dart:ui' as ui;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../components/coordinate_pro.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020-03-19
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明: 纸
|
||||
|
||||
class Paper extends StatefulWidget{
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
State<Paper> createState() => _PaperState();
|
||||
}
|
||||
|
||||
class _PaperState extends State<Paper> {
|
||||
double _rotate = 0;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Transform.rotate(
|
||||
angle: _rotate,
|
||||
child:
|
||||
Container(
|
||||
color: Colors.blue,
|
||||
alignment: Alignment.center,
|
||||
width: 100,
|
||||
height: 100,
|
||||
),
|
||||
),
|
||||
HandleWidget(
|
||||
onMove: _onMove,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onMove(double rotate, double distance) {
|
||||
setState(() {
|
||||
_rotate= rotate;
|
||||
});
|
||||
}
|
||||
}
|
||||
class HandleWidget extends StatefulWidget {
|
||||
final double size;
|
||||
final double handleRadius;
|
||||
final void Function(double rotate, double distance) onMove;
|
||||
|
||||
HandleWidget(
|
||||
{Key? key,
|
||||
this.size = 160,
|
||||
this.handleRadius = 20.0,
|
||||
required this.onMove})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_HandleWidgetState createState() => _HandleWidgetState();
|
||||
}
|
||||
|
||||
class _HandleWidgetState extends State<HandleWidget> {
|
||||
ValueNotifier<Offset> _offset = ValueNotifier(Offset.zero);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RepaintBoundary(
|
||||
child: GestureDetector(
|
||||
onPanEnd: reset,
|
||||
onPanUpdate: parser,
|
||||
child: CustomPaint(
|
||||
size: Size(widget.size, widget.size),
|
||||
painter: _HandlePainter(
|
||||
color: Colors.green,
|
||||
handleR: widget.handleRadius,
|
||||
offset: _offset))),
|
||||
);
|
||||
}
|
||||
|
||||
reset(DragEndDetails details) {
|
||||
_offset.value = Offset.zero;
|
||||
widget.onMove(0, 0);
|
||||
}
|
||||
|
||||
parser(DragUpdateDetails details) {
|
||||
final offset = details.localPosition;
|
||||
double dx = 0.0;
|
||||
double dy = 0.0;
|
||||
|
||||
dx = offset.dx - widget.size / 2;
|
||||
dy = offset.dy - widget.size / 2;
|
||||
var rad = atan2(dx, dy);
|
||||
if (dx < 0) {
|
||||
rad += 2 * pi;
|
||||
}
|
||||
var bgR = widget.size / 2 - widget.handleRadius;
|
||||
var thta = rad - pi / 2; //旋转坐标系90度
|
||||
var d = sqrt(dx * dx + dy * dy);
|
||||
if (d > bgR) {
|
||||
dx = bgR * cos(thta);
|
||||
dy = -bgR * sin(thta);
|
||||
}
|
||||
widget.onMove(thta, d);
|
||||
_offset.value = Offset(dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
class _HandlePainter extends CustomPainter {
|
||||
var _paint = Paint();
|
||||
final ValueNotifier<Offset> offset;
|
||||
final Color color;
|
||||
|
||||
var handleR;
|
||||
|
||||
_HandlePainter({this.handleR,required this.offset, this.color = Colors.blue})
|
||||
: super(repaint: offset);
|
||||
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
|
||||
canvas.clipRect(Offset.zero & size);
|
||||
|
||||
final bgR = size.width / 2 - handleR;
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
|
||||
_paint.style = PaintingStyle.fill;
|
||||
_paint.color = color.withAlpha(100);
|
||||
|
||||
canvas.drawCircle(Offset(0, 0), bgR, _paint);
|
||||
|
||||
_paint.color = color.withAlpha(150);
|
||||
|
||||
canvas.drawCircle(
|
||||
Offset(offset.value.dx, offset.value.dy), handleR, _paint);
|
||||
|
||||
_paint.color = color;
|
||||
_paint.style = PaintingStyle.stroke;
|
||||
canvas.drawLine(Offset.zero, offset.value, _paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_HandlePainter oldDelegate) =>
|
||||
oldDelegate.offset != offset ||
|
||||
oldDelegate.color != color ||
|
||||
oldDelegate.handleR != handleR;
|
||||
}
|
||||
167
packages/idraw/lib/p12/s04.dart
Normal file
167
packages/idraw/lib/p12/s04.dart
Normal file
@@ -0,0 +1,167 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
import 'dart:ui' as ui;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../components/coordinate_pro.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020-03-19
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明: 纸
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: RulerChooser(
|
||||
onChanged: (value) {},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RulerChooser extends StatefulWidget {
|
||||
final Size size;
|
||||
final void Function(double) onChanged;
|
||||
final int min;
|
||||
final int max;
|
||||
|
||||
const RulerChooser(
|
||||
{Key? key,
|
||||
required this.onChanged,
|
||||
this.max = 200,
|
||||
this.min = 100,
|
||||
this.size = const Size(240.0, 60)})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_RulerChooserState createState() => _RulerChooserState();
|
||||
}
|
||||
|
||||
class _RulerChooserState extends State<RulerChooser> {
|
||||
ValueNotifier<double> _dx = ValueNotifier(0.0);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onPanUpdate: _parser,
|
||||
child: CustomPaint(
|
||||
size: widget.size,
|
||||
painter: _HandlePainter(dx: _dx, max: widget.max, min: widget.min)),
|
||||
);
|
||||
}
|
||||
|
||||
double dx = 0;
|
||||
|
||||
void _parser(DragUpdateDetails details) {
|
||||
dx += details.delta.dx;
|
||||
|
||||
if (dx > 0) {
|
||||
dx = 0.0;
|
||||
}
|
||||
var limitMax = -(widget.max - widget.min) * (_kSpacer + _kStrokeWidth);
|
||||
if (dx < limitMax) {
|
||||
dx = limitMax;
|
||||
}
|
||||
_dx.value = dx;
|
||||
|
||||
if (widget.onChanged != null) {
|
||||
widget.onChanged(details.delta.dx / (_kSpacer + _kStrokeWidth));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const double _kHeightLevel1 = 20; // 短线长
|
||||
const double _kHeightLevel2 = 25; // 5 线长
|
||||
const double _kHeightLevel3 = 30; //10 线长
|
||||
const double _kPrefixOffSet = 5; // 左侧偏移
|
||||
const double _kVerticalOffSet = 12; // 线顶部偏移
|
||||
const double _kStrokeWidth = 2; // 刻度宽
|
||||
const double _kSpacer = 4; // 刻度间隙
|
||||
const List<Color> _kRulerColors = [
|
||||
// 渐变色
|
||||
Color(0xFF1426FB), Color(0xFF6080FB), Color(0xFFBEE0FB),
|
||||
];
|
||||
const List<double> _kRulerColorStops = [0.0, 0.2, 0.8];
|
||||
|
||||
class _HandlePainter extends CustomPainter {
|
||||
var _paint = Paint();
|
||||
Paint _pointPaint = Paint();
|
||||
|
||||
final ValueNotifier<double> dx;
|
||||
|
||||
final int max;
|
||||
final int min;
|
||||
|
||||
_HandlePainter({required this.dx, required this.max, required this.min})
|
||||
: super(repaint: dx) {
|
||||
_paint
|
||||
..strokeWidth = _kStrokeWidth
|
||||
..shader = ui.Gradient.radial(
|
||||
Offset(0, 0), 25, _kRulerColors, _kRulerColorStops, TileMode.mirror);
|
||||
_pointPaint
|
||||
..color = Colors.purple
|
||||
..strokeWidth = 4
|
||||
..strokeCap = StrokeCap.round;
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
canvas.clipRect(Offset.zero & size);
|
||||
|
||||
drawArrow(canvas);
|
||||
canvas.translate(dx.value, 0);
|
||||
drawRuler(canvas);
|
||||
}
|
||||
|
||||
// 绘制刻度
|
||||
void drawRuler(Canvas canvas) {
|
||||
double y = _kHeightLevel1;
|
||||
for (int i = min; i < max + 5; i++) {
|
||||
if (i % 5 == 0 && i % 10 != 0) {
|
||||
y = _kHeightLevel2;
|
||||
} else if (i % 10 == 0) {
|
||||
y = _kHeightLevel3;
|
||||
_simpleDrawText(canvas, i.toString(),
|
||||
offset: Offset(-3, _kHeightLevel3 + 2));
|
||||
} else {
|
||||
y = _kHeightLevel1;
|
||||
}
|
||||
canvas.drawLine(Offset.zero, Offset(0, y), _paint);
|
||||
canvas.translate(_kStrokeWidth + _kSpacer, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制三角形尖角
|
||||
void drawArrow(Canvas canvas) {
|
||||
var path = Path()
|
||||
..moveTo(_kStrokeWidth / 2 + _kPrefixOffSet, 3)
|
||||
..relativeLineTo(-3, 0)
|
||||
..relativeLineTo(3, _kPrefixOffSet)
|
||||
..relativeLineTo(3, -_kPrefixOffSet)
|
||||
..close();
|
||||
canvas.drawPath(path, _pointPaint);
|
||||
canvas.translate(_kStrokeWidth / 2 + _kPrefixOffSet, _kVerticalOffSet);
|
||||
}
|
||||
|
||||
void _simpleDrawText(Canvas canvas, String str,
|
||||
{Offset offset = Offset.zero}) {
|
||||
var builder = ui.ParagraphBuilder(ui.ParagraphStyle())
|
||||
..pushStyle(
|
||||
ui.TextStyle(
|
||||
color: Colors.black, textBaseline: ui.TextBaseline.alphabetic),
|
||||
)
|
||||
..addText(str);
|
||||
canvas.drawParagraph(
|
||||
builder.build()
|
||||
..layout(ui.ParagraphConstraints(width: 11.0 * str.length)),
|
||||
offset);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_HandlePainter oldDelegate) =>
|
||||
oldDelegate.dx != dx || oldDelegate.min != min || oldDelegate.max != max;
|
||||
}
|
||||
1
packages/idraw/lib/p13/p13.dart
Normal file
1
packages/idraw/lib/p13/p13.dart
Normal file
@@ -0,0 +1 @@
|
||||
export 'p13_page.dart';
|
||||
25
packages/idraw/lib/p13/p13_page.dart
Normal file
25
packages/idraw/lib/p13/p13_page.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:components/components.dart';
|
||||
import 's01.dart' as s1;
|
||||
import 's02.dart' as s2;
|
||||
import 's03.dart' as s3;
|
||||
import 's04.dart' as s4;
|
||||
|
||||
class P13Page extends StatelessWidget {
|
||||
const P13Page({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const DemoShower(
|
||||
srcCodeDir: 'draw/p13',
|
||||
|
||||
demos: [
|
||||
s1.Paper(),
|
||||
s2.Paper(),
|
||||
s3.Paper(),
|
||||
s4.Paper(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
114
packages/idraw/lib/p13/s01.dart
Normal file
114
packages/idraw/lib/p13/s01.dart
Normal file
@@ -0,0 +1,114 @@
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:ui'as ui;
|
||||
|
||||
import '../components/coordinate_pro.dart';
|
||||
|
||||
|
||||
/// create by 张风捷特烈 on 2020/5/1
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: CustomPaint(
|
||||
// 使用CustomPaint
|
||||
painter: PaperPainter(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
final Coordinate coordinate = Coordinate();
|
||||
|
||||
final List<Offset> points = [];
|
||||
|
||||
final double step = 1;
|
||||
final double min = 0;
|
||||
final double max = 360;
|
||||
|
||||
void initPoints() {
|
||||
for (double x = min; x <= max; x += step) {
|
||||
points.add(Offset(x, f(x)));
|
||||
// double thta = (pi / 180 * x);
|
||||
// var p = f(thta);
|
||||
// points.add(Offset(p * cos(thta), p * sin(thta)));
|
||||
}
|
||||
}
|
||||
|
||||
void initPointsWithPolar() {
|
||||
for (double x = min; x <= max; x += step) {
|
||||
double thta = (pi / 180 * x); // 角度转化为弧度
|
||||
var p = f(thta);
|
||||
points.add(Offset(p * cos(thta), p * sin(thta)));
|
||||
}
|
||||
}
|
||||
|
||||
// double f(double x) {
|
||||
// double y = -x * x / 200 + 100;
|
||||
// return y;
|
||||
// }
|
||||
|
||||
// double f(double thta) {
|
||||
// double p = 10 * thta;
|
||||
// return p;
|
||||
// }
|
||||
|
||||
// double f(double thta) {
|
||||
// double p = 100 * (1-cos(thta));
|
||||
// return p;
|
||||
// }
|
||||
|
||||
// double f(double thta) {
|
||||
// double p = 150*sin(5*thta).abs();
|
||||
// return p;
|
||||
// }
|
||||
|
||||
|
||||
double f(double thta) { // 100*(1-4*sinθ)
|
||||
double p = 50*(pow(e,cos(thta)) - 2 * cos(4 * thta) +pow(sin(thta / 12), 5));
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
coordinate.paint(canvas, size);
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
// initPoints();
|
||||
initPointsWithPolar();
|
||||
Path path = Path();
|
||||
Paint paint = Paint()
|
||||
..color = Colors.red
|
||||
..strokeWidth = 1.5
|
||||
..style = PaintingStyle.stroke;
|
||||
var colors = [
|
||||
Color(0xFFF60C0C),
|
||||
Color(0xFFF3B913),
|
||||
Color(0xFFE7F716),
|
||||
Color(0xFF3DF30B),
|
||||
Color(0xFF0DF6EF),
|
||||
Color(0xFF0829FB),
|
||||
Color(0xFFB709F4),
|
||||
];
|
||||
var pos = [1.0 / 7, 2.0 / 7, 3.0 / 7, 4.0 / 7, 5.0 / 7, 6.0 / 7, 1.0];
|
||||
|
||||
paint.shader = ui.Gradient.linear(
|
||||
Offset(0, 0), Offset(100, 0), colors, pos,TileMode.mirror);
|
||||
|
||||
// canvas.drawPoints(PointMode.points, points, paint);
|
||||
canvas.drawPoints(PointMode.polygon, points, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
||||
}
|
||||
123
packages/idraw/lib/p13/s02.dart
Normal file
123
packages/idraw/lib/p13/s02.dart
Normal file
@@ -0,0 +1,123 @@
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:ui'as ui;
|
||||
import '../components/coordinate_pro.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/5/1
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget{
|
||||
const Paper({super.key});
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: CustomPaint(
|
||||
// 使用CustomPaint
|
||||
painter: PaperPainter(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
final Coordinate coordinate = Coordinate();
|
||||
|
||||
final List<Offset> points = [];
|
||||
|
||||
final double step = 6;
|
||||
final double min = -240;
|
||||
final double max = 240;
|
||||
|
||||
void initPoints() {
|
||||
for (double x = min; x < max; x += step) {
|
||||
points.add(Offset(x, f(x)));
|
||||
}
|
||||
points.add(Offset(max, f(max)));
|
||||
points.add(Offset(max, f(max)));
|
||||
}
|
||||
|
||||
void initPointsWithPolar() {
|
||||
for (double x = min; x < max; x += step) {
|
||||
double thta = (pi / 180 * x); // 角度转化为弧度
|
||||
var p = f(thta);
|
||||
points.add(Offset(p * cos(thta), p * sin(thta)));
|
||||
}
|
||||
}
|
||||
|
||||
// double f(double x) {
|
||||
// double y = -x * x / 200 + 100;
|
||||
// return y;
|
||||
// }
|
||||
|
||||
// double f(double thta) {
|
||||
// double p = 10 * thta;
|
||||
// return p;
|
||||
// }
|
||||
|
||||
// double f(double thta) {
|
||||
// double p = 100 * (1-cos(thta));
|
||||
// return p;
|
||||
// }
|
||||
|
||||
// double f(double thta) {
|
||||
// double p = 150*sin(5*thta).abs();
|
||||
// return p;
|
||||
// }
|
||||
|
||||
|
||||
double f(double thta) { // 100*(1-4*sinθ)
|
||||
double p = 50*(pow(e,cos(thta)) - 2 * cos(4 * thta) +pow(sin(thta / 12), 5));
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
coordinate.paint(canvas, size);
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
// initPoints();
|
||||
initPointsWithPolar();
|
||||
Paint paint = Paint()
|
||||
..color = Colors.red
|
||||
..strokeWidth = 1.5
|
||||
..style = PaintingStyle.stroke;
|
||||
var colors = [
|
||||
Color(0xFFF60C0C),
|
||||
Color(0xFFF3B913),
|
||||
Color(0xFFE7F716),
|
||||
Color(0xFF3DF30B),
|
||||
Color(0xFF0DF6EF),
|
||||
Color(0xFF0829FB),
|
||||
Color(0xFFB709F4),
|
||||
];
|
||||
var pos = [1.0 / 7, 2.0 / 7, 3.0 / 7, 4.0 / 7, 5.0 / 7, 6.0 / 7, 1.0];
|
||||
|
||||
paint.shader = ui.Gradient.linear(
|
||||
Offset(0, 0), Offset(100, 0), colors, pos,TileMode.mirror);
|
||||
|
||||
|
||||
Offset p1 = points[0];
|
||||
Path path = Path()..moveTo(p1.dx, p1.dy);
|
||||
|
||||
for (var i = 1; i < points.length-1; i++) {
|
||||
double xc = (points[i].dx + points[i + 1].dx) / 2;
|
||||
double yc = (points[i].dy + points[i + 1].dy) / 2;
|
||||
Offset p2 = points[i];
|
||||
path.quadraticBezierTo(p2.dx, p2.dy, xc, yc);
|
||||
}
|
||||
|
||||
canvas.drawPath(path, paint);
|
||||
|
||||
// canvas.drawPoints(PointMode.points, points, paint..shader=null..strokeWidth=3);
|
||||
// canvas.drawPoints(PointMode.polygon, points, paint..shader=null..strokeWidth=1..color=Colors.blue);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
||||
}
|
||||
130
packages/idraw/lib/p13/s03.dart
Normal file
130
packages/idraw/lib/p13/s03.dart
Normal file
@@ -0,0 +1,130 @@
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
/// create by 张风捷特烈 on 2020/5/1
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatefulWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
_PaperState createState() => _PaperState();
|
||||
}
|
||||
|
||||
class _PaperState extends State<Paper> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(seconds: 15),
|
||||
vsync: this,
|
||||
)..repeat()
|
||||
;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: CustomPaint(
|
||||
painter: PaperPainter(_controller),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
// final Coordinate coordinate = Coordinate();
|
||||
|
||||
final Animation<double> repaint;
|
||||
|
||||
PaperPainter(this.repaint) : super(repaint: repaint) {
|
||||
initPointsWithPolar();
|
||||
}
|
||||
|
||||
final List<Offset> points = [];
|
||||
final Path path = Path();
|
||||
final double step = 4;
|
||||
final double min = -240;
|
||||
final double max = 240;
|
||||
|
||||
void initPointsWithPolar() {
|
||||
for (double x = min; x < max; x += step) {
|
||||
double thta = (pi / 180 * x); // 角度转化为弧度
|
||||
var p = f(thta);
|
||||
points.add(Offset(p * cos(thta), p * sin(thta)));
|
||||
}
|
||||
double thta = (pi / 180 * max);
|
||||
points.add(Offset(f(thta) * cos(thta), f(thta) * sin(thta)));
|
||||
points.add(Offset(f(thta) * cos(thta), f(thta) * sin(thta)));
|
||||
}
|
||||
|
||||
double f(double thta) {
|
||||
double p = 150*sin(5*thta).abs();
|
||||
return p;
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
|
||||
Paint paint = Paint()
|
||||
..color = Colors.red
|
||||
..strokeWidth = 1.5
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
var colors = [
|
||||
Color(0xFFF60C0C),
|
||||
Color(0xFFF3B913),
|
||||
Color(0xFFE7F716),
|
||||
Color(0xFF3DF30B),
|
||||
Color(0xFF0DF6EF),
|
||||
Color(0xFF0829FB),
|
||||
Color(0xFFB709F4),
|
||||
];
|
||||
var pos = [1.0 / 7, 2.0 / 7, 3.0 / 7, 4.0 / 7, 5.0 / 7, 6.0 / 7, 1.0];
|
||||
|
||||
paint.shader = ui.Gradient.linear(
|
||||
Offset(0, 0), Offset(100, 0), colors, pos, TileMode.mirror);
|
||||
|
||||
Offset p1 = points[0];
|
||||
|
||||
|
||||
path.reset();
|
||||
path..moveTo(p1.dx, p1.dy);
|
||||
|
||||
for (var i = 1; i < points.length - 1; i++) {
|
||||
double xc = (points[i].dx + points[i + 1].dx) / 2;
|
||||
double yc = (points[i].dy + points[i + 1].dy) / 2;
|
||||
Offset p2 = points[i];
|
||||
path.quadraticBezierTo(p2.dx, p2.dy, xc, yc);
|
||||
}
|
||||
|
||||
canvas.drawPath(path, paint);
|
||||
|
||||
PathMetrics pms = path.computeMetrics();
|
||||
pms.forEach((pm) {
|
||||
Tangent? tangent = pm.getTangentForOffset(pm.length * repaint.value);
|
||||
if(tangent == null) return;
|
||||
canvas.drawCircle(
|
||||
tangent.position, 5, Paint()..color = Colors.blue);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(PaperPainter oldDelegate) =>
|
||||
oldDelegate.repaint != repaint;
|
||||
}
|
||||
129
packages/idraw/lib/p13/s04.dart
Normal file
129
packages/idraw/lib/p13/s04.dart
Normal file
@@ -0,0 +1,129 @@
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
/// create by 张风捷特烈 on 2020/5/1
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatefulWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
_PaperState createState() => _PaperState();
|
||||
}
|
||||
|
||||
class _PaperState extends State<Paper> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(seconds: 15),
|
||||
vsync: this,
|
||||
)..repeat()
|
||||
;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: CustomPaint(
|
||||
painter: PaperPainter(_controller),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
final Animation<double> repaint;
|
||||
|
||||
PaperPainter(this.repaint) : super(repaint: repaint) {
|
||||
initPointsWithPolar();
|
||||
}
|
||||
|
||||
final List<Offset> points = [];
|
||||
final Path path = Path();
|
||||
final double step = 4;
|
||||
final double min = 0;
|
||||
final double max = 360;
|
||||
|
||||
void initPointsWithPolar() {
|
||||
for (double x = min; x < max; x += step) {
|
||||
double thta = (pi / 180 * x); // 角度转化为弧度
|
||||
var p = f(thta);
|
||||
points.add(Offset(p * cos(thta), p * sin(thta)));
|
||||
}
|
||||
double thta = (pi / 180 * max);
|
||||
points.add(Offset(f(thta) * cos(thta), f(thta) * sin(thta)));
|
||||
points.add(Offset(f(thta) * cos(thta), f(thta) * sin(thta)));
|
||||
}
|
||||
|
||||
double f(double thta) {
|
||||
double p = 150*sin(5*thta).abs();
|
||||
return p;
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
|
||||
Paint paint = Paint()
|
||||
..color = Colors.red
|
||||
..strokeWidth = 1.5
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
var colors = [
|
||||
Color(0xFFF60C0C),
|
||||
Color(0xFFF3B913),
|
||||
Color(0xFFE7F716),
|
||||
Color(0xFF3DF30B),
|
||||
Color(0xFF0DF6EF),
|
||||
Color(0xFF0829FB),
|
||||
Color(0xFFB709F4),
|
||||
];
|
||||
var pos = [1.0 / 7, 2.0 / 7, 3.0 / 7, 4.0 / 7, 5.0 / 7, 6.0 / 7, 1.0];
|
||||
|
||||
paint.shader = ui.Gradient.linear(
|
||||
Offset(0, 0), Offset(100, 0), colors, pos, TileMode.mirror);
|
||||
|
||||
Offset p1 = points[0];
|
||||
|
||||
|
||||
path.reset();
|
||||
path..moveTo(p1.dx, p1.dy);
|
||||
|
||||
for (var i = 1; i < points.length - 1; i++) {
|
||||
double xc = (points[i].dx + points[i + 1].dx) / 2;
|
||||
double yc = (points[i].dy + points[i + 1].dy) / 2;
|
||||
Offset p2 = points[i];
|
||||
path.quadraticBezierTo(p2.dx, p2.dy, xc, yc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
PathMetrics pms = path.computeMetrics();
|
||||
pms.forEach((pm) {
|
||||
Tangent? tangent = pm.getTangentForOffset(pm.length * repaint.value);
|
||||
if(tangent == null) return;
|
||||
canvas.drawPath(pm.extractPath(0, pm.length * repaint.value), paint);
|
||||
canvas.drawCircle(
|
||||
tangent.position, 5, Paint()..color = Colors.blue);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(PaperPainter oldDelegate) =>
|
||||
oldDelegate.repaint != repaint;
|
||||
}
|
||||
1
packages/idraw/lib/p14/p14.dart
Normal file
1
packages/idraw/lib/p14/p14.dart
Normal file
@@ -0,0 +1 @@
|
||||
export 'p14_page.dart';
|
||||
27
packages/idraw/lib/p14/p14_page.dart
Normal file
27
packages/idraw/lib/p14/p14_page.dart
Normal file
@@ -0,0 +1,27 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:components/components.dart';
|
||||
import 's01.dart' as s1;
|
||||
import 's02.dart' as s2;
|
||||
import 's03.dart' as s3;
|
||||
import 's04.dart' as s4;
|
||||
import 's05.dart' as s5;
|
||||
|
||||
class P14Page extends StatelessWidget {
|
||||
const P14Page({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const DemoShower(
|
||||
srcCodeDir: 'draw/p14',
|
||||
|
||||
demos: [
|
||||
s1.Paper(),
|
||||
s2.Paper(),
|
||||
s3.Paper(),
|
||||
s4.Paper(),
|
||||
s5.Paper(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
62
packages/idraw/lib/p14/s01.dart
Normal file
62
packages/idraw/lib/p14/s01.dart
Normal file
@@ -0,0 +1,62 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
import '../components/coordinate_pro.dart';
|
||||
|
||||
|
||||
/// create by 张风捷特烈 on 2020/5/1
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: CustomPaint(
|
||||
// 使用CustomPaint
|
||||
painter: PaperPainter(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
final Coordinate coordinate = Coordinate();
|
||||
|
||||
Offset p1 = Offset(100, 100);
|
||||
Offset p2 = Offset(120, -60);
|
||||
Paint _helpPaint = Paint();
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
coordinate.paint(canvas, size);
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
|
||||
Paint paint = Paint()
|
||||
..color = Colors.orange
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 2;
|
||||
|
||||
Path path = Path();
|
||||
path.quadraticBezierTo(p1.dx, p1.dy, p2.dx, p2.dy);
|
||||
canvas.drawPath(path, paint);
|
||||
_drawHelp(canvas);
|
||||
}
|
||||
|
||||
void _drawHelp(Canvas canvas) {
|
||||
_helpPaint
|
||||
..color = Colors.purple
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeCap = StrokeCap.round;
|
||||
canvas.drawPoints(PointMode.lines,[Offset.zero, p1, p1,p2], _helpPaint..strokeWidth=1);
|
||||
canvas.drawPoints(PointMode.points, [Offset.zero, p1, p1, p2],
|
||||
_helpPaint..strokeWidth = 8);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
||||
}
|
||||
131
packages/idraw/lib/p14/s02.dart
Normal file
131
packages/idraw/lib/p14/s02.dart
Normal file
@@ -0,0 +1,131 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../components/coordinate_pro.dart';
|
||||
import 'touch_info.dart';
|
||||
|
||||
|
||||
/// create by 张风捷特烈 on 2020/5/1
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatefulWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
_PaperState createState() => _PaperState();
|
||||
}
|
||||
|
||||
class _PaperState extends State<Paper> {
|
||||
final TouchInfo touchInfo = TouchInfo();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
touchInfo.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onPanDown: _onPanDown,
|
||||
onPanUpdate: _onPanUpdate,
|
||||
child: Container(
|
||||
color: Colors.white,
|
||||
child: CustomPaint(
|
||||
painter: PaperPainter(repaint: touchInfo),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onPanDown(DragDownDetails details) {
|
||||
if (touchInfo.points.length < 3) {
|
||||
touchInfo.addPoint(details.localPosition);
|
||||
}else{
|
||||
judgeZone(details.localPosition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _onPanUpdate(DragUpdateDetails details) {
|
||||
judgeZone(details.localPosition,update: true);
|
||||
}
|
||||
|
||||
///判断出是否在某点的半径为r圆范围内
|
||||
bool judgeCircleArea(Offset src, Offset dst, double r) =>
|
||||
(src - dst).distance <= r;
|
||||
|
||||
//判断哪个点被选中
|
||||
void judgeZone(Offset src,{bool update =false}) {
|
||||
for (int i = 0; i < touchInfo.points.length; i++) {
|
||||
if (judgeCircleArea(src, touchInfo.points[i], 15)) {
|
||||
touchInfo.selectIndex = i;
|
||||
if(update){
|
||||
touchInfo.updatePoint(i, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
final Coordinate coordinate = Coordinate();
|
||||
|
||||
Paint _helpPaint = Paint()
|
||||
..color = Colors.purple
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeCap = StrokeCap.round;
|
||||
|
||||
final TouchInfo repaint;
|
||||
|
||||
PaperPainter({ required this.repaint}) : super(repaint: repaint);
|
||||
List<Offset> pos = [];
|
||||
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
coordinate.paint(canvas, size);
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
|
||||
pos = repaint.points
|
||||
.map((e) => e.translate(-size.width / 2, -size.height / 2))
|
||||
.toList();
|
||||
|
||||
Path path = Path();
|
||||
Paint paint = Paint()
|
||||
..color = Colors.orange
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 2;
|
||||
if (pos.length < 3) {
|
||||
canvas.drawPoints(PointMode.points, pos, _helpPaint..strokeWidth = 8);
|
||||
} else {
|
||||
path.moveTo(pos[0].dx, pos[0].dy);
|
||||
path.quadraticBezierTo(pos[1].dx, pos[1].dy, pos[2].dx, pos[2].dy);
|
||||
canvas.drawPath(path, paint);
|
||||
_drawHelp(canvas);
|
||||
_drawSelectPos(canvas,size);
|
||||
}
|
||||
}
|
||||
|
||||
void _drawHelp(Canvas canvas) {
|
||||
_helpPaint..color = Colors.purple;
|
||||
canvas.drawPoints(PointMode.polygon, pos, _helpPaint..strokeWidth = 1);
|
||||
canvas.drawPoints(PointMode.points, pos, _helpPaint..strokeWidth = 8);
|
||||
}
|
||||
|
||||
void _drawSelectPos(Canvas canvas,Size size) {
|
||||
Offset? selectPos = repaint.selectPoint;
|
||||
if (selectPos == null) return;
|
||||
selectPos = selectPos.translate(-size.width / 2, -size.height / 2);
|
||||
canvas.drawCircle(
|
||||
selectPos,
|
||||
10,
|
||||
_helpPaint
|
||||
..color = Colors.green
|
||||
..strokeWidth = 2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(PaperPainter oldDelegate) =>
|
||||
oldDelegate.repaint != repaint;
|
||||
}
|
||||
127
packages/idraw/lib/p14/s03.dart
Normal file
127
packages/idraw/lib/p14/s03.dart
Normal file
@@ -0,0 +1,127 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../components/coordinate_pro.dart';
|
||||
import 'touch_info.dart';
|
||||
|
||||
class Paper extends StatefulWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
_PaperState createState() => _PaperState();
|
||||
}
|
||||
|
||||
class _PaperState extends State<Paper> {
|
||||
final TouchInfo touchInfo = TouchInfo();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
touchInfo.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onPanDown: _onPanDown,
|
||||
onPanUpdate: _onPanUpdate,
|
||||
child: Container(
|
||||
color: Colors.white,
|
||||
child: CustomPaint(
|
||||
painter: PaperPainter(repaint: touchInfo),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onPanDown(DragDownDetails details) {
|
||||
if (touchInfo.points.length < 4) {
|
||||
touchInfo.addPoint(details.localPosition);
|
||||
}else{
|
||||
judgeZone(details.localPosition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _onPanUpdate(DragUpdateDetails details) {
|
||||
judgeZone(details.localPosition,update: true);
|
||||
}
|
||||
|
||||
///判断出是否在某点的半径为r圆范围内
|
||||
bool judgeCircleArea(Offset src, Offset dst, double r) =>
|
||||
(src - dst).distance <= r;
|
||||
|
||||
//判断哪个点被选中
|
||||
void judgeZone(Offset src,{bool update =false}) {
|
||||
for (int i = 0; i < touchInfo.points.length; i++) {
|
||||
if (judgeCircleArea(src, touchInfo.points[i], 15)) {
|
||||
touchInfo.selectIndex = i;
|
||||
if(update){
|
||||
touchInfo.updatePoint(i, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
final Coordinate coordinate = Coordinate();
|
||||
|
||||
Paint _helpPaint = Paint()
|
||||
..color = Colors.purple
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeCap = StrokeCap.round;
|
||||
|
||||
final TouchInfo repaint;
|
||||
|
||||
PaperPainter({required this.repaint}) : super(repaint: repaint);
|
||||
List<Offset> pos = [];
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
coordinate.paint(canvas, size);
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
|
||||
pos = repaint.points
|
||||
.map((e) => e.translate(-size.width / 2, -size.height / 2))
|
||||
.toList();
|
||||
|
||||
Path path = Path();
|
||||
Paint paint = Paint()
|
||||
..color = Colors.orange
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 2;
|
||||
if (pos.length < 4) {
|
||||
canvas.drawPoints(PointMode.points, pos, _helpPaint..strokeWidth = 8);
|
||||
} else {
|
||||
path.moveTo(pos[0].dx, pos[0].dy);
|
||||
path.cubicTo(pos[1].dx, pos[1].dy, pos[2].dx, pos[2].dy, pos[3].dx, pos[3].dy);
|
||||
canvas.drawPath(path, paint);
|
||||
_drawHelp(canvas);
|
||||
_drawSelectPos(canvas,size);
|
||||
}
|
||||
}
|
||||
|
||||
void _drawHelp(Canvas canvas) {
|
||||
_helpPaint..color = Colors.purple;
|
||||
canvas.drawPoints(PointMode.polygon, pos, _helpPaint..strokeWidth = 1);
|
||||
canvas.drawPoints(PointMode.points, pos, _helpPaint..strokeWidth = 8);
|
||||
}
|
||||
|
||||
void _drawSelectPos(Canvas canvas,Size size) {
|
||||
Offset? selectPos = repaint.selectPoint;
|
||||
if (selectPos == null) return;
|
||||
selectPos = selectPos.translate(-size.width / 2, -size.height / 2);
|
||||
canvas.drawCircle(
|
||||
selectPos,
|
||||
10,
|
||||
_helpPaint
|
||||
..color = Colors.green
|
||||
..strokeWidth = 2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(PaperPainter oldDelegate) =>
|
||||
oldDelegate.repaint != repaint;
|
||||
}
|
||||
170
packages/idraw/lib/p14/s04.dart
Normal file
170
packages/idraw/lib/p14/s04.dart
Normal file
@@ -0,0 +1,170 @@
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import '../components/coordinate_pro.dart';
|
||||
import 'touch_info.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/5/1
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatefulWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
_PaperState createState() => _PaperState();
|
||||
}
|
||||
|
||||
class _PaperState extends State<Paper> {
|
||||
final TouchInfo touchInfo = TouchInfo();
|
||||
|
||||
//单位圆(即半径为1)控制线长
|
||||
final rate = 0.551915024494;
|
||||
double _radius = 150;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
touchInfo.setPoints(_initPoints());
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
touchInfo.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
List<Offset> _initPoints() {
|
||||
final List<Offset> pos = [];
|
||||
//第一段线
|
||||
pos.add(Offset(0, rate) * _radius);
|
||||
pos.add(Offset(1 - rate, 1) * _radius);
|
||||
pos.add(Offset(1, 1) * _radius);
|
||||
//第二段线
|
||||
pos.add(Offset(1 + rate, 1) * _radius);
|
||||
pos.add(Offset(2, rate) * _radius);
|
||||
pos.add(Offset(2, 0) * _radius);
|
||||
//第三段线
|
||||
pos.add(Offset(2, -rate) * _radius);
|
||||
pos.add(Offset(1 + rate, -1) * _radius);
|
||||
pos.add(Offset(1, -1) * _radius);
|
||||
//第四段线
|
||||
pos.add(Offset(1 - rate, -1) * _radius);
|
||||
pos.add(Offset(0, -rate) * _radius);
|
||||
pos.add(Offset(0, 0));
|
||||
return pos;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder:(_,cts)=> GestureDetector(
|
||||
onPanDown: (details)=>_onPanDown(details,cts.biggest),
|
||||
onPanUpdate: (details)=>_onPanUpdate(details,cts.biggest),
|
||||
child: Container(
|
||||
color: Colors.white,
|
||||
child: CustomPaint(
|
||||
painter: PaperPainter(repaint: touchInfo),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onPanDown(DragDownDetails details,Size size) {
|
||||
print("=====${details}===========${touchInfo.points.length}}");
|
||||
if (touchInfo.points.length < 4) {
|
||||
touchInfo.addPoint(details.localPosition);
|
||||
} else {
|
||||
judgeZone(details.localPosition,size);
|
||||
}
|
||||
}
|
||||
|
||||
void _onPanUpdate(DragUpdateDetails details,Size size) {
|
||||
judgeZone(details.localPosition,size, update: true);
|
||||
}
|
||||
|
||||
///判断出是否在某点的半径为r圆范围内
|
||||
bool judgeCircleArea(Offset src, Offset dst, double r) =>
|
||||
(src - dst).distance <= r;
|
||||
|
||||
//判断哪个点被选中
|
||||
void judgeZone(Offset src, Size size,{bool update = false}) {
|
||||
src= src.translate(-size.width/2, -size.height/2);
|
||||
for (int i = 0; i < touchInfo.points.length; i++) {
|
||||
if (judgeCircleArea(src, touchInfo.points[i], 15)) {
|
||||
touchInfo.selectIndex = i;
|
||||
if (update) {
|
||||
touchInfo.updatePoint(i, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
final Coordinate coordinate = Coordinate();
|
||||
|
||||
Paint _helpPaint = Paint()
|
||||
..color = Colors.purple
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeCap = StrokeCap.round;
|
||||
|
||||
final TouchInfo repaint;
|
||||
|
||||
PaperPainter({required this.repaint}) : super(repaint: repaint);
|
||||
List<Offset> pos = [];
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
coordinate.paint(canvas, size);
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
|
||||
pos = repaint.points;
|
||||
|
||||
Path path = Path();
|
||||
Paint paint = Paint()
|
||||
..color = Colors.orange
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 2;
|
||||
path.moveTo(0, 0);
|
||||
for (int i = 0; i < pos.length / 3; i++) {
|
||||
path.cubicTo(pos[3 * i + 0].dx, pos[3 * i + 0].dy, pos[3 * i + 1].dx,
|
||||
pos[3 * i + 1].dy, pos[3 * i + 2].dx, pos[3 * i + 2].dy);
|
||||
}
|
||||
|
||||
canvas.drawPath(path, paint);
|
||||
_drawHelp(canvas);
|
||||
_drawSelectPos(canvas, size);
|
||||
}
|
||||
|
||||
void _drawHelp(Canvas canvas) {
|
||||
|
||||
_helpPaint..strokeWidth = 1..color=Colors.purple;
|
||||
canvas.drawLine(pos[0], pos[11], _helpPaint);
|
||||
canvas.drawLine(pos[1], pos[2], _helpPaint);
|
||||
canvas.drawLine(pos[2], pos[3], _helpPaint);
|
||||
canvas.drawLine(pos[4], pos[5], _helpPaint);
|
||||
canvas.drawLine(pos[5], pos[6], _helpPaint);
|
||||
canvas.drawLine(pos[7], pos[8], _helpPaint);
|
||||
canvas.drawLine(pos[8], pos[9], _helpPaint);
|
||||
canvas.drawLine(pos[10], pos[11], _helpPaint);
|
||||
canvas.drawLine(pos[11], pos[0], _helpPaint);
|
||||
canvas.drawPoints(PointMode.points, pos, _helpPaint..strokeWidth = 8);
|
||||
}
|
||||
|
||||
void _drawSelectPos(Canvas canvas, Size size) {
|
||||
Offset? selectPos = repaint.selectPoint;
|
||||
if (selectPos == null) return;
|
||||
|
||||
canvas.drawCircle(selectPos, 10,
|
||||
_helpPaint..color = Colors.green..strokeWidth = 2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(PaperPainter oldDelegate) =>
|
||||
oldDelegate.repaint != repaint;
|
||||
}
|
||||
132
packages/idraw/lib/p14/s05.dart
Normal file
132
packages/idraw/lib/p14/s05.dart
Normal file
@@ -0,0 +1,132 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../components/coordinate_pro.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/5/1
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: CustomPaint(
|
||||
// 使用CustomPaint
|
||||
painter: PaperPainter(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
final Coordinate coordinate = Coordinate();
|
||||
|
||||
|
||||
List<Offset> points1 = [
|
||||
Offset(0, 20),
|
||||
Offset(40, 40) ,
|
||||
Offset(80, -20),
|
||||
Offset(120, -40),
|
||||
Offset(160, -80),
|
||||
Offset(200, -20),
|
||||
Offset(240, -40),
|
||||
];
|
||||
List<Offset> points2 = [
|
||||
Offset(0, 0),
|
||||
Offset(40, -20) ,
|
||||
Offset(80, -40),
|
||||
Offset(120, -80),
|
||||
Offset(160, -40),
|
||||
Offset(200, 20),
|
||||
Offset(240, 40),
|
||||
];
|
||||
List<Offset> helpPoints = [
|
||||
|
||||
];
|
||||
|
||||
Paint _helpPaint = Paint();
|
||||
|
||||
Path _linePath = Path();
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
coordinate.paint(canvas, size);
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
|
||||
Paint paint = Paint()
|
||||
..color = Colors.red
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 1;
|
||||
|
||||
Path path = Path();
|
||||
addBezierPathWithPoints(path, points2);
|
||||
canvas.drawPath(path, paint);
|
||||
|
||||
addBezierPathWithPoints(_linePath, points1);
|
||||
canvas.drawPath(_linePath, paint..color=Colors.orange);
|
||||
|
||||
_drawHelp(canvas);
|
||||
}
|
||||
|
||||
void addBezierPathWithPoints(Path path, List<Offset> points) {
|
||||
for (int i = 0; i < points.length - 1; i++) {
|
||||
Offset current = points[i];
|
||||
Offset next = points[i+1];
|
||||
if (i == 0) {
|
||||
path.moveTo(current.dx, current.dy);
|
||||
// 控制点
|
||||
double ctrlX = current.dx + (next.dx - current.dx) / 2;
|
||||
double ctrlY = next.dy;
|
||||
path.quadraticBezierTo(ctrlX, ctrlY, next.dx, next.dy);
|
||||
} else if (i < points.length - 2) {
|
||||
// 控制点 1
|
||||
double ctrl1X = current.dx + (next.dx - current.dx) / 2;
|
||||
double ctrl1Y = current.dy;
|
||||
// 控制点 2
|
||||
double ctrl2X = ctrl1X;
|
||||
double ctrl2Y = next.dy;
|
||||
path.cubicTo(ctrl1X,ctrl1Y,ctrl2X,ctrl2Y,next.dx,next.dy);
|
||||
}else{
|
||||
// 控制点
|
||||
double ctrlX = (next.dx - current.dx) / 2;
|
||||
double ctrlY = 0;
|
||||
path.relativeQuadraticBezierTo(ctrlX, ctrlY, next.dx-current.dx, next.dy-current.dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _drawHelp(Canvas canvas) {
|
||||
|
||||
_helpPaint
|
||||
..style = PaintingStyle.stroke;
|
||||
points1.forEach((element) {
|
||||
canvas.drawCircle(element, 2, _helpPaint..strokeWidth=1..color=Colors.orange);
|
||||
});
|
||||
|
||||
points2.forEach((element) {
|
||||
canvas.drawCircle(element, 2, _helpPaint..strokeWidth=1..color=Colors.red);
|
||||
});
|
||||
|
||||
// canvas.drawPoints(PointMode.polygon, points1, _helpPaint..strokeWidth=0.5..color=Colors.red);// _drawHelp(canvas);
|
||||
// canvas.drawPoints(PointMode.polygon, points2, _helpPaint..strokeWidth=0.5..color=Colors.red);// _drawHelp(canvas);
|
||||
// canvas.drawPoints(PointMode.polygon, helpPoints, _helpPaint..strokeWidth=0.5..color=Colors.red);// _drawHelp(canvas);
|
||||
|
||||
|
||||
|
||||
// _helpPaint
|
||||
// ..color = Colors.purple
|
||||
// ..style = PaintingStyle.stroke
|
||||
// ..strokeCap = StrokeCap.round;
|
||||
// canvas.drawPoints(PointMode.lines, [Offset.zero, p1, p1, p2],
|
||||
// _helpPaint..strokeWidth = 1);
|
||||
// canvas.drawPoints(PointMode.points, [Offset.zero, p1, p1, p2],
|
||||
// _helpPaint..strokeWidth = 8);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
||||
}
|
||||
45
packages/idraw/lib/p14/touch_info.dart
Normal file
45
packages/idraw/lib/p14/touch_info.dart
Normal file
@@ -0,0 +1,45 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/4
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class TouchInfo extends ChangeNotifier {
|
||||
List<Offset> _points = [];
|
||||
int _selectIndex = -1;
|
||||
|
||||
void setPoints(List<Offset> points) {
|
||||
_points = points;
|
||||
}
|
||||
|
||||
|
||||
int get selectIndex => _selectIndex;
|
||||
|
||||
List<Offset> get points => _points;
|
||||
|
||||
set selectIndex(int value) {
|
||||
assert(value != null);
|
||||
if (_selectIndex == value) return;
|
||||
|
||||
_selectIndex = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void addPoint(Offset point) {
|
||||
points.add(point);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void updatePoint(int index, Offset point) {
|
||||
points[index] = point;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_points.clear();
|
||||
_selectIndex = -1;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Offset? get selectPoint => _selectIndex == -1 ? null : _points[_selectIndex];
|
||||
}
|
||||
1
packages/idraw/lib/p15/p15.dart
Normal file
1
packages/idraw/lib/p15/p15.dart
Normal file
@@ -0,0 +1 @@
|
||||
export 'p15_page.dart';
|
||||
29
packages/idraw/lib/p15/p15_page.dart
Normal file
29
packages/idraw/lib/p15/p15_page.dart
Normal file
@@ -0,0 +1,29 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:components/components.dart';
|
||||
import 's01.dart' as s1;
|
||||
import 's02.dart' as s2;
|
||||
import 's03.dart' as s3;
|
||||
import 's04.dart' as s4;
|
||||
import 's05.dart' as s5;
|
||||
import 's06.dart' as s6;
|
||||
|
||||
class P15Page extends StatelessWidget {
|
||||
const P15Page({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const DemoShower(
|
||||
srcCodeDir: 'draw/p15',
|
||||
|
||||
demos: [
|
||||
s1.Paper(),
|
||||
s2.Paper(),
|
||||
s3.Paper(),
|
||||
s4.Paper(),
|
||||
s5.Paper(),
|
||||
s6.Paper(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
68
packages/idraw/lib/p15/s01.dart
Normal file
68
packages/idraw/lib/p15/s01.dart
Normal file
@@ -0,0 +1,68 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
import '../components/coordinate_pro.dart';
|
||||
|
||||
|
||||
/// create by 张风捷特烈 on 2020/5/1
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: CustomPaint(
|
||||
// 使用CustomPaint
|
||||
painter: PaperPainter(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
final Coordinate coordinate = Coordinate();
|
||||
Paint _helpPaint = Paint();
|
||||
|
||||
double waveWidth = 80;
|
||||
double wrapHeight=0;
|
||||
|
||||
double waveHeight = 40;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
coordinate.paint(canvas, size);
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
|
||||
Path path = Path();
|
||||
Paint paint = Paint()
|
||||
..color = Colors.orange
|
||||
..style = PaintingStyle.fill
|
||||
..strokeWidth = 2;
|
||||
|
||||
path.relativeQuadraticBezierTo( waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo( waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo( waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo( waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
||||
|
||||
canvas.drawPath(path, paint);
|
||||
_drawHelp(canvas);
|
||||
}
|
||||
|
||||
void _drawHelp(Canvas canvas) {
|
||||
_helpPaint
|
||||
..color = Colors.purple
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeCap = StrokeCap.round;
|
||||
canvas.drawPoints(PointMode.polygon,[Offset.zero, Offset(waveWidth / 2, -waveHeight * 2), Offset(waveWidth , 0)], _helpPaint..strokeWidth=1);
|
||||
canvas.drawPoints(PointMode.points, [Offset.zero, Offset(waveWidth / 2, -waveHeight * 2), Offset(waveWidth , 0)],
|
||||
_helpPaint..strokeWidth = 8);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
||||
}
|
||||
69
packages/idraw/lib/p15/s02.dart
Normal file
69
packages/idraw/lib/p15/s02.dart
Normal file
@@ -0,0 +1,69 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../components/coordinate_pro.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/5/1
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: CustomPaint(
|
||||
// 使用CustomPaint
|
||||
painter: PaperPainter(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
final Coordinate coordinate = Coordinate();
|
||||
Paint _helpPaint = Paint();
|
||||
|
||||
double waveWidth = 80;
|
||||
double wrapHeight =100;
|
||||
double waveHeight = 40;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
coordinate.paint(canvas, size);
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
|
||||
Path path = Path();
|
||||
Paint paint = Paint()
|
||||
..color = Colors.orange
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 2;
|
||||
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(-2*waveWidth, 0);
|
||||
path.moveTo(0, 0);
|
||||
path.relativeQuadraticBezierTo(waveWidth/2, -waveHeight*2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo(waveWidth/2, waveHeight*2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo(waveWidth/2, -waveHeight*2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo(waveWidth/2, waveHeight*2, waveWidth, 0);
|
||||
path.close();
|
||||
canvas.drawPath(path, paint..style=PaintingStyle.fill);
|
||||
canvas.restore();
|
||||
|
||||
_drawHelp(canvas);
|
||||
|
||||
}
|
||||
|
||||
void _drawHelp(Canvas canvas) {
|
||||
_helpPaint
|
||||
..color = Colors.purple
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeCap = StrokeCap.round;
|
||||
canvas.drawRect(Rect.fromPoints(Offset(0,-100), Offset(160,100)), _helpPaint..strokeWidth=2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
||||
}
|
||||
96
packages/idraw/lib/p15/s03.dart
Normal file
96
packages/idraw/lib/p15/s03.dart
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../components/coordinate_pro.dart';
|
||||
|
||||
class Paper extends StatefulWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
_PaperState createState() => _PaperState();
|
||||
}
|
||||
|
||||
class _PaperState extends State<Paper> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
vsync: this,
|
||||
)..repeat();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: CustomPaint(
|
||||
painter: PaperPainter(_controller),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
final Coordinate coordinate = Coordinate();
|
||||
Paint _helpPaint = Paint();
|
||||
|
||||
final Animation<double> repaint;
|
||||
|
||||
PaperPainter(this.repaint) : super(repaint: repaint);
|
||||
|
||||
double waveWidth = 80;
|
||||
double wrapHeight = 100;
|
||||
double waveHeight = 20;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
coordinate.paint(canvas, size);
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
|
||||
Path path = Path();
|
||||
Paint paint = Paint()
|
||||
..color = Colors.orange
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 2;
|
||||
|
||||
canvas.save();
|
||||
// canvas.translate(-2*waveWidth, 0);
|
||||
canvas.translate(-2 * waveWidth + 2 * waveWidth * repaint.value, 0);
|
||||
path.moveTo(0, 0);
|
||||
path.relativeQuadraticBezierTo(
|
||||
waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo(waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo(
|
||||
waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo(waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
||||
path.relativeLineTo(0, wrapHeight);
|
||||
path.relativeLineTo(-waveWidth * 2 * 2.0, 0);
|
||||
path.close();
|
||||
canvas.drawPath(path, paint..style = PaintingStyle.fill);
|
||||
canvas.restore();
|
||||
|
||||
_drawHelp(canvas);
|
||||
}
|
||||
|
||||
void _drawHelp(Canvas canvas) {
|
||||
_helpPaint
|
||||
..color = Colors.purple
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeCap = StrokeCap.round;
|
||||
canvas.drawRect(Rect.fromPoints(Offset(0, -100), Offset(160, 100)),
|
||||
_helpPaint..strokeWidth = 2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(PaperPainter oldDelegate) =>
|
||||
oldDelegate.repaint != repaint;
|
||||
}
|
||||
106
packages/idraw/lib/p15/s04.dart
Normal file
106
packages/idraw/lib/p15/s04.dart
Normal file
@@ -0,0 +1,106 @@
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import '../components/coordinate_pro.dart';
|
||||
import 'touch_info.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/5/1
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatefulWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
_PaperState createState() => _PaperState();
|
||||
}
|
||||
|
||||
class _PaperState extends State<Paper> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
vsync: this,
|
||||
)..repeat();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: CustomPaint(
|
||||
painter: PaperPainter(CurveTween(curve: Curves.easeInOutQuad).animate(_controller)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
final Coordinate coordinate = Coordinate();
|
||||
Paint _helpPaint = Paint();
|
||||
|
||||
final Animation<double> repaint;
|
||||
|
||||
PaperPainter(this.repaint) : super(repaint: repaint);
|
||||
|
||||
double waveWidth = 80;
|
||||
double wrapHeight = 100;
|
||||
double waveHeight = 20;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
coordinate.paint(canvas, size);
|
||||
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
canvas.clipRect((Rect.fromCenter(
|
||||
center: Offset( waveWidth, 0),width: waveWidth*2,height: 200.0)));
|
||||
Path path = Path();
|
||||
Paint paint = Paint()
|
||||
..color = Colors.orange
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 2;
|
||||
|
||||
canvas.save();
|
||||
// canvas.translate(-2*waveWidth, 0);
|
||||
canvas.translate(-2 * waveWidth + 2 * waveWidth * repaint.value, 0);
|
||||
path.moveTo(0, 0);
|
||||
path.relativeQuadraticBezierTo(
|
||||
waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo(waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo(
|
||||
waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo(waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
||||
path.relativeLineTo(0, wrapHeight);
|
||||
path.relativeLineTo(-waveWidth * 2 * 2.0, 0);
|
||||
path.close();
|
||||
canvas.drawPath(path, paint..style = PaintingStyle.fill);
|
||||
canvas.restore();
|
||||
|
||||
_drawHelp(canvas);
|
||||
}
|
||||
|
||||
void _drawHelp(Canvas canvas) {
|
||||
_helpPaint
|
||||
..color = Colors.purple
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeCap = StrokeCap.round;
|
||||
canvas.drawRect(Rect.fromPoints(Offset(0, -100), Offset(160, 100)),
|
||||
_helpPaint..strokeWidth = 2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(PaperPainter oldDelegate) =>
|
||||
oldDelegate.repaint != repaint;
|
||||
}
|
||||
97
packages/idraw/lib/p15/s05.dart
Normal file
97
packages/idraw/lib/p15/s05.dart
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../components/coordinate_pro.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/5/1
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatefulWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
_PaperState createState() => _PaperState();
|
||||
}
|
||||
|
||||
class _PaperState extends State<Paper> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(milliseconds: 1000),
|
||||
vsync: this,
|
||||
)
|
||||
..repeat()
|
||||
;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: CustomPaint(
|
||||
painter: PaperPainter(
|
||||
CurveTween(curve: Curves.linear).animate(_controller)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
|
||||
final Animation<double> repaint;
|
||||
|
||||
PaperPainter(this.repaint) : super(repaint: repaint);
|
||||
|
||||
double waveWidth = 80;
|
||||
double wrapHeight = 100;
|
||||
double waveHeight = 10;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
canvas.clipRect((Rect.fromCenter(
|
||||
center: Offset(waveWidth, 0), width: waveWidth * 2, height: 200.0)));
|
||||
|
||||
Paint paint = Paint();
|
||||
|
||||
Path path = getWavePath();
|
||||
canvas.translate(-4 * waveWidth + 2 * waveWidth * repaint.value, 0);
|
||||
canvas.drawPath(path, paint..color = Colors.orange);
|
||||
|
||||
canvas.translate(2*waveWidth* repaint.value, 0);
|
||||
canvas.drawPath(path, paint..color = Colors.orange.withAlpha(88));
|
||||
|
||||
}
|
||||
|
||||
Path getWavePath() {
|
||||
Path path = Path();
|
||||
path.relativeQuadraticBezierTo(
|
||||
waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo(
|
||||
waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo(
|
||||
waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo(
|
||||
waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo(
|
||||
waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
||||
path.relativeQuadraticBezierTo(
|
||||
waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
||||
path.relativeLineTo(0, wrapHeight);
|
||||
path.relativeLineTo(-waveWidth * 3 * 2.0, 0);
|
||||
return path;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(PaperPainter oldDelegate) =>
|
||||
oldDelegate.repaint != repaint;
|
||||
}
|
||||
192
packages/idraw/lib/p15/s06.dart
Normal file
192
packages/idraw/lib/p15/s06.dart
Normal file
@@ -0,0 +1,192 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../components/coordinate_pro.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/5/1
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(child: Wrap(
|
||||
spacing: 30,
|
||||
runSpacing: 30,
|
||||
children: List.generate(12, (v) => 0.1 * v+0.1)
|
||||
.map((e) => TolyWaveLoading(
|
||||
isOval: (e*10).toInt().isEven, // 是否椭圆裁切
|
||||
progress: 0.5, // 进度
|
||||
waveHeight: 3, //波浪高
|
||||
color: [Colors.blue,Colors.red,Colors.green][(e*10).toInt()%3], //颜色
|
||||
)).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TolyWaveLoading extends StatefulWidget {
|
||||
// 波高
|
||||
final double waveHeight;
|
||||
|
||||
// 进度
|
||||
final double progress;
|
||||
|
||||
// 颜色
|
||||
final Color color;
|
||||
|
||||
// 尺寸
|
||||
final Size size;
|
||||
|
||||
// 底波透明度
|
||||
final int secondAlpha;
|
||||
|
||||
// 边线宽
|
||||
final double strokeWidth;
|
||||
|
||||
// 圆角半径
|
||||
final double borderRadius;
|
||||
|
||||
// 是否是椭圆
|
||||
final bool isOval;
|
||||
final Duration duration;
|
||||
|
||||
final Curve curve;
|
||||
|
||||
const TolyWaveLoading(
|
||||
{Key? key,
|
||||
this.waveHeight = 5,
|
||||
this.progress = 0.5,
|
||||
this.duration = const Duration(seconds: 1),
|
||||
this.size = const Size(100, 100),
|
||||
this.color = Colors.green,
|
||||
this.secondAlpha = 88,
|
||||
this.strokeWidth = 3,
|
||||
this.curve = Curves.linear,
|
||||
this.borderRadius = 20,
|
||||
this.isOval = false})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_TolyWaveLoadingState createState() => _TolyWaveLoadingState();
|
||||
}
|
||||
|
||||
class _TolyWaveLoadingState extends State<TolyWaveLoading>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: widget.duration,
|
||||
vsync: this,
|
||||
)..repeat();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomPaint(
|
||||
size: widget.size,
|
||||
painter: PaperPainter(
|
||||
waveHeight: widget.waveHeight,
|
||||
secondAlpha: widget.secondAlpha,
|
||||
color: widget.color,
|
||||
borderRadius: widget.borderRadius,
|
||||
isOval: widget.isOval,
|
||||
progress: widget.progress,
|
||||
strokeWidth: widget.strokeWidth,
|
||||
repaint: CurveTween(curve: widget.curve).animate(_controller)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PaperPainter extends CustomPainter {
|
||||
final Animation<double> repaint;
|
||||
|
||||
PaperPainter({
|
||||
required this.repaint,
|
||||
required this.waveHeight,
|
||||
required this.color,
|
||||
required this.progress,
|
||||
required this.secondAlpha,
|
||||
required this.borderRadius,
|
||||
required this.isOval,
|
||||
required this.strokeWidth,
|
||||
}) : super(repaint: repaint);
|
||||
|
||||
final double waveHeight;
|
||||
final double progress;
|
||||
final Color color;
|
||||
final double strokeWidth;
|
||||
final int secondAlpha;
|
||||
final double borderRadius;
|
||||
final bool isOval;
|
||||
Path path = Path();
|
||||
Paint _mainPaint = Paint();
|
||||
Path _mainPath = Path();
|
||||
double waveWidth = 0;
|
||||
double wrapHeight = 0;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
// 由于 使用 repaint 触发更新 path 和 _mainPath 不会重新创建
|
||||
// 而导致刷新时不断为 path 和 _mainPath 添加路径,导致路径非常庞大,越来越卡,而掉帧
|
||||
// 处理方案一: 绘制前 重置 path 或者
|
||||
// 处理方案二: 不将 path 设为成员变量,每次绘制都新建 Path 对象,这样会造成大量 Path 对象创建,测试发现两种方案结果差不多。
|
||||
path.reset();
|
||||
_mainPath.reset();
|
||||
|
||||
waveWidth = size.width / 2;
|
||||
wrapHeight = size.height;
|
||||
|
||||
_mainPaint..strokeWidth = strokeWidth..style = PaintingStyle.stroke..color = color;
|
||||
|
||||
if (!isOval) {
|
||||
path.addRRect(RRect.fromRectXY(Offset(0, 0) & size, borderRadius, borderRadius));
|
||||
canvas.clipPath(path);
|
||||
canvas.drawPath(path,_mainPaint);
|
||||
}
|
||||
if (isOval) {
|
||||
path.addOval(Offset(0, 0) & size);
|
||||
canvas.clipPath(path);
|
||||
canvas.drawPath(path, _mainPaint);
|
||||
}
|
||||
|
||||
canvas.translate(-4 * waveWidth + 2 * waveWidth * repaint.value, wrapHeight + waveHeight);
|
||||
drawWave(canvas);
|
||||
canvas.drawPath(_mainPath, _mainPaint..style = PaintingStyle.fill..color = color);
|
||||
|
||||
canvas.translate(2 * waveWidth * repaint.value, 0);
|
||||
drawWave(canvas);
|
||||
canvas.drawPath(_mainPath, _mainPaint..color = color.withAlpha(88));
|
||||
}
|
||||
|
||||
void drawWave(Canvas canvas) {
|
||||
_mainPath.moveTo(0, 0);
|
||||
_mainPath.relativeLineTo(0, -wrapHeight * progress);
|
||||
_mainPath.relativeQuadraticBezierTo(waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
||||
_mainPath.relativeQuadraticBezierTo(waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
||||
_mainPath.relativeQuadraticBezierTo(waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
||||
_mainPath.relativeQuadraticBezierTo(waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
||||
_mainPath.relativeQuadraticBezierTo(waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
||||
_mainPath.relativeQuadraticBezierTo(waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
||||
_mainPath.relativeLineTo(0, wrapHeight);
|
||||
_mainPath.relativeLineTo(-waveWidth * 3 * 2.0, 0);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(PaperPainter oldDelegate) =>
|
||||
oldDelegate.repaint != repaint|| oldDelegate.waveHeight != waveHeight||
|
||||
oldDelegate.progress != progress|| oldDelegate.color != color||
|
||||
oldDelegate.strokeWidth != strokeWidth|| oldDelegate.isOval != isOval||
|
||||
oldDelegate.secondAlpha != secondAlpha|| oldDelegate.borderRadius != borderRadius;
|
||||
}
|
||||
|
||||
45
packages/idraw/lib/p15/touch_info.dart
Normal file
45
packages/idraw/lib/p15/touch_info.dart
Normal file
@@ -0,0 +1,45 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/4
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class TouchInfo extends ChangeNotifier {
|
||||
List<Offset> _points = [];
|
||||
int _selectIndex = -1;
|
||||
|
||||
void setPoints(List<Offset> points) {
|
||||
_points = points;
|
||||
}
|
||||
|
||||
|
||||
int get selectIndex => _selectIndex;
|
||||
|
||||
List<Offset> get points => _points;
|
||||
|
||||
set selectIndex(int value) {
|
||||
assert(value != null);
|
||||
if (_selectIndex == value) return;
|
||||
|
||||
_selectIndex = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void addPoint(Offset point) {
|
||||
points.add(point);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void updatePoint(int index, Offset point) {
|
||||
points[index] = point;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_points.clear();
|
||||
_selectIndex = -1;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Offset? get selectPoint => _selectIndex == -1 ? null : _points[_selectIndex];
|
||||
}
|
||||
1
packages/idraw/lib/p16/p16.dart
Normal file
1
packages/idraw/lib/p16/p16.dart
Normal file
@@ -0,0 +1 @@
|
||||
export 'p16_page.dart';
|
||||
29
packages/idraw/lib/p16/p16_page.dart
Normal file
29
packages/idraw/lib/p16/p16_page.dart
Normal file
@@ -0,0 +1,29 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:components/components.dart';
|
||||
import 's01.dart' as s1;
|
||||
import 's02.dart' as s2;
|
||||
import 's03.dart' as s3;
|
||||
import 's04.dart' as s4;
|
||||
import 's05.dart' as s5;
|
||||
import 's06.dart' as s6;
|
||||
|
||||
class P16Page extends StatelessWidget {
|
||||
const P16Page({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const DemoShower(
|
||||
srcCodeDir: 'draw/p16',
|
||||
|
||||
demos: [
|
||||
s1.Paper(),
|
||||
s2.Paper(),
|
||||
s3.Paper(),
|
||||
s4.Paper(),
|
||||
s5.Paper(),
|
||||
s6.Paper(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
172
packages/idraw/lib/p16/s01.dart
Normal file
172
packages/idraw/lib/p16/s01.dart
Normal file
@@ -0,0 +1,172 @@
|
||||
import 'dart:math';
|
||||
|
||||
// import 'dart:ui' as ui;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/5
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: const ICharts(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ICharts extends StatelessWidget {
|
||||
const ICharts({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(alignment: Alignment.topCenter, children: [
|
||||
Container(
|
||||
width: 350,
|
||||
height: 250,
|
||||
padding: EdgeInsets.only(top: 40, right: 20, bottom: 20, left: 20),
|
||||
child: CustomPaint(
|
||||
painter: ChartPainter(),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top:8.0),
|
||||
child: Text(
|
||||
"捷特数学成绩统计图 - 2040 年",
|
||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
|
||||
),
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
const double _kScaleHeight = 8; // 刻度高
|
||||
const double _kBarPadding = 10; // 柱状图前间隔
|
||||
|
||||
class ChartPainter extends CustomPainter {
|
||||
final TextPainter _textPainter =
|
||||
TextPainter(textDirection: TextDirection.ltr);
|
||||
|
||||
final List<double> yData = [88, 98, 70, 80, 100, 75];
|
||||
final List<String> xData = ["7月", "8月", "9月", "10月", "11月", "12月"];
|
||||
|
||||
// final List<String> xData = [ "语文","数学", "英语", "物理", "化学", "生物"];
|
||||
|
||||
Path axisPath = Path();
|
||||
Paint axisPaint = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 1;
|
||||
|
||||
Paint gridPaint = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..color = Colors.grey
|
||||
..strokeWidth = 0.5;
|
||||
Paint fillPaint = Paint()..color = Colors.red;
|
||||
|
||||
double xStep = 0; // x 间隔
|
||||
double yStep = 0; // y 间隔
|
||||
|
||||
double maxData = 0; // 数据最大值
|
||||
|
||||
ChartPainter() {
|
||||
maxData = yData.reduce(max);
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
// canvas.drawRect(
|
||||
// Offset.zero & size, Paint()..color = Colors.black.withAlpha(22));
|
||||
canvas.translate(0, size.height);
|
||||
canvas.translate(_kScaleHeight, -_kScaleHeight);
|
||||
|
||||
axisPath.moveTo(-_kScaleHeight, 0);
|
||||
axisPath.relativeLineTo(size.width, 0);
|
||||
axisPath.moveTo(0, _kScaleHeight);
|
||||
axisPath.relativeLineTo(0, -size.height);
|
||||
canvas.drawPath(axisPath, axisPaint);
|
||||
|
||||
drawYText(canvas, size);
|
||||
drawXText(canvas, size);
|
||||
drawBarChart(canvas, size);
|
||||
}
|
||||
|
||||
void drawXText(Canvas canvas, Size size) {
|
||||
xStep = (size.width - _kScaleHeight) / xData.length;
|
||||
canvas.save();
|
||||
canvas.translate(xStep, 0);
|
||||
for (int i = 0; i < xData.length; i++) {
|
||||
canvas.drawLine(Offset(0, 0), Offset(0, _kScaleHeight), axisPaint);
|
||||
_drawAxisText(canvas, xData[i],
|
||||
alignment: Alignment.center, offset: Offset(-xStep / 2, 10));
|
||||
canvas.translate(xStep, 0);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void drawBarChart(Canvas canvas, Size size) {
|
||||
canvas.save();
|
||||
canvas.translate(xStep, 0);
|
||||
for (int i = 0; i < xData.length; i++) {
|
||||
canvas.drawRect(
|
||||
Rect.fromLTWH(_kBarPadding, 0, xStep - 2 * _kBarPadding,
|
||||
-(yData[i] / maxData * (size.height - _kScaleHeight)))
|
||||
.translate(-xStep, 0),
|
||||
fillPaint);
|
||||
canvas.translate(xStep, 0);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void drawYText(Canvas canvas, Size size) {
|
||||
canvas.save();
|
||||
yStep = (size.height - _kScaleHeight) / 5;
|
||||
double numStep = maxData / 5;
|
||||
for (int i = 0; i <= 5; i++) {
|
||||
if (i == 0) {
|
||||
_drawAxisText(canvas, '0', offset: Offset(-10, 2));
|
||||
canvas.translate(0, -yStep);
|
||||
continue;
|
||||
}
|
||||
|
||||
canvas.drawLine(
|
||||
Offset(0, 0), Offset(size.width - _kScaleHeight, 0), gridPaint);
|
||||
|
||||
canvas.drawLine(Offset(-_kScaleHeight, 0), Offset(0, 0), axisPaint);
|
||||
String str = '${(numStep * i).toStringAsFixed(0)}';
|
||||
_drawAxisText(canvas, str, offset: Offset(-10, 2));
|
||||
canvas.translate(0, -yStep);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void _drawAxisText(Canvas canvas, String str,
|
||||
{Color color = Colors.black,
|
||||
bool x = false,
|
||||
Alignment alignment = Alignment.centerRight,
|
||||
Offset offset = Offset.zero}) {
|
||||
TextSpan text = TextSpan(
|
||||
text: str,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: color,
|
||||
));
|
||||
|
||||
_textPainter.text = text;
|
||||
_textPainter.layout(); // 进行布局
|
||||
|
||||
Size size = _textPainter.size;
|
||||
|
||||
Offset offsetPos = Offset(-size.width / 2, -size.height / 2)
|
||||
.translate(-size.width / 2 * alignment.x + offset.dx, 0.0 + offset.dy);
|
||||
_textPainter.paint(canvas, offsetPos);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||
}
|
||||
197
packages/idraw/lib/p16/s02.dart
Normal file
197
packages/idraw/lib/p16/s02.dart
Normal file
@@ -0,0 +1,197 @@
|
||||
import 'dart:math';
|
||||
|
||||
// import 'dart:ui' as ui;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/5
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: const ICharts(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ICharts extends StatefulWidget {
|
||||
const ICharts({super.key});
|
||||
|
||||
@override
|
||||
_IChartsState createState() => _IChartsState();
|
||||
}
|
||||
|
||||
class _IChartsState extends State<ICharts> with SingleTickerProviderStateMixin{
|
||||
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(milliseconds: 800),
|
||||
vsync: this,
|
||||
)..forward();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(alignment: Alignment.topCenter, children: [
|
||||
Container(
|
||||
width: 350,
|
||||
height: 250,
|
||||
padding: EdgeInsets.only(top: 40, right: 20, bottom: 20, left: 20),
|
||||
child: CustomPaint(
|
||||
painter: ChartPainter(repaint: _controller),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top:8.0),
|
||||
child: Text(
|
||||
"捷特数学成绩统计图 - 2040 年",
|
||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
|
||||
),
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
const double _kScaleHeight = 8; // 刻度高
|
||||
const double _kBarPadding = 10; // 柱状图前间隔
|
||||
|
||||
class ChartPainter extends CustomPainter {
|
||||
final TextPainter _textPainter =
|
||||
TextPainter(textDirection: TextDirection.ltr);
|
||||
|
||||
final List<double> yData = [88, 98, 70, 80, 100, 75];
|
||||
final List<String> xData = ["7月", "8月", "9月", "10月", "11月", "12月"];
|
||||
|
||||
// final List<String> xData = [ "语文","数学", "英语", "物理", "化学", "生物"];
|
||||
|
||||
final Animation<double> repaint;
|
||||
|
||||
|
||||
Path axisPath = Path();
|
||||
Paint axisPaint = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 1;
|
||||
|
||||
Paint gridPaint = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..color = Colors.grey
|
||||
..strokeWidth = 0.5;
|
||||
Paint fillPaint = Paint()..color = Colors.red;
|
||||
|
||||
double xStep = 0; // x 间隔
|
||||
double yStep = 0; // y 间隔
|
||||
|
||||
double maxData = 0; // 数据最大值
|
||||
|
||||
ChartPainter({required this.repaint}):super(repaint: repaint) {
|
||||
maxData = yData.reduce(max);
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
|
||||
canvas.translate(0, size.height);
|
||||
canvas.translate(_kScaleHeight, -_kScaleHeight);
|
||||
|
||||
axisPath.moveTo(-_kScaleHeight, 0);
|
||||
axisPath.relativeLineTo(size.width, 0);
|
||||
axisPath.moveTo(0, _kScaleHeight);
|
||||
axisPath.relativeLineTo(0, -size.height);
|
||||
canvas.drawPath(axisPath, axisPaint);
|
||||
|
||||
drawYText(canvas, size);
|
||||
drawXText(canvas, size);
|
||||
drawBarChart(canvas,size);
|
||||
}
|
||||
|
||||
void drawXText(Canvas canvas, Size size) {
|
||||
xStep = (size.width - _kScaleHeight) / xData.length;
|
||||
canvas.save();
|
||||
canvas.translate(xStep, 0);
|
||||
for (int i = 0; i < xData.length; i++) {
|
||||
canvas.drawLine(Offset(0, 0), Offset(0, _kScaleHeight), axisPaint);
|
||||
_drawAxisText(canvas, xData[i],
|
||||
alignment: Alignment.center, offset: Offset(-xStep / 2, 10));
|
||||
canvas.translate(xStep, 0);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void drawBarChart(Canvas canvas, Size size) {
|
||||
canvas.save();
|
||||
canvas.translate(xStep, 0);
|
||||
for (int i = 0; i < xData.length; i++) {
|
||||
double dataHeight = -(yData[i] / maxData * (size.height - _kScaleHeight));
|
||||
canvas.drawRect(
|
||||
Rect.fromLTWH(
|
||||
_kBarPadding, 0, xStep-2*_kBarPadding, dataHeight*repaint.value)
|
||||
.translate(-xStep, 0),
|
||||
fillPaint);
|
||||
canvas.translate(xStep, 0);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void drawYText(Canvas canvas, Size size) {
|
||||
canvas.save();
|
||||
yStep = (size.height - _kScaleHeight) / 5;
|
||||
double numStep = maxData / 5;
|
||||
for (int i = 0; i <= 5; i++) {
|
||||
if (i == 0) {
|
||||
_drawAxisText(canvas, '0', offset: Offset(-10, 2));
|
||||
canvas.translate(0, -yStep);
|
||||
continue;
|
||||
}
|
||||
|
||||
canvas.drawLine(
|
||||
Offset(0, 0), Offset(size.width - _kScaleHeight, 0), gridPaint);
|
||||
|
||||
canvas.drawLine(Offset(-_kScaleHeight, 0), Offset(0, 0), axisPaint);
|
||||
String str = '${(numStep * i).toStringAsFixed(0)}';
|
||||
_drawAxisText(canvas, str, offset: Offset(-10, 2));
|
||||
canvas.translate(0, -yStep);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void _drawAxisText(Canvas canvas, String str,
|
||||
{Color color = Colors.black,
|
||||
bool x = false,
|
||||
Alignment alignment = Alignment.centerRight,
|
||||
Offset offset = Offset.zero}) {
|
||||
TextSpan text = TextSpan(
|
||||
text: str,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: color,
|
||||
));
|
||||
|
||||
_textPainter.text = text;
|
||||
_textPainter.layout(); // 进行布局
|
||||
|
||||
Size size = _textPainter.size;
|
||||
|
||||
Offset offsetPos = Offset(-size.width / 2, -size.height / 2)
|
||||
.translate(-size.width / 2 * alignment.x + offset.dx, 0.0 + offset.dy);
|
||||
_textPainter.paint(canvas, offsetPos);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||
}
|
||||
215
packages/idraw/lib/p16/s03.dart
Normal file
215
packages/idraw/lib/p16/s03.dart
Normal file
@@ -0,0 +1,215 @@
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
// import 'dart:ui' as ui;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/5
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: const ICharts(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ICharts extends StatefulWidget {
|
||||
const ICharts({super.key});
|
||||
|
||||
@override
|
||||
_IChartsState createState() => _IChartsState();
|
||||
}
|
||||
|
||||
class _IChartsState extends State<ICharts> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(milliseconds: 1000),
|
||||
vsync: this,
|
||||
)
|
||||
..forward()
|
||||
;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(alignment: Alignment.topCenter, children: [
|
||||
Container(
|
||||
width: 350,
|
||||
height: 250,
|
||||
padding: EdgeInsets.only(top: 40, right: 20, bottom: 20, left: 20),
|
||||
child: CustomPaint(
|
||||
painter: ChartPainter(repaint: _controller),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
"捷特数学成绩统计图 - 2040 年",
|
||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
|
||||
),
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
const double _kScaleHeight = 8; // 刻度高
|
||||
const double _kBarPadding = 10; // 柱状图前间隔
|
||||
|
||||
class ChartPainter extends CustomPainter {
|
||||
final TextPainter _textPainter =
|
||||
TextPainter(textDirection: TextDirection.ltr);
|
||||
|
||||
final List<double> yData = [88, 98, 70, 80, 100, 75];
|
||||
final List<String> xData = ["7月", "8月", "9月", "10月", "11月", "12月"];
|
||||
|
||||
// final List<String> xData = [ "语文","数学", "英语", "物理", "化学", "生物"];
|
||||
|
||||
final Animation<double> repaint;
|
||||
|
||||
Path axisPath = Path();
|
||||
Paint axisPaint = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 1;
|
||||
|
||||
Paint gridPaint = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..color = Colors.grey
|
||||
..strokeWidth = 0.5;
|
||||
Paint fillPaint = Paint()..color = Colors.red;
|
||||
Paint linePaint = Paint()
|
||||
..color = Colors.red
|
||||
..strokeCap=StrokeCap.round
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
double xStep = 0; // x 间隔
|
||||
double yStep = 0; // y 间隔
|
||||
|
||||
double maxData = 0; // 数据最大值
|
||||
|
||||
final List<Offset> line = []; // 折线点位信息
|
||||
|
||||
ChartPainter({required this.repaint}) : super(repaint: repaint) {
|
||||
maxData = yData.reduce(max);
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
xStep = (size.width - _kScaleHeight) / xData.length;
|
||||
yStep = (size.height - _kScaleHeight) / 5;
|
||||
|
||||
canvas.translate(0, size.height);
|
||||
canvas.translate(_kScaleHeight, -_kScaleHeight);
|
||||
axisPath.moveTo(-_kScaleHeight, 0);
|
||||
axisPath.relativeLineTo(size.width, 0);
|
||||
axisPath.moveTo(0, _kScaleHeight);
|
||||
axisPath.relativeLineTo(0, -size.height);
|
||||
canvas.drawPath(axisPath, axisPaint);
|
||||
|
||||
drawYText(canvas, size);
|
||||
drawXText(canvas, size);
|
||||
collectPoints(canvas, size);
|
||||
drawLineChart(canvas);
|
||||
}
|
||||
|
||||
void drawXText(Canvas canvas, Size size) {
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(xStep, 0);
|
||||
for (int i = 0; i < xData.length; i++) {
|
||||
canvas.drawLine(Offset(0, 0), Offset(0, _kScaleHeight), axisPaint);
|
||||
_drawAxisText(canvas, xData[i],
|
||||
alignment: Alignment.center, offset: Offset(-xStep / 2, 10));
|
||||
canvas.translate(xStep, 0);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void collectPoints(Canvas canvas, Size size) {
|
||||
line.clear();
|
||||
canvas.translate(xStep, 0);
|
||||
for (int i = 0; i < xData.length; i++) {
|
||||
double dataHeight = -(yData[i] / maxData * (size.height - _kScaleHeight));
|
||||
line.add(Offset(xStep * i-xStep/2, dataHeight));
|
||||
}
|
||||
}
|
||||
|
||||
void drawLineChart(Canvas canvas){
|
||||
canvas.drawPoints(PointMode.points, line, linePaint..strokeWidth=5);
|
||||
|
||||
Offset p1 = line[0];
|
||||
Path path = Path()..moveTo(p1.dx, p1.dy);
|
||||
for (var i = 1; i < line.length; i++) {
|
||||
path.lineTo(line[i].dx, line[i].dy);
|
||||
}
|
||||
linePaint..strokeWidth=1;
|
||||
PathMetrics pms = path.computeMetrics();
|
||||
pms.forEach((pm) {
|
||||
canvas.drawPath(pm.extractPath(0, pm.length * repaint.value), linePaint);
|
||||
});
|
||||
}
|
||||
|
||||
void drawYText(Canvas canvas, Size size) {
|
||||
canvas.save();
|
||||
double numStep = maxData / 5;
|
||||
for (int i = 0; i <= 5; i++) {
|
||||
if (i == 0) {
|
||||
_drawAxisText(canvas, '0', offset: Offset(-10, 2));
|
||||
canvas.translate(0, -yStep);
|
||||
continue;
|
||||
}
|
||||
|
||||
canvas.drawLine(
|
||||
Offset(0, 0), Offset(size.width - _kScaleHeight, 0), gridPaint);
|
||||
|
||||
canvas.drawLine(Offset(-_kScaleHeight, 0), Offset(0, 0), axisPaint);
|
||||
String str = '${(numStep * i).toStringAsFixed(0)}';
|
||||
_drawAxisText(canvas, str, offset: Offset(-10, 2));
|
||||
canvas.translate(0, -yStep);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void _drawAxisText(Canvas canvas, String str,
|
||||
{Color color = Colors.black,
|
||||
bool x = false,
|
||||
Alignment alignment = Alignment.centerRight,
|
||||
Offset offset = Offset.zero}) {
|
||||
TextSpan text = TextSpan(
|
||||
text: str,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: color,
|
||||
));
|
||||
|
||||
_textPainter.text = text;
|
||||
_textPainter.layout(); // 进行布局
|
||||
|
||||
Size size = _textPainter.size;
|
||||
|
||||
Offset offsetPos = Offset(-size.width / 2, -size.height / 2)
|
||||
.translate(-size.width / 2 * alignment.x + offset.dx, 0.0 + offset.dy);
|
||||
_textPainter.paint(canvas, offsetPos);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||
|
||||
}
|
||||
237
packages/idraw/lib/p16/s04.dart
Normal file
237
packages/idraw/lib/p16/s04.dart
Normal file
@@ -0,0 +1,237 @@
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
// import 'dart:ui' as ui;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/5
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: const ICharts(),
|
||||
);
|
||||
}
|
||||
}
|
||||
class ICharts extends StatefulWidget {
|
||||
const ICharts({super.key});
|
||||
|
||||
@override
|
||||
_IChartsState createState() => _IChartsState();
|
||||
}
|
||||
|
||||
class _IChartsState extends State<ICharts> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(milliseconds: 1000),
|
||||
vsync: this,
|
||||
)
|
||||
..forward()
|
||||
;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(alignment: Alignment.topCenter, children: [
|
||||
Container(
|
||||
width: 350,
|
||||
height: 250,
|
||||
padding: EdgeInsets.only(top: 40, right: 20, bottom: 20, left: 20),
|
||||
child: CustomPaint(
|
||||
painter: ChartPainter(repaint: _controller),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
"捷特数学成绩统计图 - 2040 年",
|
||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
|
||||
),
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
const double _kScaleHeight = 8; // 刻度高
|
||||
const double _kBarPadding = 10; // 柱状图前间隔
|
||||
|
||||
class ChartPainter extends CustomPainter {
|
||||
final TextPainter _textPainter =
|
||||
TextPainter(textDirection: TextDirection.ltr);
|
||||
|
||||
final List<double> yData = [88, 98, 70, 80, 100, 75];
|
||||
final List<String> xData = ["7月", "8月", "9月", "10月", "11月", "12月"];
|
||||
|
||||
// final List<String> xData = [ "语文","数学", "英语", "物理", "化学", "生物"];
|
||||
|
||||
final Animation<double> repaint;
|
||||
|
||||
Path axisPath = Path();
|
||||
Paint axisPaint = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 1;
|
||||
|
||||
Paint gridPaint = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..color = Colors.grey
|
||||
..strokeWidth = 0.5;
|
||||
Paint fillPaint = Paint()..color = Colors.red;
|
||||
Paint linePaint = Paint()
|
||||
..color = Colors.orange
|
||||
..strokeCap=StrokeCap.round
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
double xStep = 0; // x 间隔
|
||||
double yStep = 0; // y 间隔
|
||||
|
||||
double maxData = 0; // 数据最大值
|
||||
|
||||
final List<Offset> line = []; // 折线点位信息
|
||||
|
||||
ChartPainter({required this.repaint}) : super(repaint: repaint) {
|
||||
maxData = yData.reduce(max);
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
xStep = (size.width - _kScaleHeight) / xData.length;
|
||||
yStep = (size.height - _kScaleHeight) / 5;
|
||||
|
||||
canvas.translate(0, size.height);
|
||||
canvas.translate(_kScaleHeight, -_kScaleHeight);
|
||||
axisPath.moveTo(-_kScaleHeight, 0);
|
||||
axisPath.relativeLineTo(size.width, 0);
|
||||
axisPath.moveTo(0, _kScaleHeight);
|
||||
axisPath.relativeLineTo(0, -size.height);
|
||||
canvas.drawPath(axisPath, axisPaint);
|
||||
|
||||
drawYText(canvas, size);
|
||||
drawXText(canvas, size);
|
||||
collectPoints(canvas, size);
|
||||
drawLineChart(canvas);
|
||||
}
|
||||
|
||||
void drawXText(Canvas canvas, Size size) {
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(xStep, 0);
|
||||
for (int i = 0; i < xData.length; i++) {
|
||||
canvas.drawLine(Offset(0, 0), Offset(0, _kScaleHeight), axisPaint);
|
||||
_drawAxisText(canvas, xData[i],
|
||||
alignment: Alignment.center, offset: Offset(-xStep / 2, 10));
|
||||
canvas.translate(xStep, 0);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void collectPoints(Canvas canvas, Size size) {
|
||||
line.clear();
|
||||
canvas.translate(xStep, 0);
|
||||
for (int i = 0; i < xData.length; i++) {
|
||||
double dataHeight = -(yData[i] / maxData * (size.height - _kScaleHeight));
|
||||
line.add(Offset(xStep * i-xStep/2, dataHeight));
|
||||
}
|
||||
}
|
||||
|
||||
void drawLineChart(Canvas canvas){
|
||||
canvas.drawPoints(PointMode.points, line, linePaint..strokeWidth=5);
|
||||
Path path = Path();
|
||||
addBezierPathWithPoints(path, line);
|
||||
linePaint..strokeWidth=1;
|
||||
PathMetrics pms = path.computeMetrics();
|
||||
pms.forEach((pm) {
|
||||
canvas.drawPath(pm.extractPath(0, pm.length * repaint.value), linePaint);
|
||||
});
|
||||
}
|
||||
|
||||
void drawYText(Canvas canvas, Size size) {
|
||||
canvas.save();
|
||||
double numStep = maxData / 5;
|
||||
for (int i = 0; i <= 5; i++) {
|
||||
if (i == 0) {
|
||||
_drawAxisText(canvas, '0', offset: Offset(-10, 2));
|
||||
canvas.translate(0, -yStep);
|
||||
continue;
|
||||
}
|
||||
|
||||
canvas.drawLine(
|
||||
Offset(0, 0), Offset(size.width - _kScaleHeight, 0), gridPaint);
|
||||
|
||||
canvas.drawLine(Offset(-_kScaleHeight, 0), Offset(0, 0), axisPaint);
|
||||
String str = '${(numStep * i).toStringAsFixed(0)}';
|
||||
_drawAxisText(canvas, str, offset: Offset(-10, 2));
|
||||
canvas.translate(0, -yStep);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void addBezierPathWithPoints(Path path, List<Offset> points) {
|
||||
for (int i = 0; i < points.length - 1; i++) {
|
||||
Offset current = points[i];
|
||||
Offset next = points[i+1];
|
||||
if (i == 0) {
|
||||
path.moveTo(current.dx, current.dy);
|
||||
// 控制点
|
||||
double ctrlX = current.dx + (next.dx - current.dx) / 2;
|
||||
double ctrlY = next.dy;
|
||||
path.quadraticBezierTo(ctrlX, ctrlY, next.dx, next.dy);
|
||||
} else if (i < points.length - 2) {
|
||||
// 控制点 1
|
||||
double ctrl1X = current.dx + (next.dx - current.dx) / 2;
|
||||
double ctrl1Y = current.dy;
|
||||
// 控制点 2
|
||||
double ctrl2X = ctrl1X;
|
||||
double ctrl2Y = next.dy;
|
||||
path.cubicTo(ctrl1X,ctrl1Y,ctrl2X,ctrl2Y,next.dx,next.dy);
|
||||
}else{
|
||||
// 控制点
|
||||
double ctrlX = (next.dx - current.dx) / 2;
|
||||
double ctrlY = 0;
|
||||
path.relativeQuadraticBezierTo(ctrlX, ctrlY, next.dx-current.dx, next.dy-current.dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _drawAxisText(Canvas canvas, String str,
|
||||
{Color color = Colors.black,
|
||||
bool x = false,
|
||||
Alignment alignment = Alignment.centerRight,
|
||||
Offset offset = Offset.zero}) {
|
||||
TextSpan text = TextSpan(
|
||||
text: str,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: color,
|
||||
));
|
||||
|
||||
_textPainter.text = text;
|
||||
_textPainter.layout(); // 进行布局
|
||||
|
||||
Size size = _textPainter.size;
|
||||
|
||||
Offset offsetPos = Offset(-size.width / 2, -size.height / 2)
|
||||
.translate(-size.width / 2 * alignment.x + offset.dx, 0.0 + offset.dy);
|
||||
_textPainter.paint(canvas, offsetPos);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||
|
||||
}
|
||||
232
packages/idraw/lib/p16/s05.dart
Normal file
232
packages/idraw/lib/p16/s05.dart
Normal file
@@ -0,0 +1,232 @@
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
// import 'dart:ui' as ui;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/5
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: const ICharts(),
|
||||
);
|
||||
}
|
||||
}
|
||||
class ICharts extends StatefulWidget {
|
||||
const ICharts({super.key});
|
||||
|
||||
@override
|
||||
_IChartsState createState() => _IChartsState();
|
||||
}
|
||||
|
||||
class _IChartsState extends State<ICharts> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(milliseconds: 1000),
|
||||
vsync: this,
|
||||
)
|
||||
..forward()
|
||||
;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(alignment: Alignment.topCenter, children: [
|
||||
Container(
|
||||
width: 350,
|
||||
height: 250,
|
||||
padding: EdgeInsets.only(top: 40, right: 20, bottom: 20, left: 20),
|
||||
child: CustomPaint(
|
||||
painter: ChartPainter(repaint: _controller),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
"捷特数学成绩统计图 - 2040 年",
|
||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
|
||||
),
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
const double _kScaleHeight = 8; // 刻度高
|
||||
const double _kBarPadding = 10; // 柱状图前间隔
|
||||
|
||||
class ChartPainter extends CustomPainter {
|
||||
final TextPainter _textPainter =
|
||||
TextPainter(textDirection: TextDirection.ltr);
|
||||
|
||||
final List<double> yData = [88, 98, 70, 80, 100, 75];
|
||||
final List<String> xData = ["7月", "8月", "9月", "10月", "11月", "12月"];
|
||||
|
||||
// final List<String> xData = [ "语文","数学", "英语", "物理", "化学", "生物"];
|
||||
|
||||
final Animation<double> repaint;
|
||||
|
||||
Path axisPath = Path();
|
||||
Paint axisPaint = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 1;
|
||||
|
||||
Paint gridPaint = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..color = Colors.grey
|
||||
..strokeWidth = 0.5;
|
||||
Paint fillPaint = Paint()..color = Colors.red;
|
||||
Paint linePaint = Paint()
|
||||
..color = Colors.red
|
||||
..strokeCap=StrokeCap.round
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
double xStep = 0; // x 间隔
|
||||
double yStep = 0; // y 间隔
|
||||
|
||||
double maxData = 0; // 数据最大值
|
||||
|
||||
final List<Offset> line = []; // 折线点位信息
|
||||
|
||||
ChartPainter({required this.repaint}) : super(repaint: repaint) {
|
||||
maxData = yData.reduce(max);
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
xStep = (size.width - _kScaleHeight) / xData.length;
|
||||
yStep = (size.height - _kScaleHeight) / 5;
|
||||
|
||||
canvas.translate(0, size.height);
|
||||
canvas.translate(_kScaleHeight, -_kScaleHeight);
|
||||
axisPath.moveTo(-_kScaleHeight, 0);
|
||||
axisPath.relativeLineTo(size.width, 0);
|
||||
axisPath.moveTo(0, _kScaleHeight);
|
||||
axisPath.relativeLineTo(0, -size.height);
|
||||
canvas.drawPath(axisPath, axisPaint);
|
||||
|
||||
drawYText(canvas, size);
|
||||
drawXText(canvas, size);
|
||||
drawBarChart(canvas,size);
|
||||
collectPoints(canvas, size);
|
||||
drawLineChart(canvas);
|
||||
}
|
||||
|
||||
void drawXText(Canvas canvas, Size size) {
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(xStep, 0);
|
||||
for (int i = 0; i < xData.length; i++) {
|
||||
canvas.drawLine(Offset(0, 0), Offset(0, _kScaleHeight), axisPaint);
|
||||
_drawAxisText(canvas, xData[i],
|
||||
alignment: Alignment.center, offset: Offset(-xStep / 2, 10));
|
||||
canvas.translate(xStep, 0);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void collectPoints(Canvas canvas, Size size) {
|
||||
line.clear();
|
||||
canvas.translate(xStep, 0);
|
||||
for (int i = 0; i < xData.length; i++) {
|
||||
double dataHeight = -(yData[i] / maxData * (size.height - _kScaleHeight));
|
||||
line.add(Offset(xStep * i-xStep/2, dataHeight));
|
||||
}
|
||||
}
|
||||
|
||||
void drawBarChart(Canvas canvas, Size size) {
|
||||
fillPaint..color=Colors.lightBlue;
|
||||
canvas.save();
|
||||
canvas.translate(xStep, 0);
|
||||
for (int i = 0; i < xData.length; i++) {
|
||||
double dataHeight = -(yData[i] / maxData * (size.height - _kScaleHeight));
|
||||
canvas.drawRect(
|
||||
Rect.fromLTWH(
|
||||
_kBarPadding, 0, xStep-2*_kBarPadding, dataHeight*repaint.value)
|
||||
.translate(-xStep, 0),
|
||||
fillPaint);
|
||||
canvas.translate(xStep, 0);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
|
||||
void drawLineChart(Canvas canvas){
|
||||
canvas.drawPoints(PointMode.points, line, linePaint..strokeWidth=5);
|
||||
|
||||
Offset p1 = line[0];
|
||||
Path path = Path()..moveTo(p1.dx, p1.dy);
|
||||
for (var i = 1; i < line.length; i++) {
|
||||
path.lineTo(line[i].dx, line[i].dy);
|
||||
}
|
||||
linePaint..strokeWidth=1;
|
||||
PathMetrics pms = path.computeMetrics();
|
||||
pms.forEach((pm) {
|
||||
canvas.drawPath(pm.extractPath(0, pm.length * repaint.value), linePaint);
|
||||
});
|
||||
}
|
||||
|
||||
void drawYText(Canvas canvas, Size size) {
|
||||
canvas.save();
|
||||
double numStep = maxData / 5;
|
||||
for (int i = 0; i <= 5; i++) {
|
||||
if (i == 0) {
|
||||
_drawAxisText(canvas, '0', offset: Offset(-10, 2));
|
||||
canvas.translate(0, -yStep);
|
||||
continue;
|
||||
}
|
||||
|
||||
canvas.drawLine(
|
||||
Offset(0, 0), Offset(size.width - _kScaleHeight, 0), gridPaint);
|
||||
|
||||
canvas.drawLine(Offset(-_kScaleHeight, 0), Offset(0, 0), axisPaint);
|
||||
String str = '${(numStep * i).toStringAsFixed(0)}';
|
||||
_drawAxisText(canvas, str, offset: Offset(-10, 2));
|
||||
canvas.translate(0, -yStep);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void _drawAxisText(Canvas canvas, String str,
|
||||
{Color color = Colors.black,
|
||||
bool x = false,
|
||||
Alignment alignment = Alignment.centerRight,
|
||||
Offset offset = Offset.zero}) {
|
||||
TextSpan text = TextSpan(
|
||||
text: str,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: color,
|
||||
));
|
||||
|
||||
_textPainter.text = text;
|
||||
_textPainter.layout(); // 进行布局
|
||||
|
||||
Size size = _textPainter.size;
|
||||
|
||||
Offset offsetPos = Offset(-size.width / 2, -size.height / 2)
|
||||
.translate(-size.width / 2 * alignment.x + offset.dx, 0.0 + offset.dy);
|
||||
_textPainter.paint(canvas, offsetPos);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||
|
||||
}
|
||||
254
packages/idraw/lib/p16/s06.dart
Normal file
254
packages/idraw/lib/p16/s06.dart
Normal file
@@ -0,0 +1,254 @@
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
// import 'dart:ui' as ui;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/5
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: const ICharts(),
|
||||
);
|
||||
}
|
||||
}
|
||||
class ICharts extends StatefulWidget {
|
||||
const ICharts({super.key});
|
||||
|
||||
@override
|
||||
_IChartsState createState() => _IChartsState();
|
||||
}
|
||||
|
||||
class _IChartsState extends State<ICharts> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(milliseconds: 1000),
|
||||
vsync: this,
|
||||
)
|
||||
..forward()
|
||||
;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(alignment: Alignment.topCenter, children: [
|
||||
Container(
|
||||
width: 400,
|
||||
height: 300,
|
||||
padding: EdgeInsets.only(top: 40, right: 20, bottom: 20, left: 20),
|
||||
child: CustomPaint(
|
||||
painter: ChartPainter(repaint: _controller),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
"捷特 3 月支出统计图 - 2040 年",
|
||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
|
||||
),
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
const double _kScaleHeight = 8; // 刻度高
|
||||
const double _kBarPadding = 10; // 柱状图前间隔
|
||||
const double _kPiePadding = 20; // 饼状图边距
|
||||
|
||||
class ChartPainter extends CustomPainter {
|
||||
final TextPainter _textPainter =
|
||||
TextPainter(textDirection: TextDirection.ltr);
|
||||
|
||||
final List<double> yData = [0.12, 0.25, 0.1, 0.18, 0.15, 0.2];
|
||||
final List<Color> colors = [
|
||||
Colors.red,
|
||||
Colors.orangeAccent,
|
||||
Colors.blue,
|
||||
Colors.green,
|
||||
Colors.purple,
|
||||
Colors.pink
|
||||
];
|
||||
final List<String> xData = ["学习资料", "伙食费", "话费", "游玩", "游戏", "其他"];
|
||||
|
||||
final Animation<double> repaint;
|
||||
|
||||
Path axisPath = Path();
|
||||
Paint axisPaint = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 1;
|
||||
|
||||
Paint gridPaint = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..color = Colors.grey
|
||||
..strokeWidth = 0.5;
|
||||
Paint fillPaint = Paint()..color = Colors.red;
|
||||
Paint linePaint = Paint()
|
||||
..color = Colors.red
|
||||
..strokeCap = StrokeCap.round
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
double radius = 0; // 饼图半径
|
||||
double yStep = 0; // y 间隔
|
||||
|
||||
double maxData = 0; // 数据最大值
|
||||
|
||||
final List<Offset> line = []; // 折线点位信息
|
||||
|
||||
ChartPainter({required this.repaint}) : super(repaint: repaint) {
|
||||
maxData = yData.reduce(max);
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
radius = size.shortestSide / 2 - _kPiePadding;
|
||||
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
canvas.rotate(-pi / 2);
|
||||
|
||||
Path clipPath = Path();
|
||||
clipPath.lineTo(radius, 0);
|
||||
clipPath.arcTo(
|
||||
Rect.fromCenter(center: Offset.zero, width: radius * 4, height: radius * 4),
|
||||
0, 2 * pi * repaint.value, false);
|
||||
clipPath.close();
|
||||
if(repaint.value!=1.0){
|
||||
canvas.clipPath(clipPath);
|
||||
}
|
||||
|
||||
|
||||
drawPieChart(canvas);
|
||||
drawInfo(canvas);
|
||||
}
|
||||
|
||||
void drawInfo(Canvas canvas) {
|
||||
for (int i = 0; i < yData.length; i++) {
|
||||
Color color = colors[i % colors.length];
|
||||
|
||||
canvas.save();
|
||||
canvas.rotate(2 * pi * yData[i] / 2);
|
||||
_drawAxisText(canvas, "${(yData[i] * 100).toStringAsFixed(1)}%",
|
||||
color: Colors.white,
|
||||
alignment: Alignment.center,
|
||||
offset: Offset(radius / 2 + 5, 0));
|
||||
|
||||
Path showPath = Path();
|
||||
showPath.moveTo(radius, 0);
|
||||
showPath.relativeLineTo(15, 0);
|
||||
showPath.relativeLineTo(5, 10);
|
||||
canvas.drawPath(
|
||||
showPath,
|
||||
linePaint..color = color,
|
||||
);
|
||||
|
||||
_drawAxisText(canvas, xData[i],
|
||||
color: color,
|
||||
fontSize: 9,
|
||||
alignment: Alignment.centerLeft,
|
||||
offset: Offset(radius + 5, 18));
|
||||
canvas.restore();
|
||||
|
||||
canvas.rotate(2 * pi * yData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void drawPieChart(Canvas canvas) {
|
||||
for (int i = 0; i < yData.length; i++) {
|
||||
Color color = colors[i % colors.length];
|
||||
Path path = Path();
|
||||
path.lineTo(radius, 0);
|
||||
path.arcTo(
|
||||
Rect.fromCenter(
|
||||
center: Offset.zero, width: radius * 2, height: radius * 2),
|
||||
0,
|
||||
2 * pi * yData[i],
|
||||
false);
|
||||
path.close();
|
||||
canvas.drawPath(
|
||||
path,
|
||||
fillPaint
|
||||
..style = PaintingStyle.fill
|
||||
..color = color);
|
||||
canvas.rotate(2 * pi * yData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void drawLineChart(Canvas canvas) {
|
||||
canvas.drawPoints(PointMode.points, line, linePaint..strokeWidth = 5);
|
||||
|
||||
Offset p1 = line[0];
|
||||
Path path = Path()..moveTo(p1.dx, p1.dy);
|
||||
for (var i = 1; i < line.length; i++) {
|
||||
path.lineTo(line[i].dx, line[i].dy);
|
||||
}
|
||||
linePaint..strokeWidth = 1;
|
||||
PathMetrics pms = path.computeMetrics();
|
||||
pms.forEach((pm) {
|
||||
canvas.drawPath(pm.extractPath(0, pm.length * repaint.value), linePaint);
|
||||
});
|
||||
}
|
||||
|
||||
void drawYText(Canvas canvas, Size size) {
|
||||
canvas.save();
|
||||
double numStep = maxData / 5;
|
||||
for (int i = 0; i <= 5; i++) {
|
||||
if (i == 0) {
|
||||
_drawAxisText(canvas, '0', offset: Offset(-10, 2));
|
||||
canvas.translate(0, -yStep);
|
||||
continue;
|
||||
}
|
||||
|
||||
canvas.drawLine(
|
||||
Offset(0, 0), Offset(size.width - _kScaleHeight, 0), gridPaint);
|
||||
|
||||
canvas.drawLine(Offset(-_kScaleHeight, 0), Offset(0, 0), axisPaint);
|
||||
String str = '${(numStep * i).toStringAsFixed(0)}';
|
||||
_drawAxisText(canvas, str, offset: Offset(-10, 2));
|
||||
canvas.translate(0, -yStep);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void _drawAxisText(Canvas canvas, String str,
|
||||
{Color color = Colors.black,
|
||||
double fontSize = 11,
|
||||
bool x = false,
|
||||
Alignment alignment = Alignment.centerRight,
|
||||
Offset offset = Offset.zero}) {
|
||||
TextSpan text = TextSpan(
|
||||
text: str,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
color: color,
|
||||
));
|
||||
|
||||
_textPainter.text = text;
|
||||
_textPainter.layout(); // 进行布局
|
||||
|
||||
Size size = _textPainter.size;
|
||||
|
||||
Offset offsetPos = Offset(-size.width / 2, -size.height / 2)
|
||||
.translate(-size.width / 2 * alignment.x + offset.dx, 0.0 + offset.dy);
|
||||
_textPainter.paint(canvas, offsetPos);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||
}
|
||||
1
packages/idraw/lib/p17/p17.dart
Normal file
1
packages/idraw/lib/p17/p17.dart
Normal file
@@ -0,0 +1 @@
|
||||
export 'p17_page.dart';
|
||||
21
packages/idraw/lib/p17/p17_page.dart
Normal file
21
packages/idraw/lib/p17/p17_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 P17Page extends StatelessWidget {
|
||||
const P17Page({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const DemoShower(
|
||||
srcCodeDir: 'draw/p17',
|
||||
|
||||
demos: [
|
||||
s1.Paper(),
|
||||
// s2.Paper(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
271
packages/idraw/lib/p17/s01.dart
Normal file
271
packages/idraw/lib/p17/s01.dart
Normal file
@@ -0,0 +1,271 @@
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
// import 'dart:ui' as ui;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/5
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: const ICharts(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ICharts extends StatefulWidget {
|
||||
const ICharts({super.key});
|
||||
|
||||
@override
|
||||
_IChartsState createState() => _IChartsState();
|
||||
}
|
||||
|
||||
class _IChartsState extends State<ICharts> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(milliseconds: 1500),
|
||||
vsync: this,
|
||||
)
|
||||
..forward();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(alignment: Alignment.topCenter, children: [
|
||||
Container(
|
||||
width: 500,
|
||||
height: 380,
|
||||
padding: EdgeInsets.only(top: 20, right: 20, bottom: 20, left: 20),
|
||||
child: CustomPaint(
|
||||
painter: ChartPainter(repaint: _controller),
|
||||
),
|
||||
),
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.only(top: 8.0),
|
||||
// child: Text(
|
||||
// "捷特 3 月支出统计图 - 2040 年",
|
||||
// style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
|
||||
// ),
|
||||
// )
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
const double _kPiePadding = 20; // 圆边距
|
||||
const double _kStrokeWidth = 12; // 圆弧宽
|
||||
const double _kAngle = 270; // 圆弧角度
|
||||
const int _kMax = 220; // 最大刻度值
|
||||
const int _kMin = 0; // 最小刻度值
|
||||
const double _kColorStopRate = 0.2; // 颜色变化分率
|
||||
const double _kScaleHeightLever1 = 14; // 短刻度线
|
||||
const double _kScaleHeightLever2 = 18; // 逢5线
|
||||
const double _kScaleHeightLever3 = 20; // 逢10线
|
||||
const double _kScaleDensity = 0.5; // 密度
|
||||
const double _kScaleTextStep = 10; // 刻度文字步长
|
||||
|
||||
const List<Color> _kColors = [
|
||||
// 颜色列表
|
||||
Colors.green,
|
||||
Colors.blue,
|
||||
Colors.red,
|
||||
];
|
||||
|
||||
class ChartPainter extends CustomPainter {
|
||||
final TextPainter _textPainter =
|
||||
TextPainter(textDirection: TextDirection.ltr);
|
||||
|
||||
double value = 150; //指针数值
|
||||
double radius = 0; // 圆半径
|
||||
|
||||
final Animation<double> repaint;
|
||||
|
||||
Paint fillPaint = Paint();
|
||||
|
||||
Paint stokePaint = Paint()
|
||||
..strokeWidth = 1
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
double get initAngle => (360 - _kAngle) / 2;
|
||||
|
||||
ChartPainter({required this.repaint}) : super(repaint: repaint);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
radius = size.shortestSide / 2 - _kPiePadding; // 当前圆半径
|
||||
canvas.translate(size.width / 2, size.height / 2); // 画布原点移至中点
|
||||
|
||||
drawText(canvas);
|
||||
drawArrow(canvas); // 绘制指针
|
||||
canvas.rotate(pi / 2); // 将起始点旋转到 y 轴正方向
|
||||
drawScale(canvas); // 绘制刻度
|
||||
drawOutline(canvas); // 绘制弧线
|
||||
}
|
||||
|
||||
void drawOutline(Canvas canvas) {
|
||||
Path path = Path()..moveTo(radius, 0);
|
||||
path.arcTo(
|
||||
Rect.fromCenter(
|
||||
center: Offset.zero, width: radius * 2, height: radius * 2),
|
||||
pi / 180 * initAngle,
|
||||
pi / 180 * _kAngle,
|
||||
true);
|
||||
|
||||
PathMetrics pms = path.computeMetrics();
|
||||
stokePaint..strokeWidth = _kStrokeWidth;
|
||||
pms.forEach((PathMetric pm) {
|
||||
canvas.drawPath(pm.extractPath(0, pm.length * _kColorStopRate),
|
||||
stokePaint..color = _kColors[0]);
|
||||
canvas.drawPath(
|
||||
pm.extractPath(
|
||||
pm.length * _kColorStopRate, pm.length * (1 - _kColorStopRate)),
|
||||
stokePaint..color = _kColors[1]);
|
||||
canvas.drawPath(
|
||||
pm.extractPath(pm.length * (1 - _kColorStopRate), pm.length),
|
||||
stokePaint..color = _kColors[2]);
|
||||
});
|
||||
}
|
||||
|
||||
void drawScale(Canvas canvas) {
|
||||
canvas.save();
|
||||
canvas.rotate(pi / 180 * initAngle);
|
||||
double len = 0;
|
||||
Color color = Colors.red;
|
||||
int count = (_kMax * _kScaleDensity).toInt(); // 格线个数
|
||||
for (int i = _kMin; i <= count; i++) {
|
||||
if (i % 5 == 0 && i % 10 != 0) {
|
||||
len = _kScaleHeightLever2;
|
||||
} else if (i % 10 == 0) {
|
||||
len = _kScaleHeightLever3;
|
||||
} else {
|
||||
len = _kScaleHeightLever1;
|
||||
}
|
||||
if (i < count * _kColorStopRate) {
|
||||
color = Colors.green;
|
||||
} else if (i < count * (1 - _kColorStopRate)) {
|
||||
color = Colors.blue;
|
||||
} else {
|
||||
color = Colors.red;
|
||||
}
|
||||
canvas.drawLine(Offset(radius + _kStrokeWidth / 2, 0),
|
||||
Offset(radius - len, 0), stokePaint..color = color..strokeWidth=1);
|
||||
canvas.rotate(pi / 180 / _kMax * _kAngle / _kScaleDensity);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void drawArrow(Canvas canvas) {
|
||||
var nowPer = value / _kMax;
|
||||
Color color = Colors.red;
|
||||
canvas.save();
|
||||
double radians = pi / 180 * (-_kAngle / 2 + nowPer * _kAngle*repaint.value);
|
||||
canvas.rotate(radians);
|
||||
Path arrowPath = Path();
|
||||
arrowPath.moveTo(0, 18);
|
||||
arrowPath.relativeLineTo(-6, -10);
|
||||
arrowPath.relativeLineTo(6, -radius + 10);
|
||||
arrowPath.relativeLineTo(6, radius - 10);
|
||||
arrowPath.close();
|
||||
|
||||
if (nowPer < _kColorStopRate) {
|
||||
color = _kColors[0];
|
||||
} else if (nowPer < (1 - _kColorStopRate)) {
|
||||
color = _kColors[1];
|
||||
} else {
|
||||
color = _kColors[2];
|
||||
}
|
||||
|
||||
canvas.drawPath(arrowPath, fillPaint..color = color);
|
||||
canvas.drawCircle(Offset.zero, 3, stokePaint..color = Colors.yellow..strokeWidth=1);
|
||||
canvas.drawCircle(Offset.zero, 3, fillPaint..color = Colors.white);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void drawText(Canvas canvas) {
|
||||
_drawAxisText(canvas, 'km/s',
|
||||
fontSize: 20,
|
||||
fontStyle: FontStyle.italic,
|
||||
fontWeight: FontWeight.bold,
|
||||
alignment: Alignment.center,
|
||||
color: Colors.black,
|
||||
offset: Offset(0, -radius / 2));
|
||||
|
||||
_drawAxisText(canvas, '${value.toStringAsFixed(1)}',
|
||||
fontSize: 16,
|
||||
alignment: Alignment.center,
|
||||
color: Colors.black,
|
||||
offset: Offset(0, radius / 2));
|
||||
|
||||
int count = (_kMax - _kMin) * _kScaleDensity ~/ _kScaleTextStep;
|
||||
Color color = Colors.red;
|
||||
for (int i = _kMin; i <= count; i++) {
|
||||
var thta = pi / 180 * (90 + initAngle + (_kAngle / count) * i);
|
||||
if (i < count * _kColorStopRate) {
|
||||
color = _kColors[0];
|
||||
} else if (i < count * (1 - _kColorStopRate)) {
|
||||
color = _kColors[1];
|
||||
} else {
|
||||
color = _kColors[2];
|
||||
}
|
||||
|
||||
Rect rect = Rect.fromLTWH((radius - 40) * cos(thta) - 12,
|
||||
(radius - 40) * sin(thta) - 8, 24, 16);
|
||||
|
||||
canvas.drawRRect(RRect.fromRectAndRadius(rect, Radius.circular(3)),
|
||||
fillPaint..color = color);
|
||||
_drawAxisText(canvas, '${i * _kScaleTextStep ~/ _kScaleDensity}',
|
||||
fontSize: 11,
|
||||
alignment: Alignment.center,
|
||||
color: Colors.white,
|
||||
offset: Offset((radius - 40) * cos(thta), (radius - 40) * sin(thta)));
|
||||
}
|
||||
}
|
||||
|
||||
void _drawAxisText(Canvas canvas, String str,
|
||||
{Color color = Colors.black,
|
||||
double fontSize = 11,
|
||||
FontStyle fontStyle = FontStyle.normal,
|
||||
Alignment alignment = Alignment.centerRight,
|
||||
FontWeight fontWeight = FontWeight.normal,
|
||||
Offset offset = Offset.zero}) {
|
||||
TextSpan text = TextSpan(
|
||||
text: str,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
fontWeight: fontWeight,
|
||||
fontStyle: fontStyle,
|
||||
color: color,
|
||||
));
|
||||
|
||||
_textPainter.text = text;
|
||||
_textPainter.layout(); // 进行布局
|
||||
|
||||
Size size = _textPainter.size;
|
||||
|
||||
Offset offsetPos = Offset(-size.width / 2, -size.height / 2)
|
||||
.translate(-size.width / 2 * alignment.x + offset.dx, 0.0 + offset.dy);
|
||||
_textPainter.paint(canvas, offsetPos);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||
}
|
||||
432
packages/idraw/lib/p17/s02.dart
Normal file
432
packages/idraw/lib/p17/s02.dart
Normal file
@@ -0,0 +1,432 @@
|
||||
import 'dart:math';
|
||||
|
||||
// import 'dart:ui' as ui;
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:convert' show json;
|
||||
/// create by 张风捷特烈 on 2020/11/5
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: const ChinaMap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChinaMap extends StatefulWidget {
|
||||
const ChinaMap({super.key});
|
||||
|
||||
@override
|
||||
_ChinaMapState createState() => _ChinaMapState();
|
||||
}
|
||||
|
||||
class _ChinaMapState extends State<ChinaMap> {
|
||||
final String url = 'https://geo.datav.aliyun.com/areas_v2/bound/100000_full.json'; //全国点位详细信息
|
||||
|
||||
//请求点位信息地址
|
||||
Future<MapRoot?> getMapRoot() async {
|
||||
try {
|
||||
final Response response = await Dio().get(url);
|
||||
if (response.data != null) {
|
||||
return MapRoot.fromJson(response.data);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
print(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
late Future<MapRoot?> _future;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_future = getMapRoot();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder<MapRoot?>(
|
||||
future: _future,
|
||||
builder: (context, async) {
|
||||
print(async.hasData);
|
||||
if (async.hasData) {
|
||||
return CustomPaint(
|
||||
size: Size(500, 400),
|
||||
painter: MapPainter(mapRoot: async.data),
|
||||
);
|
||||
} else {
|
||||
return CupertinoActivityIndicator();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MapPainter extends CustomPainter {
|
||||
final MapRoot? mapRoot; //点位信息
|
||||
|
||||
late Paint _paint;
|
||||
final List<Color> colors = [Colors.red, Colors.yellow, Colors.blue, Colors.green];
|
||||
int colorIndex = 0;
|
||||
|
||||
MapPainter({required this.mapRoot}) {
|
||||
_paint = Paint()
|
||||
..strokeWidth = 0.1
|
||||
..isAntiAlias = true;
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
if(mapRoot == null) return;
|
||||
if(mapRoot!.features ==null) return;
|
||||
|
||||
canvas.clipRect(
|
||||
Rect.fromPoints(Offset.zero, Offset(size.width, size.height)));
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
double dx = mapRoot!.features![0]?.geometry?.coordinates[0][0][0].dx??0;
|
||||
double dy = mapRoot!.features![0]?.geometry?.coordinates[0][0][0].dy??0;
|
||||
canvas.translate( -dx, -dy);
|
||||
|
||||
double rate = 0.65;
|
||||
|
||||
canvas.translate(-700*rate, 350*rate);
|
||||
canvas.scale(8*rate, -10.5*rate);
|
||||
|
||||
_drawMap(canvas, size);
|
||||
}
|
||||
|
||||
|
||||
void _drawMap(Canvas canvas, Size size) {
|
||||
//全国省份循环
|
||||
for (int i = 0; i < mapRoot!.features!.length; i++) {
|
||||
var features = mapRoot!.features![i];
|
||||
if(features ==null) return;
|
||||
PaintingStyle style;
|
||||
Color color = Colors.black;
|
||||
style = PaintingStyle.fill;
|
||||
Path path = Path();
|
||||
if (features.properties?.name == "台湾省" ||
|
||||
features.properties?.name == "海南省" ||
|
||||
features.properties?.name == "河北省" ||
|
||||
features.properties?.name == "") { //海南和台湾和九段线
|
||||
Path otherPath = Path();
|
||||
features.geometry?.coordinates.forEach((List<List<Offset>> lv3) {
|
||||
for (var lv2 in lv3) {
|
||||
otherPath.moveTo(lv2[0].dx, lv2[0].dy);
|
||||
// for (var lv1 in lv2) {
|
||||
// otherPath.lineTo(lv1.dx, lv1.dy); //优化一半点位
|
||||
// print("========${lv1}==============================");
|
||||
// }
|
||||
}
|
||||
});
|
||||
path.addPath(otherPath, Offset.zero);
|
||||
if (features.properties?.name == "") {
|
||||
style = PaintingStyle.stroke;
|
||||
color = Colors.black;
|
||||
} else {
|
||||
style = PaintingStyle.fill;
|
||||
color = colors[colorIndex % 4];
|
||||
}
|
||||
colorIndex++;
|
||||
} else {
|
||||
|
||||
final Offset first = features.geometry?.coordinates[0][0][0]??Offset.zero;
|
||||
path.moveTo(first.dx, first.dy);
|
||||
if(features.geometry ==null) return;
|
||||
for (Offset d in features.geometry!.coordinates.first.first) {
|
||||
path.lineTo(d.dx, d.dy);
|
||||
}
|
||||
style = PaintingStyle.fill;
|
||||
color = colors[colorIndex % 4];
|
||||
colorIndex++;
|
||||
}
|
||||
|
||||
canvas.drawPath(path, _paint..color = color..style = style); //绘制地图
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(MapPainter oldDelegate) => oldDelegate.mapRoot != mapRoot;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class MapRoot {
|
||||
String type;
|
||||
String name;
|
||||
List<Features?>? features;
|
||||
|
||||
MapRoot({
|
||||
required this.type,
|
||||
required this.name,
|
||||
required this.features,
|
||||
});
|
||||
|
||||
static MapRoot? fromJson(jsonRes) {
|
||||
if (jsonRes == null) return null;
|
||||
|
||||
List<Features?>? features = jsonRes['features'] is List ? [] : null;
|
||||
if (features != null) {
|
||||
for (var item in jsonRes['features']) {
|
||||
if (item != null) {
|
||||
features.add(Features.fromJson(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
return MapRoot(
|
||||
type: jsonRes['type'],
|
||||
name: jsonRes['name'],
|
||||
features: features,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'type': type,
|
||||
'name': name,
|
||||
'features': features,
|
||||
};
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return json.encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
class Features {
|
||||
String type;
|
||||
Properties? properties;
|
||||
Geometry? geometry;
|
||||
|
||||
Features({
|
||||
required this.type,
|
||||
required this.properties,
|
||||
required this.geometry,
|
||||
});
|
||||
|
||||
static Features? fromJson(jsonRes) => jsonRes == null
|
||||
? null
|
||||
: Features(
|
||||
type: jsonRes['type'],
|
||||
properties: Properties.fromJson(jsonRes['properties']),
|
||||
geometry: Geometry.fromJson(jsonRes['geometry']),
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'type': type,
|
||||
'properties': properties,
|
||||
'geometry': geometry,
|
||||
};
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return json.encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
class Properties {
|
||||
String? adcode;
|
||||
String? name;
|
||||
List<double>? center;
|
||||
List<double>? centroid;
|
||||
int? childrenNum;
|
||||
String?level;
|
||||
Parent? parent;
|
||||
int? subFeatureIndex;
|
||||
List<int>? acroutes;
|
||||
Object? adchar;
|
||||
|
||||
Properties({
|
||||
required this.adcode,
|
||||
required this.name,
|
||||
required this.center,
|
||||
required this.centroid,
|
||||
required this.childrenNum,
|
||||
required this.level,
|
||||
required this.parent,
|
||||
required this.subFeatureIndex,
|
||||
required this.acroutes,
|
||||
required this.adchar,
|
||||
});
|
||||
|
||||
static Properties? fromJson(jsonRes) {
|
||||
if (jsonRes == null) return null;
|
||||
|
||||
List<double>? center = jsonRes['center'] is List ? [] : null;
|
||||
if (center != null) {
|
||||
for (var item in jsonRes['center']) {
|
||||
if (item != null) {
|
||||
center.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<double>? centroid = jsonRes['centroid'] is List ? [] : null;
|
||||
if (centroid != null) {
|
||||
for (var item in jsonRes['centroid']) {
|
||||
if (item != null) {
|
||||
centroid.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<int>? acroutes = jsonRes['acroutes'] is List ? [] : null;
|
||||
if (acroutes != null) {
|
||||
for (var item in jsonRes['acroutes']) {
|
||||
if (item != null) {
|
||||
acroutes.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Properties(
|
||||
adcode: jsonRes['adcode'],
|
||||
name: jsonRes['name'],
|
||||
center: center,
|
||||
centroid: centroid,
|
||||
childrenNum: jsonRes['childrenNum'],
|
||||
level: jsonRes['level'],
|
||||
parent: Parent.fromJson(jsonRes['parent']),
|
||||
subFeatureIndex: jsonRes['subFeatureIndex'],
|
||||
acroutes: acroutes,
|
||||
adchar: jsonRes['adchar'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'adcode': adcode,
|
||||
'name': name,
|
||||
'center': center,
|
||||
'centroid': centroid,
|
||||
'childrenNum': childrenNum,
|
||||
'level': level,
|
||||
'parent': parent,
|
||||
'subFeatureIndex': subFeatureIndex,
|
||||
'acroutes': acroutes,
|
||||
'adchar': adchar,
|
||||
};
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return json.encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
class Parent {
|
||||
int adcode;
|
||||
|
||||
Parent({
|
||||
required this.adcode,
|
||||
});
|
||||
|
||||
static Parent? fromJson(jsonRes) => jsonRes == null
|
||||
? null
|
||||
: Parent(
|
||||
adcode: jsonRes['adcode'],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'adcode': adcode,
|
||||
};
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return json.encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
class Geometry {
|
||||
String type;
|
||||
List<List<List<Offset>>> coordinates;
|
||||
|
||||
Geometry({
|
||||
required this.type,
|
||||
required this.coordinates,
|
||||
});
|
||||
|
||||
static Geometry? fromJson(jsonRes) {
|
||||
if (jsonRes == null) return null;
|
||||
|
||||
List<List<List<Offset>>>? coordinates =
|
||||
jsonRes['coordinates'] is List ? [] : null;
|
||||
|
||||
bool fourLever =false;
|
||||
if (jsonRes['coordinates'] is List) {
|
||||
if (jsonRes['coordinates'][0] is List){
|
||||
if (jsonRes['coordinates'][0][0] is List){
|
||||
if (jsonRes['coordinates'][0][0][0] is List){
|
||||
fourLever =true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!fourLever){
|
||||
if (coordinates != null) {
|
||||
for (var level0 in jsonRes['coordinates']) {
|
||||
List<List<Offset>> lever0=[];
|
||||
if (level0 != null) {
|
||||
List<Offset> items1 = [];
|
||||
for (var item1 in level0 is List ? level0 : []) {
|
||||
if (item1 != null) {
|
||||
Offset items2 = Offset(item1[0], item1[1]);
|
||||
items1.add(items2);
|
||||
}
|
||||
lever0.add(items1);
|
||||
}
|
||||
}
|
||||
coordinates.add(lever0);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if (coordinates != null) {
|
||||
for (var level0 in jsonRes['coordinates']) {
|
||||
if (level0 != null) {
|
||||
List<List<Offset>> items1 = [];
|
||||
for (var item1 in level0 is List ? level0 : []) {
|
||||
if (item1 != null) {
|
||||
List<Offset> items2 = [];
|
||||
for (var item2 in item1 is List ? item1 : []) {
|
||||
if (item2 != null && item2 is List) {
|
||||
Offset items3 = Offset(item2[0], item2[1]);
|
||||
items2.add(items3);
|
||||
} else {
|
||||
items2.add(Offset.zero);
|
||||
}
|
||||
items1.add(items2);
|
||||
}
|
||||
}
|
||||
coordinates.add(items1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return Geometry(
|
||||
type: jsonRes['type'],
|
||||
coordinates: coordinates??[],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'type': type,
|
||||
'coordinates': coordinates,
|
||||
};
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return json.encode(this);
|
||||
}
|
||||
}
|
||||
1
packages/idraw/lib/p18/p18.dart
Normal file
1
packages/idraw/lib/p18/p18.dart
Normal file
@@ -0,0 +1 @@
|
||||
export 'p18_page.dart';
|
||||
27
packages/idraw/lib/p18/p18_page.dart
Normal file
27
packages/idraw/lib/p18/p18_page.dart
Normal file
@@ -0,0 +1,27 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:components/components.dart';
|
||||
import 's01.dart' as s1;
|
||||
import 's02.dart' as s2;
|
||||
import 's03.dart' as s3;
|
||||
import 's04.dart' as s4;
|
||||
import 's05.dart' as s5;
|
||||
|
||||
class P18Page extends StatelessWidget {
|
||||
const P18Page({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const DemoShower(
|
||||
srcCodeDir: 'draw/p18',
|
||||
|
||||
demos: [
|
||||
s1.Paper(),
|
||||
s2.Paper(),
|
||||
s3.Paper(),
|
||||
s4.Paper(),
|
||||
// s5.Paper(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
201
packages/idraw/lib/p18/s01.dart
Normal file
201
packages/idraw/lib/p18/s01.dart
Normal file
@@ -0,0 +1,201 @@
|
||||
import 'dart:math';
|
||||
|
||||
// import 'dart:ui' as ui;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/5
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: const World(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class World extends StatefulWidget {
|
||||
const World({super.key});
|
||||
|
||||
@override
|
||||
_WorldState createState() => _WorldState();
|
||||
}
|
||||
|
||||
class _WorldState extends State<World> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
ParticleManage pm = ParticleManage();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
initParticleManage();
|
||||
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(seconds: 1),
|
||||
vsync: this,
|
||||
)
|
||||
..addListener(pm.tick)
|
||||
// ..repeat()
|
||||
;
|
||||
}
|
||||
|
||||
void initParticleManage() {
|
||||
pm.size = Size(300, 200);
|
||||
Particle particle = Particle(x: 0, y: 0, vx: 3, vy: 0,ay: 0.05,
|
||||
color: Colors.blue, size: 8);
|
||||
pm.particles = [particle];
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
theWorld(){
|
||||
if (_controller.isAnimating) {
|
||||
_controller.stop();
|
||||
} else {
|
||||
_controller.repeat();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: theWorld,
|
||||
child: CustomPaint(
|
||||
size: pm.size,
|
||||
painter: WorldRender(manage: pm),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ParticleManage with ChangeNotifier {
|
||||
List<Particle> particles = [];
|
||||
|
||||
Size size;
|
||||
|
||||
ParticleManage({this.size = Size.zero});
|
||||
|
||||
void setParticles(List<Particle> particles) {
|
||||
this.particles = particles;
|
||||
}
|
||||
|
||||
void addParticle(Particle particle) {
|
||||
particles.add(particle);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void tick() {
|
||||
particles.forEach(doUpdate);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void doUpdate(Particle p) {
|
||||
p.vy += p.ay; // y加速度变化
|
||||
p.vx += p.ax; // x加速度变化
|
||||
p.x += p.vx;
|
||||
p.y += p.vy;
|
||||
if (p.x > size.width) {
|
||||
p.x = size.width;
|
||||
p.vx = -p.vx;
|
||||
}
|
||||
if (p.x < 0) {
|
||||
p.x = 0;
|
||||
p.vx = -p.vx;
|
||||
}
|
||||
if (p.y > size.height) {
|
||||
p.y = size.height;
|
||||
p.vy = -p.vy;
|
||||
}
|
||||
if (p.y < 0) {
|
||||
p.y = 0;
|
||||
p.vy = -p.vy;
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
particles.forEach((p) {
|
||||
p.x = 0;
|
||||
});
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
class WorldRender extends CustomPainter {
|
||||
|
||||
final ParticleManage manage;
|
||||
|
||||
Paint fillPaint = Paint();
|
||||
|
||||
Paint stokePaint = Paint()
|
||||
..strokeWidth = 0.5
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
WorldRender({required this.manage}) : super(repaint: manage);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
canvas.drawRect(Offset.zero & size, stokePaint);
|
||||
manage.particles.forEach((particle) {
|
||||
drawParticle(canvas, particle);
|
||||
});
|
||||
}
|
||||
|
||||
void drawParticle(Canvas canvas, Particle particle) {
|
||||
fillPaint.color = particle.color;
|
||||
canvas.drawCircle(Offset(particle.x, particle.y), particle.size, fillPaint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant WorldRender oldDelegate) =>
|
||||
oldDelegate.manage != manage;
|
||||
}
|
||||
|
||||
|
||||
class Particle {
|
||||
/// x 位移.
|
||||
double x;
|
||||
|
||||
/// y 位移.
|
||||
double y;
|
||||
|
||||
/// 粒子水平速度.
|
||||
double vx;
|
||||
|
||||
// 粒子水平加速度
|
||||
double ax;
|
||||
|
||||
// 粒子竖直加速度
|
||||
double ay;
|
||||
|
||||
///粒子竖直速度.
|
||||
double vy;
|
||||
|
||||
|
||||
/// 粒子大小.
|
||||
double size;
|
||||
|
||||
/// 粒子颜色.
|
||||
Color color;
|
||||
|
||||
Particle({
|
||||
this.x = 0,
|
||||
this.y = 0,
|
||||
this.ax = 0,
|
||||
this.ay = 0,
|
||||
this.vx = 0,
|
||||
this.vy = 0,
|
||||
this.size = 0,
|
||||
this.color = Colors.black,
|
||||
});
|
||||
}
|
||||
215
packages/idraw/lib/p18/s02.dart
Normal file
215
packages/idraw/lib/p18/s02.dart
Normal file
@@ -0,0 +1,215 @@
|
||||
import 'dart:math';
|
||||
|
||||
// import 'dart:ui' as ui;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/5
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: const World(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class World extends StatefulWidget {
|
||||
const World({super.key});
|
||||
|
||||
@override
|
||||
_WorldState createState() => _WorldState();
|
||||
}
|
||||
|
||||
class _WorldState extends State<World> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
ParticleManage pm = ParticleManage();
|
||||
Random random = Random();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
initParticleManage();
|
||||
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(seconds: 1),
|
||||
vsync: this,
|
||||
)..addListener(pm.tick)
|
||||
// ..repeat()
|
||||
;
|
||||
}
|
||||
|
||||
void initParticleManage() {
|
||||
pm.size = Size(300, 200);
|
||||
for (var i = 0; i < 30; i++) {
|
||||
pm.particles.add(Particle(
|
||||
color: randomRGB(),
|
||||
size: 5 + 4 * random.nextDouble(),
|
||||
vx: 3 * random.nextDouble() * pow(-1, random.nextInt(20)),
|
||||
vy: 3 * random.nextDouble() * pow(-1, random.nextInt(20)),
|
||||
ay: 0.1,
|
||||
x: 150,
|
||||
y: 100));
|
||||
}
|
||||
}
|
||||
|
||||
Color randomRGB({int limitR = 0, int limitG = 0, int limitB = 0,}) {
|
||||
var r = limitR + random.nextInt(256 - limitR); //红值
|
||||
var g = limitG + random.nextInt(256 - limitG); //绿值
|
||||
var b = limitB + random.nextInt(256 - limitB); //蓝值
|
||||
return Color.fromARGB(255, r, g, b); //生成argb模式的颜色
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
theWorld() {
|
||||
if (_controller.isAnimating) {
|
||||
_controller.stop();
|
||||
} else {
|
||||
_controller.repeat();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: theWorld,
|
||||
child: CustomPaint(
|
||||
size: pm.size,
|
||||
painter: WorldRender(manage: pm),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ParticleManage with ChangeNotifier {
|
||||
List<Particle> particles = [];
|
||||
|
||||
Size size;
|
||||
|
||||
ParticleManage({this.size = Size.zero});
|
||||
|
||||
void setParticles(List<Particle> particles) {
|
||||
this.particles = particles;
|
||||
}
|
||||
|
||||
void addParticle(Particle particle) {
|
||||
particles.add(particle);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void tick() {
|
||||
particles.forEach(doUpdate);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void doUpdate(Particle p) {
|
||||
p.vy += p.ay; // y加速度变化
|
||||
p.vx += p.ax; // x加速度变化
|
||||
p.x += p.vx;
|
||||
p.y += p.vy;
|
||||
if (p.x > size.width) {
|
||||
p.x = size.width;
|
||||
p.vx = -p.vx;
|
||||
}
|
||||
if (p.x < 0) {
|
||||
p.x = 0;
|
||||
p.vx = -p.vx;
|
||||
}
|
||||
if (p.y > size.height) {
|
||||
p.y = size.height;
|
||||
p.vy = -p.vy;
|
||||
}
|
||||
if (p.y < 0) {
|
||||
p.y = 0;
|
||||
p.vy = -p.vy;
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
particles.forEach((p) {
|
||||
p.x = 0;
|
||||
});
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
class WorldRender extends CustomPainter {
|
||||
|
||||
final ParticleManage manage;
|
||||
|
||||
Paint fillPaint = Paint();
|
||||
|
||||
Paint stokePaint = Paint()
|
||||
..strokeWidth = 0.5
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
WorldRender({required this.manage}) : super(repaint: manage);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
canvas.drawRect(Offset.zero & size, stokePaint);
|
||||
manage.particles.forEach((particle) {
|
||||
drawParticle(canvas, particle);
|
||||
});
|
||||
}
|
||||
|
||||
void drawParticle(Canvas canvas, Particle particle) {
|
||||
fillPaint.color = particle.color;
|
||||
canvas.drawCircle(Offset(particle.x, particle.y), particle.size, fillPaint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant WorldRender oldDelegate) =>
|
||||
oldDelegate.manage != manage;
|
||||
}
|
||||
|
||||
|
||||
class Particle {
|
||||
/// x 位移.
|
||||
double x;
|
||||
|
||||
/// y 位移.
|
||||
double y;
|
||||
|
||||
/// 粒子水平速度.
|
||||
double vx;
|
||||
|
||||
// 粒子水平加速度
|
||||
double ax;
|
||||
|
||||
// 粒子竖直加速度
|
||||
double ay;
|
||||
|
||||
///粒子竖直速度.
|
||||
double vy;
|
||||
|
||||
|
||||
/// 粒子大小.
|
||||
double size;
|
||||
|
||||
/// 粒子颜色.
|
||||
Color color;
|
||||
|
||||
Particle({
|
||||
this.x = 0,
|
||||
this.y = 0,
|
||||
this.ax = 0,
|
||||
this.ay = 0,
|
||||
this.vx = 0,
|
||||
this.vy = 0,
|
||||
this.size = 0,
|
||||
this.color = Colors.black,
|
||||
});
|
||||
}
|
||||
218
packages/idraw/lib/p18/s03.dart
Normal file
218
packages/idraw/lib/p18/s03.dart
Normal file
@@ -0,0 +1,218 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
// import 'dart:ui' as ui;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/5
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: const World(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class World extends StatefulWidget {
|
||||
const World({super.key});
|
||||
|
||||
@override
|
||||
_WorldState createState() => _WorldState();
|
||||
}
|
||||
|
||||
class _WorldState extends State<World> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
ParticleManage pm = ParticleManage();
|
||||
Random random = Random();
|
||||
late Timer timer;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
pm.size = Size(300, 200);
|
||||
|
||||
timer =Timer.periodic(Duration(seconds: 1), (timer) {
|
||||
if(pm.particles.length>20){
|
||||
timer.cancel();
|
||||
}
|
||||
pm.addParticle(Particle(
|
||||
color: randomRGB(),
|
||||
size: 5 + 4 * random.nextDouble(),
|
||||
vx: 3 * random.nextDouble() * pow(-1, random.nextInt(20)),
|
||||
vy: 3 * random.nextDouble() * pow(-1, random.nextInt(20)),
|
||||
ay: 0.1,
|
||||
x: 150,
|
||||
y: 100));
|
||||
});
|
||||
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(seconds: 1),
|
||||
vsync: this,
|
||||
)..addListener(pm.tick)
|
||||
..repeat();
|
||||
}
|
||||
|
||||
Color randomRGB({int limitR = 0, int limitG = 0, int limitB = 0,}) {
|
||||
var r = limitR + random.nextInt(256 - limitR); //红值
|
||||
var g = limitG + random.nextInt(256 - limitG); //绿值
|
||||
var b = limitB + random.nextInt(256 - limitB); //蓝值
|
||||
return Color.fromARGB(255, r, g, b); //生成argb模式的颜色
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
timer.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
theWorld() {
|
||||
if (_controller.isAnimating) {
|
||||
_controller.stop();
|
||||
} else {
|
||||
_controller.repeat();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: theWorld,
|
||||
child: CustomPaint(
|
||||
size: pm.size,
|
||||
painter: WorldRender(manage: pm),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ParticleManage with ChangeNotifier {
|
||||
List<Particle> particles = [];
|
||||
|
||||
Size size;
|
||||
|
||||
ParticleManage({this.size = Size.zero});
|
||||
|
||||
void setParticles(List<Particle> particles) {
|
||||
this.particles = particles;
|
||||
}
|
||||
|
||||
void addParticle(Particle particle) {
|
||||
particles.add(particle);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void tick() {
|
||||
particles.forEach(doUpdate);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void doUpdate(Particle p) {
|
||||
p.vy += p.ay; // y加速度变化
|
||||
p.vx += p.ax; // x加速度变化
|
||||
p.x += p.vx;
|
||||
p.y += p.vy;
|
||||
if (p.x > size.width) {
|
||||
p.x = size.width;
|
||||
p.vx = -p.vx;
|
||||
}
|
||||
if (p.x < 0) {
|
||||
p.x = 0;
|
||||
p.vx = -p.vx;
|
||||
}
|
||||
if (p.y > size.height) {
|
||||
p.y = size.height;
|
||||
p.vy = -p.vy;
|
||||
}
|
||||
if (p.y < 0) {
|
||||
p.y = 0;
|
||||
p.vy = -p.vy;
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
particles.forEach((p) {
|
||||
p.x = 0;
|
||||
});
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
class WorldRender extends CustomPainter {
|
||||
|
||||
final ParticleManage manage;
|
||||
|
||||
Paint fillPaint = Paint();
|
||||
|
||||
Paint stokePaint = Paint()
|
||||
..strokeWidth = 0.5
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
WorldRender({required this.manage}) : super(repaint: manage);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
canvas.drawRect(Offset.zero & size, stokePaint);
|
||||
manage.particles.forEach((particle) {
|
||||
drawParticle(canvas, particle);
|
||||
});
|
||||
}
|
||||
|
||||
void drawParticle(Canvas canvas, Particle particle) {
|
||||
fillPaint.color = particle.color;
|
||||
canvas.drawCircle(Offset(particle.x, particle.y), particle.size, fillPaint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant WorldRender oldDelegate) =>
|
||||
oldDelegate.manage != manage;
|
||||
}
|
||||
|
||||
|
||||
class Particle {
|
||||
/// x 位移.
|
||||
double x;
|
||||
|
||||
/// y 位移.
|
||||
double y;
|
||||
|
||||
/// 粒子水平速度.
|
||||
double vx;
|
||||
|
||||
// 粒子水平加速度
|
||||
double ax;
|
||||
|
||||
// 粒子竖直加速度
|
||||
double ay;
|
||||
|
||||
///粒子竖直速度.
|
||||
double vy;
|
||||
|
||||
|
||||
/// 粒子大小.
|
||||
double size;
|
||||
|
||||
/// 粒子颜色.
|
||||
Color color;
|
||||
|
||||
Particle({
|
||||
this.x = 0,
|
||||
this.y = 0,
|
||||
this.ax = 0,
|
||||
this.ay = 0,
|
||||
this.vx = 0,
|
||||
this.vy = 0,
|
||||
this.size = 0,
|
||||
this.color = Colors.black,
|
||||
});
|
||||
}
|
||||
207
packages/idraw/lib/p18/s04.dart
Normal file
207
packages/idraw/lib/p18/s04.dart
Normal file
@@ -0,0 +1,207 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
// import 'dart:ui' as ui;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/5
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: const World(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class World extends StatefulWidget {
|
||||
const World({super.key});
|
||||
|
||||
@override
|
||||
_WorldState createState() => _WorldState();
|
||||
}
|
||||
|
||||
class _WorldState extends State<World> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
ParticleManage pm = ParticleManage();
|
||||
Random random = Random();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
pm.size = Size(300, 200);
|
||||
|
||||
pm.addParticle(Particle(
|
||||
color: Colors.blue,
|
||||
size: 50,
|
||||
vx: 4 * random.nextDouble() * pow(-1, random.nextInt(20)),
|
||||
vy: 4 * random.nextDouble() * pow(-1, random.nextInt(20)),
|
||||
ay: 0.1,
|
||||
ax: 0.1,
|
||||
x: 150,
|
||||
y: 100));
|
||||
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(seconds: 1),
|
||||
vsync: this,
|
||||
)
|
||||
..addListener(pm.tick)
|
||||
// ..repeat()
|
||||
;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
theWorld() {
|
||||
if (_controller.isAnimating) {
|
||||
_controller.stop();
|
||||
} else {
|
||||
_controller.repeat();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: theWorld,
|
||||
child: CustomPaint(
|
||||
size: pm.size,
|
||||
painter: WorldRender(manage: pm),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ParticleManage with ChangeNotifier {
|
||||
List<Particle> particles = [];
|
||||
|
||||
Size size;
|
||||
|
||||
ParticleManage({this.size = Size.zero});
|
||||
|
||||
void setParticles(List<Particle> particles) {
|
||||
this.particles = particles;
|
||||
}
|
||||
|
||||
void addParticle(Particle particle) {
|
||||
particles.add(particle);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void tick() {
|
||||
particles.forEach(doUpdate);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void doUpdate(Particle p) {
|
||||
p.vy += p.ay; // y加速度变化
|
||||
p.vx += p.ax; // x加速度变化
|
||||
p.x += p.vx;
|
||||
p.y += p.vy;
|
||||
if (p.x > size.width) {
|
||||
p.x = size.width;
|
||||
p.vx = -p.vx;
|
||||
}
|
||||
if (p.x < 0) {
|
||||
p.x = 0;
|
||||
p.vx = -p.vx;
|
||||
}
|
||||
if (p.y > size.height) {
|
||||
p.y = size.height;
|
||||
p.vy = -p.vy;
|
||||
}
|
||||
if (p.y < 0) {
|
||||
p.y = 0;
|
||||
p.vy = -p.vy;
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
particles.forEach((p) {
|
||||
p.x = 0;
|
||||
});
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
class WorldRender extends CustomPainter {
|
||||
|
||||
final ParticleManage manage;
|
||||
|
||||
Paint fillPaint = Paint();
|
||||
|
||||
Paint stokePaint = Paint()
|
||||
..strokeWidth = 0.5
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
WorldRender({required this.manage}) : super(repaint: manage);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
canvas.drawRect(Offset.zero & size, stokePaint);
|
||||
manage.particles.forEach((particle) {
|
||||
drawParticle(canvas, particle);
|
||||
});
|
||||
}
|
||||
|
||||
void drawParticle(Canvas canvas, Particle particle) {
|
||||
fillPaint.color = particle.color;
|
||||
canvas.drawCircle(Offset(particle.x, particle.y), particle.size, fillPaint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant WorldRender oldDelegate) =>
|
||||
oldDelegate.manage != manage;
|
||||
}
|
||||
|
||||
|
||||
class Particle {
|
||||
/// x 位移.
|
||||
double x;
|
||||
|
||||
/// y 位移.
|
||||
double y;
|
||||
|
||||
/// 粒子水平速度.
|
||||
double vx;
|
||||
|
||||
// 粒子水平加速度
|
||||
double ax;
|
||||
|
||||
// 粒子竖直加速度
|
||||
double ay;
|
||||
|
||||
///粒子竖直速度.
|
||||
double vy;
|
||||
|
||||
|
||||
/// 粒子大小.
|
||||
double size;
|
||||
|
||||
/// 粒子颜色.
|
||||
Color color;
|
||||
|
||||
Particle({
|
||||
this.x = 0,
|
||||
this.y = 0,
|
||||
this.ax = 0,
|
||||
this.ay = 0,
|
||||
this.vx = 0,
|
||||
this.vy = 0,
|
||||
this.size = 0,
|
||||
this.color = Colors.black,
|
||||
});
|
||||
}
|
||||
244
packages/idraw/lib/p18/s05.dart
Normal file
244
packages/idraw/lib/p18/s05.dart
Normal file
@@ -0,0 +1,244 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
// import 'dart:ui' as ui;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:image/image.dart' as image;
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/5
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class Paper extends StatelessWidget {
|
||||
const Paper({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: const World(),
|
||||
);
|
||||
}
|
||||
}
|
||||
class World extends StatefulWidget {
|
||||
const World({super.key});
|
||||
|
||||
@override
|
||||
_WorldState createState() => _WorldState();
|
||||
}
|
||||
|
||||
class _WorldState extends State<World> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
ParticleManage pm = ParticleManage();
|
||||
Random random = Random();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
pm.size = Size(400, 260);
|
||||
|
||||
initParticles();
|
||||
|
||||
// pm.addParticle(Particle(
|
||||
// color: Colors.blue,
|
||||
// size: 50,
|
||||
// vx: 4 * random.nextDouble() * pow(-1, random.nextInt(20)),
|
||||
// vy: 4 * random.nextDouble() * pow(-1, random.nextInt(20)),
|
||||
// ay: 0.1,
|
||||
// ax: 0.1,
|
||||
// x: 150,
|
||||
// y: 100));
|
||||
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(seconds: 1),
|
||||
vsync: this,
|
||||
)..addListener(pm.tick)
|
||||
// ..repeat()
|
||||
;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
theWorld() {
|
||||
if (_controller.isAnimating) {
|
||||
_controller.stop();
|
||||
} else {
|
||||
_controller.repeat();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: theWorld,
|
||||
child: CustomPaint(
|
||||
size: pm.size,
|
||||
painter: WorldRender(manage: pm),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void initParticles() async {
|
||||
ByteData data = await rootBundle.load("assets/images/flutter.png");
|
||||
List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
|
||||
image.Image? imageSrc = image.decodeImage(Uint8List.fromList(bytes));
|
||||
if(imageSrc==null) return;
|
||||
|
||||
double offsetX= (pm.size.width-imageSrc.width)/2;
|
||||
double offsetY= (pm.size.height-imageSrc.height)/2;
|
||||
|
||||
for (int i = 0; i < imageSrc.width; i++) {
|
||||
for (int j = 0; j < imageSrc.height; j++) {
|
||||
image.PixelUint8 pixel = imageSrc.getPixel(i, j) as image.PixelUint8;
|
||||
|
||||
if (pixel.toString() != '(255, 255, 255, 0)') {
|
||||
// print('-($i,$j)----${imageSrc.getPixel(i, j)}---------------');
|
||||
|
||||
Particle particle = Particle(
|
||||
x: i * 1.0+ offsetX,
|
||||
y: j * 1.0+ offsetY,
|
||||
vx: 4 * random.nextDouble() * pow(-1, random.nextInt(20)),
|
||||
vy: 4 * random.nextDouble() * pow(-1, random.nextInt(20)),
|
||||
ay: 0.1,
|
||||
size: 0.5,
|
||||
color: Colors.blue); //产生粒子---每个粒子拥有随机的一些属性信息
|
||||
|
||||
pm.particles.add(particle);
|
||||
}
|
||||
}
|
||||
}
|
||||
setState(() {
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ParticleManage with ChangeNotifier {
|
||||
List<Particle> particles = [];
|
||||
|
||||
Size size;
|
||||
|
||||
ParticleManage({this.size = Size.zero});
|
||||
|
||||
void setParticles(List<Particle> particles) {
|
||||
this.particles = particles;
|
||||
}
|
||||
|
||||
void addParticle(Particle particle) {
|
||||
particles.add(particle);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void tick() {
|
||||
particles.forEach(doUpdate);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void doUpdate(Particle p) {
|
||||
p.vy += p.ay; // y加速度变化
|
||||
p.vx += p.ax; // x加速度变化
|
||||
p.x += p.vx;
|
||||
p.y += p.vy;
|
||||
if (p.x > size.width) {
|
||||
p.x = size.width;
|
||||
p.vx = -p.vx;
|
||||
}
|
||||
if (p.x < 0) {
|
||||
p.x = 0;
|
||||
p.vx = -p.vx;
|
||||
}
|
||||
if (p.y > size.height) {
|
||||
p.y = size.height;
|
||||
p.vy = -p.vy;
|
||||
}
|
||||
if (p.y < 0) {
|
||||
p.y = 0;
|
||||
p.vy = -p.vy;
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
particles.forEach((p) {
|
||||
p.x = 0;
|
||||
});
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
class WorldRender extends CustomPainter {
|
||||
|
||||
final ParticleManage manage;
|
||||
|
||||
Paint fillPaint = Paint();
|
||||
|
||||
Paint stokePaint = Paint()
|
||||
..strokeWidth = 0.5
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
WorldRender({required this.manage}) : super(repaint: manage);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
// canvas.drawRect(Offset.zero&size, stokePaint);
|
||||
manage.particles.forEach((particle) {
|
||||
drawParticle(canvas, particle);
|
||||
});
|
||||
}
|
||||
|
||||
void drawParticle(Canvas canvas, Particle particle) {
|
||||
|
||||
fillPaint.color = particle.color;
|
||||
canvas.drawCircle(Offset(particle.x, particle.y), particle.size, fillPaint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant WorldRender oldDelegate) =>
|
||||
oldDelegate.manage != manage;
|
||||
}
|
||||
|
||||
|
||||
class Particle {
|
||||
/// x 位移.
|
||||
double x;
|
||||
|
||||
/// y 位移.
|
||||
double y;
|
||||
|
||||
/// 粒子水平速度.
|
||||
double vx;
|
||||
|
||||
// 粒子水平加速度
|
||||
double ax;
|
||||
|
||||
// 粒子竖直加速度
|
||||
double ay;
|
||||
|
||||
///粒子竖直速度.
|
||||
double vy;
|
||||
|
||||
|
||||
/// 粒子大小.
|
||||
double size;
|
||||
|
||||
/// 粒子颜色.
|
||||
Color color;
|
||||
|
||||
Particle({
|
||||
this.x = 0,
|
||||
this.y = 0,
|
||||
this.ax = 0,
|
||||
this.ay = 0,
|
||||
this.vx = 0,
|
||||
this.vy = 0,
|
||||
this.size = 0,
|
||||
this.color = Colors.black,
|
||||
});
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user