From 2f4e8d35646abee3ab00ffc4a514d6eccb0ab157 Mon Sep 17 00:00:00 2001 From: toly <1981462002@qq.com> Date: Thu, 21 Dec 2023 22:06:28 +0800 Subject: [PATCH] books --- assets/palettes.json | 758 ++++++++++++++++++ .../router/menus/menu_scope/menu_scope.dart | 9 +- lib/navigation/router/routers/app.dart | 25 +- lib/navigation/router/routers/draw.dart | 74 +- .../fade_page_transitions_builder.dart | 40 +- .../transition/size_clip_transition.dart | 105 +++ lib/navigation/views/app_navigation.dart | 1 + lib/navigation/views/top_bar.dart | 37 +- .../lib/toly_ui/code_view/code_view.dart | 14 +- .../idraw/lib/components/coordinate_pro.dart | 30 +- packages/idraw/lib/idraw.dart | 7 + packages/idraw/lib/p12/p12.dart | 1 + packages/idraw/lib/p12/p12_page.dart | 25 + packages/idraw/lib/p12/s01.dart | 66 ++ packages/idraw/lib/p12/s02.dart | 109 +++ packages/idraw/lib/p12/s03.dart | 153 ++++ packages/idraw/lib/p12/s04.dart | 167 ++++ packages/idraw/lib/p13/p13.dart | 1 + packages/idraw/lib/p13/p13_page.dart | 25 + packages/idraw/lib/p13/s01.dart | 114 +++ packages/idraw/lib/p13/s02.dart | 123 +++ packages/idraw/lib/p13/s03.dart | 130 +++ packages/idraw/lib/p13/s04.dart | 129 +++ packages/idraw/lib/p14/p14.dart | 1 + packages/idraw/lib/p14/p14_page.dart | 27 + packages/idraw/lib/p14/s01.dart | 62 ++ packages/idraw/lib/p14/s02.dart | 131 +++ packages/idraw/lib/p14/s03.dart | 127 +++ packages/idraw/lib/p14/s04.dart | 170 ++++ packages/idraw/lib/p14/s05.dart | 132 +++ packages/idraw/lib/p14/touch_info.dart | 45 ++ packages/idraw/lib/p15/p15.dart | 1 + packages/idraw/lib/p15/p15_page.dart | 29 + packages/idraw/lib/p15/s01.dart | 68 ++ packages/idraw/lib/p15/s02.dart | 69 ++ packages/idraw/lib/p15/s03.dart | 96 +++ packages/idraw/lib/p15/s04.dart | 106 +++ packages/idraw/lib/p15/s05.dart | 97 +++ packages/idraw/lib/p15/s06.dart | 192 +++++ packages/idraw/lib/p15/touch_info.dart | 45 ++ packages/idraw/lib/p16/p16.dart | 1 + packages/idraw/lib/p16/p16_page.dart | 29 + packages/idraw/lib/p16/s01.dart | 172 ++++ packages/idraw/lib/p16/s02.dart | 197 +++++ packages/idraw/lib/p16/s03.dart | 215 +++++ packages/idraw/lib/p16/s04.dart | 237 ++++++ packages/idraw/lib/p16/s05.dart | 232 ++++++ packages/idraw/lib/p16/s06.dart | 254 ++++++ packages/idraw/lib/p17/p17.dart | 1 + packages/idraw/lib/p17/p17_page.dart | 21 + packages/idraw/lib/p17/s01.dart | 271 +++++++ packages/idraw/lib/p17/s02.dart | 432 ++++++++++ packages/idraw/lib/p18/p18.dart | 1 + packages/idraw/lib/p18/p18_page.dart | 27 + packages/idraw/lib/p18/s01.dart | 201 +++++ packages/idraw/lib/p18/s02.dart | 215 +++++ packages/idraw/lib/p18/s03.dart | 218 +++++ packages/idraw/lib/p18/s04.dart | 207 +++++ packages/idraw/lib/p18/s05.dart | 244 ++++++ packages/idraw/pubspec.yaml | 1 + pubspec.lock | 25 +- pubspec.yaml | 1 + 62 files changed, 6651 insertions(+), 92 deletions(-) create mode 100644 assets/palettes.json create mode 100644 lib/navigation/transition/size_clip_transition.dart create mode 100644 packages/idraw/lib/p12/p12.dart create mode 100644 packages/idraw/lib/p12/p12_page.dart create mode 100644 packages/idraw/lib/p12/s01.dart create mode 100644 packages/idraw/lib/p12/s02.dart create mode 100644 packages/idraw/lib/p12/s03.dart create mode 100644 packages/idraw/lib/p12/s04.dart create mode 100644 packages/idraw/lib/p13/p13.dart create mode 100644 packages/idraw/lib/p13/p13_page.dart create mode 100644 packages/idraw/lib/p13/s01.dart create mode 100644 packages/idraw/lib/p13/s02.dart create mode 100644 packages/idraw/lib/p13/s03.dart create mode 100644 packages/idraw/lib/p13/s04.dart create mode 100644 packages/idraw/lib/p14/p14.dart create mode 100644 packages/idraw/lib/p14/p14_page.dart create mode 100644 packages/idraw/lib/p14/s01.dart create mode 100644 packages/idraw/lib/p14/s02.dart create mode 100644 packages/idraw/lib/p14/s03.dart create mode 100644 packages/idraw/lib/p14/s04.dart create mode 100644 packages/idraw/lib/p14/s05.dart create mode 100644 packages/idraw/lib/p14/touch_info.dart create mode 100644 packages/idraw/lib/p15/p15.dart create mode 100644 packages/idraw/lib/p15/p15_page.dart create mode 100644 packages/idraw/lib/p15/s01.dart create mode 100644 packages/idraw/lib/p15/s02.dart create mode 100644 packages/idraw/lib/p15/s03.dart create mode 100644 packages/idraw/lib/p15/s04.dart create mode 100644 packages/idraw/lib/p15/s05.dart create mode 100644 packages/idraw/lib/p15/s06.dart create mode 100644 packages/idraw/lib/p15/touch_info.dart create mode 100644 packages/idraw/lib/p16/p16.dart create mode 100644 packages/idraw/lib/p16/p16_page.dart create mode 100644 packages/idraw/lib/p16/s01.dart create mode 100644 packages/idraw/lib/p16/s02.dart create mode 100644 packages/idraw/lib/p16/s03.dart create mode 100644 packages/idraw/lib/p16/s04.dart create mode 100644 packages/idraw/lib/p16/s05.dart create mode 100644 packages/idraw/lib/p16/s06.dart create mode 100644 packages/idraw/lib/p17/p17.dart create mode 100644 packages/idraw/lib/p17/p17_page.dart create mode 100644 packages/idraw/lib/p17/s01.dart create mode 100644 packages/idraw/lib/p17/s02.dart create mode 100644 packages/idraw/lib/p18/p18.dart create mode 100644 packages/idraw/lib/p18/p18_page.dart create mode 100644 packages/idraw/lib/p18/s01.dart create mode 100644 packages/idraw/lib/p18/s02.dart create mode 100644 packages/idraw/lib/p18/s03.dart create mode 100644 packages/idraw/lib/p18/s04.dart create mode 100644 packages/idraw/lib/p18/s05.dart diff --git a/assets/palettes.json b/assets/palettes.json new file mode 100644 index 0000000..3ae13a2 --- /dev/null +++ b/assets/palettes.json @@ -0,0 +1,758 @@ +[ + [ + "0xffCC5D4C", + "0xffFFFEC6", + "0xffC7D1AF", + "0xff96B49C", + "0xff5B5847" + ], + [ + "0xffE4E4C5", + "0xffB9D48B", + "0xff8D2036", + "0xffCE0A31", + "0xffD3E4C5" + ], + [ + "0xffEB9C4D", + "0xffF2D680", + "0xffF3FFCF", + "0xffBAC9A9", + "0xff697060" + ], + [ + "0xff360745", + "0xffD61C59", + "0xffE7D84B", + "0xffEFEAC5", + "0xff1B8798" + ], + [ + "0xffF2E8C4", + "0xff98D9B6", + "0xff3EC9A7", + "0xff2B879E", + "0xff616668" + ], + [ + "0xffFFF3DB", + "0xffE7E4D5", + "0xffD3C8B4", + "0xffC84648", + "0xff703E3B" + ], + [ + "0xffF5DD9D", + "0xffBCC499", + "0xff92A68A", + "0xff7B8F8A", + "0xff506266" + ], + [ + "0xff041122", + "0xff259073", + "0xff7FDA89", + "0xffC8E98E", + "0xffE6F99D" + ], + [ + "0xff1D1313", + "0xff24B694", + "0xffD22042", + "0xffA3B808", + "0xff30C4C9" + ], + [ + "0xffF0FFC9", + "0xffA9DA88", + "0xff62997A", + "0xff72243D", + "0xff3B0819" + ], + [ + "0xffC6CCA5", + "0xff8AB8A8", + "0xff6B9997", + "0xff54787D", + "0xff615145" + ], + [ + "0xff429398", + "0xff6B5D4D", + "0xffB0A18F", + "0xffDFCDB4", + "0xffFBEED3" + ], + [ + "0xff2D1B33", + "0xffF36A71", + "0xffEE887A", + "0xffE4E391", + "0xff9ABC8A" + ], + [ + "0xff4B1139", + "0xff3B4058", + "0xff2A6E78", + "0xff7A907C", + "0xffC9B180" + ], + [ + "0xff322938", + "0xff89A194", + "0xffCFC89A", + "0xffCC883A", + "0xffA14016" + ], + [ + "0xff540045", + "0xffC60052", + "0xffFF714B", + "0xffEAFF87", + "0xffACFFE9" + ], + [ + "0xff79254A", + "0xff795C64", + "0xff79927D", + "0xffAEB18E", + "0xffE3CF9E" + ], + [ + "0xff452E3C", + "0xffFF3D5A", + "0xffFFB969", + "0xffEAF27E", + "0xff3B8C88" + ], + [ + "0xff2B2726", + "0xff0A516D", + "0xff018790", + "0xff7DAD93", + "0xffBACCA4" + ], + [ + "0xff027B7F", + "0xffFFA588", + "0xffD62957", + "0xffBF1E62", + "0xff572E4F" + ], + [ + "0xffFA6A64", + "0xff7A4E48", + "0xff4A4031", + "0xffF6E2BB", + "0xff9EC6B8" + ], + [ + "0xff23192D", + "0xffFD0A54", + "0xffF57576", + "0xffFEBF97", + "0xffF5ECB7" + ], + [ + "0xffA3C68C", + "0xff879676", + "0xff6E6662", + "0xff4F364A", + "0xff340735" + ], + [ + "0xffA32C28", + "0xff1C090B", + "0xff384030", + "0xff7B8055", + "0xffBCA875" + ], + [ + "0xff6D9788", + "0xff1E2528", + "0xff7E1C13", + "0xffBF0A0D", + "0xffE6E1C2" + ], + [ + "0xff373737", + "0xff8DB986", + "0xffACCE91", + "0xffBADB73", + "0xffEFEAE4" + ], + [ + "0xff280904", + "0xff680E34", + "0xff9A151A", + "0xffC21B12", + "0xffFC4B2A" + ], + [ + "0xff4B3E4D", + "0xff1E8C93", + "0xffDBD8A2", + "0xffC4AC30", + "0xffD74F33" + ], + [ + "0xffA69E80", + "0xffE0BA9B", + "0xffE7A97E", + "0xffD28574", + "0xff3B1922" + ], + [ + "0xff161616", + "0xffC94D65", + "0xffE7C049", + "0xff92B35A", + "0xff1F6764" + ], + [ + "0xff234D20", + "0xff36802D", + "0xff77AB59", + "0xffC9DF8A", + "0xffF0F7DA" + ], + [ + "0xffE6EBA9", + "0xffABBB9F", + "0xff6F8B94", + "0xff706482", + "0xff703D6F" + ], + [ + "0xffFDCFBF", + "0xffFEB89F", + "0xffE23D75", + "0xff5F0D3B", + "0xff742365" + ], + [ + "0xff641F5E", + "0xff676077", + "0xff65AC92", + "0xffC2C092", + "0xffEDD48E" + ], + [ + "0xff26251C", + "0xffEB0A44", + "0xffF2643D", + "0xffF2A73D", + "0xffA0E8B7" + ], + [ + "0xff4F364C", + "0xff5E405F", + "0xff6B6B6B", + "0xff8F9E6F", + "0xffB1CF72" + ], + [ + "0xff230B00", + "0xffA29D7F", + "0xffD4CFA5", + "0xffF8ECD4", + "0xffAABE9B" + ], + [ + "0xff85847E", + "0xffAB6A6E", + "0xffF7345B", + "0xff353130", + "0xffCBCFB4" + ], + [ + "0xffD24858", + "0xffEA8676", + "0xffEAB05E", + "0xffFDEECD", + "0xff493831" + ], + [ + "0xffD3D5B0", + "0xffB5CEA4", + "0xff9DC19D", + "0xff8C7C62", + "0xff71443F" + ], + [ + "0xffFFFF99", + "0xffD9CC8C", + "0xffB39980", + "0xff8C6673", + "0xff663366" + ], + [ + "0xffED6464", + "0xffBF6370", + "0xff87586C", + "0xff574759", + "0xff1A1B1C" + ], + [ + "0xffCCB24C", + "0xffF7D683", + "0xffFFFDC0", + "0xffFFFFFD", + "0xff457D97" + ], + [ + "0xffF0F0D8", + "0xffB4DEBE", + "0xff77CCA4", + "0xff666666", + "0xffB4DF37" + ], + [ + "0xff1A081F", + "0xff4D1D4D", + "0xff05676E", + "0xff489C79", + "0xffEBC288" + ], + [ + "0xff7A5B3E", + "0xffFAFAFA", + "0xffFA4B00", + "0xffCDBDAE", + "0xff1F1F1F" + ], + [ + "0xffD31900", + "0xffFF6600", + "0xffFFF2AF", + "0xff7CB490", + "0xff000000" + ], + [ + "0xffE8C382", + "0xffB39D69", + "0xffA86B4C", + "0xff7D1A0C", + "0xff340A0B" + ], + [ + "0xffEBEAA9", + "0xffEBC588", + "0xff7D2948", + "0xff3B0032", + "0xff0E0B29" + ], + [ + "0xff063940", + "0xff195E63", + "0xff3E838C", + "0xff8EBDB6", + "0xffECE1C3" + ], + [ + "0xff595B5A", + "0xff14C3A2", + "0xff0DE5A8", + "0xff7CF49A", + "0xffB8FD99" + ], + [ + "0xff411F2D", + "0xffAC4147", + "0xffF88863", + "0xffFFC27F", + "0xffFFE29A" + ], + [ + "0xffE7E79D", + "0xffC0D890", + "0xff78A890", + "0xff606078", + "0xffD8A878" + ], + [ + "0xff9DBCBC", + "0xffF0F0AF", + "0xffFF370F", + "0xff332717", + "0xff6BACBF" + ], + [ + "0xff94654C", + "0xffF89FA1", + "0xffFABDBD", + "0xffFAD6D6", + "0xffFEFCD0" + ], + [ + "0xff1F1F20", + "0xff2B4C7E", + "0xff567EBB", + "0xff606D80", + "0xffDCE0E6" + ], + [ + "0xffCDDBC2", + "0xffF7E4C6", + "0xffFB9274", + "0xffF5565B", + "0xff875346" + ], + [ + "0xffECBE13", + "0xff738C79", + "0xff6A6B5F", + "0xff2C2B26", + "0xffA43955" + ], + [ + "0xffFFF5DE", + "0xffB8D9C8", + "0xff917081", + "0xff750E49", + "0xff4D002B" + ], + [ + "0xffF0DDBD", + "0xffBA3622", + "0xff851E25", + "0xff520C30", + "0xff1C997F" + ], + [ + "0xff312C20", + "0xff494D4B", + "0xff7C7052", + "0xffB3A176", + "0xffE2CB92" + ], + [ + "0xff3F2C26", + "0xffDD423E", + "0xffA2A384", + "0xffEAC388", + "0xffC5AD4B" + ], + [ + "0xff0A0310", + "0xff49007E", + "0xffFF005B", + "0xffFF7D10", + "0xffFFB238" + ], + [ + "0xffCDECCC", + "0xffEDD269", + "0xffE88460", + "0xffF23460", + "0xff321D2E" + ], + [ + "0xff574C41", + "0xffE36B6B", + "0xffE3A56B", + "0xffE3C77B", + "0xff96875A" + ], + [ + "0xffE7DD96", + "0xffE16639", + "0xffAD860A", + "0xffB7023F", + "0xff55024A" + ], + [ + "0xff213435", + "0xff46685B", + "0xff648A64", + "0xffA6B985", + "0xffE1E3AC" + ], + [ + "0xff181419", + "0xff4A073C", + "0xff9E0B41", + "0xffCC3E18", + "0xffF0971C" + ], + [ + "0xff413040", + "0xff6C6368", + "0xffB9A173", + "0xffEAA353", + "0xffFFEFA9" + ], + [ + "0xff4D3B36", + "0xffEB613B", + "0xffF98F6F", + "0xffC1D9CD", + "0xffF7EADC" + ], + [ + "0xffFFCDB8", + "0xffFDEECF", + "0xffC8C696", + "0xff97BEA9", + "0xff37260C" + ], + [ + "0xff130912", + "0xff3E1C33", + "0xff602749", + "0xffB14623", + "0xffF6921D" + ], + [ + "0xffFFFF00", + "0xffCCD91A", + "0xff99B333", + "0xff668C4D", + "0xff336666" + ], + [ + "0xff001449", + "0xff012677", + "0xff005BC5", + "0xff00B4FC", + "0xff17F9FF" + ], + [ + "0xffED5672", + "0xff160E32", + "0xff9EAE8A", + "0xffCDBB93", + "0xffFBC599" + ], + [ + "0xff785D56", + "0xffBE4C54", + "0xffC6B299", + "0xffE6D5C1", + "0xffFFF4E3" + ], + [ + "0xff2B1719", + "0xff02483E", + "0xff057C46", + "0xff9BB61B", + "0xffF8BE00" + ], + [ + "0xffE6A06F", + "0xff9E9C71", + "0xff5E8271", + "0xff33454E", + "0xff242739" + ], + [ + "0xffF7F3D5", + "0xffFFDABF", + "0xffFA9B9B", + "0xffE88087", + "0xff635063" + ], + [ + "0xffE7EED0", + "0xffCAD1C3", + "0xff948E99", + "0xff51425F", + "0xff2E1437" + ], + [ + "0xffE25858", + "0xffE9D6AF", + "0xffFFFFDD", + "0xffC0EFD2", + "0xff384252" + ], + [ + "0xffACDEB2", + "0xffE1EAB5", + "0xffEDAD9E", + "0xffFE4B74", + "0xff390D2D" + ], + [ + "0xff42282C", + "0xff6CA19E", + "0xff84ABAA", + "0xffDED1B6", + "0xff6D997A" + ], + [ + "0xffFDFFD9", + "0xff73185E", + "0xff36BBA6", + "0xff0C0D02", + "0xff8B911A" + ], + [ + "0xff9F0A28", + "0xffD55C2B", + "0xffF6E7D3", + "0xff89A46F", + "0xff55203C" + ], + [ + "0xffA69A90", + "0xff4A403D", + "0xffFFF1C1", + "0xffFACF7D", + "0xffEA804C" + ], + [ + "0xff418E8E", + "0xff5A4E3C", + "0xffC4D428", + "0xffD8E472", + "0xffE9EBBF" + ], + [ + "0xffC9D1D3", + "0xffF7F7F7", + "0xff9DD3DF", + "0xff3B3737", + "0xff991818" + ], + [ + "0xffFAF6D0", + "0xffC7D8AB", + "0xff909A92", + "0xff744F78", + "0xff30091E" + ], + [ + "0xffF6C7B7", + "0xffF7A398", + "0xffFA7F77", + "0xffB42529", + "0xff000000" + ], + [ + "0xffA7321C", + "0xffFFDC68", + "0xffCC982A", + "0xff928941", + "0xff352504" + ], + [ + "0xffF0371A", + "0xff000000", + "0xffF7E6A6", + "0xff3E6B48", + "0xffB5B479" + ], + [ + "0xffF4F4F4", + "0xff9BA657", + "0xffF0E5C9", + "0xffA68C69", + "0xff594433" + ], + [ + "0xffF1E8B4", + "0xffB2BB91", + "0xffD7BF5E", + "0xffD16344", + "0xff83555E" + ], + [ + "0xff000000", + "0xff001F36", + "0xff1C5560", + "0xff79AE92", + "0xffFBFFCD" + ], + [ + "0xffE0DC8B", + "0xffF6AA3D", + "0xffED4C57", + "0xff574435", + "0xff6CC4B9" + ], + [ + "0xff42393B", + "0xff75C9A3", + "0xffBAC99A", + "0xffFFC897", + "0xffF7EFA2" + ], + [ + "0xffF2CC67", + "0xffF38264", + "0xffF40034", + "0xff5F051F", + "0xff75BAA8" + ], + [ + "0xffFBFEE5", + "0xffC91842", + "0xff98173D", + "0xff25232D", + "0xffA8E7CA" + ], + [ + "0xff998496", + "0xffF7E0AE", + "0xffFA748F", + "0xff2D2C26", + "0xffC3B457" + ], + [ + "0xffDBD9B7", + "0xffC1C9C8", + "0xffA5B5AB", + "0xff949A8E", + "0xff615566" + ], + [ + "0xffF3E6BC", + "0xffF1C972", + "0xffF5886B", + "0xff72AE95", + "0xff5A3226" + ], + [ + "0xffD9D4A8", + "0xffD15C57", + "0xffCC3747", + "0xff5C374B", + "0xff4A5F67" + ], + [ + "0xff674F23", + "0xffE48B69", + "0xffE1B365", + "0xffE5DB84", + "0xffFFEEAC" + ], + [ + "0xffBF2A23", + "0xffA6AD3C", + "0xffF0CE4E", + "0xffCF872E", + "0xff8A211D" + ], + [ + "0xff84C1B1", + "0xffAD849A", + "0xffD64783", + "0xffFD135A", + "0xff40202A" + ], + [ + "0xff020304", + "0xff541F14", + "0xff938172", + "0xffCC9E61", + "0xff626266" + ], + [ + "0xff002C2B", + "0xffFF3D00", + "0xffFFBC11", + "0xff0A837F", + "0xff076461" + ] +] diff --git a/lib/navigation/router/menus/menu_scope/menu_scope.dart b/lib/navigation/router/menus/menu_scope/menu_scope.dart index ab94fcd..9b19280 100644 --- a/lib/navigation/router/menus/menu_scope/menu_scope.dart +++ b/lib/navigation/router/menus/menu_scope/menu_scope.dart @@ -62,7 +62,6 @@ class MenuStore with ChangeNotifier { ?.label; void selectMenuPath(String path) { - print("======================selectMenuPath:$path======${_shouldAddHistory}=============="); MenuNode root = MenuNode( path: '', label: '', @@ -160,6 +159,14 @@ class MenuStore with ChangeNotifier { } void select(MenuNode menu) { + bool hasHistory = _history.where((e) => e.menuPath==menu.path).isNotEmpty; + if(hasHistory){ + _shouldAddHistory = false; + selectMenuPath(menu.path); + notifyListeners(); + return; + } + if (menu.isLeaf) { _state = state.copyWith(activeMenu: menu.path); goRouter.go(menu.path); diff --git a/lib/navigation/router/routers/app.dart b/lib/navigation/router/routers/app.dart index 25db920..83acb19 100644 --- a/lib/navigation/router/routers/app.dart +++ b/lib/navigation/router/routers/app.dart @@ -1,4 +1,5 @@ import 'package:components/components.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:iroute/navigation/router/routers/anima.dart'; @@ -7,13 +8,13 @@ import 'package:iroute/navigation/router/routers/render.dart'; import 'package:iroute/navigation/router/routers/scroll.dart'; import 'package:iroute/navigation/router/routers/touch.dart'; +import '../../transition/size_clip_transition.dart'; import '../../views/app_navigation.dart'; import '../../../pages/empty/empty_panel.dart'; import 'dashboard.dart'; import 'draw.dart'; import 'layout.dart'; - final RouteBase appRoute = ShellRoute( builder: (BuildContext context, GoRouterState state, Widget child) { return TolyBookNavigation(content: child); @@ -29,9 +30,27 @@ final RouteBase appRoute = ShellRoute( animaRouters, GoRoute( path: '/code', - builder: (BuildContext context, GoRouterState state) { + pageBuilder: (BuildContext context, GoRouterState state) { String? path = state.uri.queryParameters['path']; - return CodeView(path: path??'',); + return CustomTransitionPage( + transitionDuration: const Duration(milliseconds: 500), + reverseTransitionDuration: const Duration(milliseconds: 500), + child: CodeView( + path: path ?? '', + ), + transitionsBuilder: (_, a1, a2, child) => + SizeClipTransition( + animation: a1, + secondaryAnimation: a2, + child: child, + ) + // CupertinoPageTransition( + // primaryRouteAnimation: a1, + // secondaryRouteAnimation: a2, + // linearTransition: true, + // child: child, + // ), + ); }, ), GoRoute( diff --git a/lib/navigation/router/routers/draw.dart b/lib/navigation/router/routers/draw.dart index 2b3c2ef..6a9ddb4 100644 --- a/lib/navigation/router/routers/draw.dart +++ b/lib/navigation/router/routers/draw.dart @@ -5,32 +5,76 @@ import 'package:iroute/pages/empty/empty_panel.dart'; final RouteBase drawRouters = GoRoute( path: '/draw/chapter:index', - builder: (BuildContext context, GoRouterState state) { + pageBuilder: (BuildContext context, GoRouterState state) { String? index = state.pathParameters['index']; - switch(index){ + Widget child = const EmptyPanel(msg: '暂未实现'); + switch (index) { case '1': - return const P01Page(); + child = const P01Page(); + break; case '2': - return const P02Page(); + child = const P02Page(); + break; case '3': - return const P03Page(); + child = const P03Page(); + break; case '4': - return const P04Page(); + child = const P04Page(); + break; case '5': - return const P05Page(); + child = const P05Page(); + break; case '6': - return const P06Page(); + child = const P06Page(); + break; case '7': - return const P07Page(); + child = const P07Page(); + break; case '8': - return const P08Page(); + child = const P08Page(); + break; case '9': - return const P09Page(); + child = const P09Page(); + break; case '10': - return const P10Page(); - case '11': - return const P11Page(); + child = const P10Page(); + break; + case '11': + child = const P11Page(); + break; + case '12': + child = const P12Page(); + break; + case '13': + child = const P13Page(); + break; + case '14': + child = const P14Page(); + break; + case '15': + child = const P15Page(); + break; + case '16': + child = const P16Page(); + break; + case '17': + child = const P17Page(); + break; + case '18': + child = const P18Page(); + break; } - return const EmptyPanel(msg: '暂未实现'); + + return CustomTransitionPage( + child: child, + transitionsBuilder: (ctx, a1, a2, child) => FadeTransition( + opacity: a1.drive(CurveTween(curve: Curves.easeIn)), + child: SlideTransition( + position: Tween( + begin: Offset.zero, end: const Offset(-1.0, 0.0)) + .animate(a2), + child: child, + ), + )); }, ); diff --git a/lib/navigation/transition/fade_page_transitions_builder.dart b/lib/navigation/transition/fade_page_transitions_builder.dart index 0587ecc..d0e9e3f 100644 --- a/lib/navigation/transition/fade_page_transitions_builder.dart +++ b/lib/navigation/transition/fade_page_transitions_builder.dart @@ -1,43 +1,19 @@ import 'package:flutter/material.dart'; class FadePageTransitionsBuilder extends PageTransitionsBuilder { - const FadePageTransitionsBuilder(); @override Widget buildTransitions( - PageRoute? route, - BuildContext? context, - Animation animation, - Animation secondaryAnimation, - Widget child, - ) { - return _FadePagePageTransition( - animation: animation, - secondaryAnimation: secondaryAnimation, + PageRoute? route, + BuildContext? context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) { + return FadeTransition( + opacity: animation.drive(CurveTween(curve: Curves.easeIn)), child: child, ); } } - -class _FadePagePageTransition extends StatelessWidget { - - const _FadePagePageTransition({ - required this.animation, - required this.secondaryAnimation, - required this.child, - }); - - final Animation animation; - final Animation secondaryAnimation; - final Widget child; - - @override - Widget build(BuildContext context) { - var curveTween = CurveTween(curve: Curves.easeIn); - return FadeTransition( - opacity: animation.drive(curveTween), - child: child, - ); - } -} \ No newline at end of file diff --git a/lib/navigation/transition/size_clip_transition.dart b/lib/navigation/transition/size_clip_transition.dart new file mode 100644 index 0000000..f3fa0f5 --- /dev/null +++ b/lib/navigation/transition/size_clip_transition.dart @@ -0,0 +1,105 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; + +class SizeClipTransition extends StatelessWidget { + final Animation animation; + final Animation secondaryAnimation; + final Widget child; + + const SizeClipTransition({ + super.key, + required this.animation, + required this.secondaryAnimation, + required this.child, + }); + + @override + Widget build(BuildContext context) { + return ClipPath( + clipper: CirclePathClipper(Curves.easeIn.transform(animation.value)), + child: child, + ); + } +} + +class SizePathClipper extends CustomClipper { + final double progress; + + SizePathClipper(this.progress); + + @override + Path getClip(Size size) { + Rect box = Rect.fromLTWH(0, 0, size.width, size.height); + Rect center = Rect.fromCenter( + center: Offset(size.width / 2, size.height / 2), + width: size.width * (1 - progress), + height: size.height, + ); + + return Path() + ..addRect(box) + ..addRect(center) + ..fillType = PathFillType.evenOdd; + } + + @override + bool shouldReclip(covariant SizePathClipper oldClipper) { + return oldClipper.progress != progress; + } +} + +class ScalePathClipper extends CustomClipper { + final double progress; + + ScalePathClipper(this.progress); + + @override + Path getClip(Size size) { + Rect box = Rect.fromLTWH(0, 0, size.width, size.height); + Rect center = Rect.fromCenter( + center: Offset(size.width / 2, size.height / 2), + width: size.width * (1 - progress), + height: size.height* (1 - progress), + ); + + return Path() + ..addRect(box) + ..addRect(center) + ..fillType = PathFillType.evenOdd; + } + + @override + bool shouldReclip(covariant ScalePathClipper oldClipper) { + return oldClipper.progress != progress; + } +} + +class CirclePathClipper extends CustomClipper { + final double progress; + + CirclePathClipper(this.progress); + + @override + Path getClip(Size size) { + print('progress:$progress'); + if(progress==0){ + return Path(); + } + Rect box = Rect.fromLTWH(0, 0, size.width, size.height); + Rect center = Rect.fromCircle( + center: Offset(size.width , 0), + radius: sqrt(size.width*size.width+size.height*size.height) * (progress), + ); + + Path zone = Path()..addRect(box); + Path cliper = Path()..addOval(center); + + return Path.combine(PathOperation.intersect, zone, cliper ); + } + + @override + bool shouldReclip(covariant CirclePathClipper oldClipper) { + return oldClipper.progress != progress; + } +} \ No newline at end of file diff --git a/lib/navigation/views/app_navigation.dart b/lib/navigation/views/app_navigation.dart index c13994d..fd31183 100644 --- a/lib/navigation/views/app_navigation.dart +++ b/lib/navigation/views/app_navigation.dart @@ -13,6 +13,7 @@ class TolyBookNavigation extends StatelessWidget { @override Widget build(BuildContext context) { + return Scaffold( body: Row( children: [ diff --git a/lib/navigation/views/top_bar.dart b/lib/navigation/views/top_bar.dart index 131a111..def4058 100644 --- a/lib/navigation/views/top_bar.dart +++ b/lib/navigation/views/top_bar.dart @@ -10,23 +10,26 @@ class AppTopBar extends StatelessWidget { Widget build(BuildContext context) { // String? lable = MenuScope.of(context).currentNode?.label; return DragToMoveWrap( - child: Stack( - alignment: Alignment.centerRight, - children: [Row( - children: [ - SizedBox(width: 20,), - RouteBackIndicator(), - Padding( - padding: const EdgeInsets.symmetric(vertical: 10.0), - child: RouterIndicator(), - ), - // Text( - // '$lable', - // style: TextStyle(fontSize: 14), - // ), - Spacer(), - ], - ),WindowButtons()] + child: SizedBox( + height: 36, + child: Stack( + alignment: Alignment.centerRight, + children: [Row( + children: [ + SizedBox(width: 20,), + RouteBackIndicator(), + Padding( + padding: const EdgeInsets.symmetric(vertical: 10.0), + child: RouterIndicator(), + ), + // Text( + // '$lable', + // style: TextStyle(fontSize: 14), + // ), + Spacer(), + ], + ),WindowButtons()] + ), ), ); } diff --git a/packages/components/lib/toly_ui/code_view/code_view.dart b/packages/components/lib/toly_ui/code_view/code_view.dart index ebede29..478fb5c 100644 --- a/packages/components/lib/toly_ui/code_view/code_view.dart +++ b/packages/components/lib/toly_ui/code_view/code_view.dart @@ -18,18 +18,20 @@ class _CodeViewState extends State { @override void initState() { - // TODO: implement initState super.initState(); _loadContent(); } @override Widget build(BuildContext context) { - return SingleChildScrollView( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 20), - child: Material( - child: CodeWidget(code:'${content}', style: HighlighterStyle.fromColors(HighlighterStyle.lightColor),), + return ColoredBox( + color: Colors.white, + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 20,vertical: 10), + child: Material( + child: CodeWidget(code:'${content}', style: HighlighterStyle.fromColors(HighlighterStyle.lightColor),), + ), ), ), ); diff --git a/packages/idraw/lib/components/coordinate_pro.dart b/packages/idraw/lib/components/coordinate_pro.dart index d59eafe..794ad5c 100644 --- a/packages/idraw/lib/components/coordinate_pro.dart +++ b/packages/idraw/lib/components/coordinate_pro.dart @@ -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(); } } - diff --git a/packages/idraw/lib/idraw.dart b/packages/idraw/lib/idraw.dart index 2422f56..291f0f6 100644 --- a/packages/idraw/lib/idraw.dart +++ b/packages/idraw/lib/idraw.dart @@ -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'; diff --git a/packages/idraw/lib/p12/p12.dart b/packages/idraw/lib/p12/p12.dart new file mode 100644 index 0000000..05a8ed1 --- /dev/null +++ b/packages/idraw/lib/p12/p12.dart @@ -0,0 +1 @@ +export 'p12_page.dart'; \ No newline at end of file diff --git a/packages/idraw/lib/p12/p12_page.dart b/packages/idraw/lib/p12/p12_page.dart new file mode 100644 index 0000000..d070ee0 --- /dev/null +++ b/packages/idraw/lib/p12/p12_page.dart @@ -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(), + ], + ); + } +} diff --git a/packages/idraw/lib/p12/s01.dart b/packages/idraw/lib/p12/s01.dart new file mode 100644 index 0000000..064dd38 --- /dev/null +++ b/packages/idraw/lib/p12/s01.dart @@ -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 { + @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; +} diff --git a/packages/idraw/lib/p12/s02.dart b/packages/idraw/lib/p12/s02.dart new file mode 100644 index 0000000..09dc6df --- /dev/null +++ b/packages/idraw/lib/p12/s02.dart @@ -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 { + ValueNotifier _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; + 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; +} \ No newline at end of file diff --git a/packages/idraw/lib/p12/s03.dart b/packages/idraw/lib/p12/s03.dart new file mode 100644 index 0000000..0b07a4b --- /dev/null +++ b/packages/idraw/lib/p12/s03.dart @@ -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 createState() => _PaperState(); +} + +class _PaperState extends State { + 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 { + ValueNotifier _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; + 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; +} diff --git a/packages/idraw/lib/p12/s04.dart b/packages/idraw/lib/p12/s04.dart new file mode 100644 index 0000000..e9d1045 --- /dev/null +++ b/packages/idraw/lib/p12/s04.dart @@ -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 { + ValueNotifier _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 _kRulerColors = [ + // 渐变色 + Color(0xFF1426FB), Color(0xFF6080FB), Color(0xFFBEE0FB), +]; +const List _kRulerColorStops = [0.0, 0.2, 0.8]; + +class _HandlePainter extends CustomPainter { + var _paint = Paint(); + Paint _pointPaint = Paint(); + + final ValueNotifier 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; +} diff --git a/packages/idraw/lib/p13/p13.dart b/packages/idraw/lib/p13/p13.dart new file mode 100644 index 0000000..a23264c --- /dev/null +++ b/packages/idraw/lib/p13/p13.dart @@ -0,0 +1 @@ +export 'p13_page.dart'; \ No newline at end of file diff --git a/packages/idraw/lib/p13/p13_page.dart b/packages/idraw/lib/p13/p13_page.dart new file mode 100644 index 0000000..542da60 --- /dev/null +++ b/packages/idraw/lib/p13/p13_page.dart @@ -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(), + ], + ); + } +} diff --git a/packages/idraw/lib/p13/s01.dart b/packages/idraw/lib/p13/s01.dart new file mode 100644 index 0000000..723fe6e --- /dev/null +++ b/packages/idraw/lib/p13/s01.dart @@ -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 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; +} diff --git a/packages/idraw/lib/p13/s02.dart b/packages/idraw/lib/p13/s02.dart new file mode 100644 index 0000000..4553d4d --- /dev/null +++ b/packages/idraw/lib/p13/s02.dart @@ -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 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; +} diff --git a/packages/idraw/lib/p13/s03.dart b/packages/idraw/lib/p13/s03.dart new file mode 100644 index 0000000..fad3f59 --- /dev/null +++ b/packages/idraw/lib/p13/s03.dart @@ -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 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 repaint; + + PaperPainter(this.repaint) : super(repaint: repaint) { + initPointsWithPolar(); + } + + final List 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; +} diff --git a/packages/idraw/lib/p13/s04.dart b/packages/idraw/lib/p13/s04.dart new file mode 100644 index 0000000..c762e67 --- /dev/null +++ b/packages/idraw/lib/p13/s04.dart @@ -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 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 repaint; + + PaperPainter(this.repaint) : super(repaint: repaint) { + initPointsWithPolar(); + } + + final List 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; +} diff --git a/packages/idraw/lib/p14/p14.dart b/packages/idraw/lib/p14/p14.dart new file mode 100644 index 0000000..c33f2e8 --- /dev/null +++ b/packages/idraw/lib/p14/p14.dart @@ -0,0 +1 @@ +export 'p14_page.dart'; \ No newline at end of file diff --git a/packages/idraw/lib/p14/p14_page.dart b/packages/idraw/lib/p14/p14_page.dart new file mode 100644 index 0000000..cd3d486 --- /dev/null +++ b/packages/idraw/lib/p14/p14_page.dart @@ -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(), + ], + ); + } +} diff --git a/packages/idraw/lib/p14/s01.dart b/packages/idraw/lib/p14/s01.dart new file mode 100644 index 0000000..522cdb9 --- /dev/null +++ b/packages/idraw/lib/p14/s01.dart @@ -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; +} diff --git a/packages/idraw/lib/p14/s02.dart b/packages/idraw/lib/p14/s02.dart new file mode 100644 index 0000000..74c9a0e --- /dev/null +++ b/packages/idraw/lib/p14/s02.dart @@ -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 { + 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 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; +} diff --git a/packages/idraw/lib/p14/s03.dart b/packages/idraw/lib/p14/s03.dart new file mode 100644 index 0000000..288591f --- /dev/null +++ b/packages/idraw/lib/p14/s03.dart @@ -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 { + 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 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; +} \ No newline at end of file diff --git a/packages/idraw/lib/p14/s04.dart b/packages/idraw/lib/p14/s04.dart new file mode 100644 index 0000000..4ba857c --- /dev/null +++ b/packages/idraw/lib/p14/s04.dart @@ -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 { + 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 _initPoints() { + final List 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 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; +} diff --git a/packages/idraw/lib/p14/s05.dart b/packages/idraw/lib/p14/s05.dart new file mode 100644 index 0000000..1fea1c8 --- /dev/null +++ b/packages/idraw/lib/p14/s05.dart @@ -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 points1 = [ + Offset(0, 20), + Offset(40, 40) , + Offset(80, -20), + Offset(120, -40), + Offset(160, -80), + Offset(200, -20), + Offset(240, -40), + ]; + List points2 = [ + Offset(0, 0), + Offset(40, -20) , + Offset(80, -40), + Offset(120, -80), + Offset(160, -40), + Offset(200, 20), + Offset(240, 40), + ]; + List 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 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; +} diff --git a/packages/idraw/lib/p14/touch_info.dart b/packages/idraw/lib/p14/touch_info.dart new file mode 100644 index 0000000..b24e384 --- /dev/null +++ b/packages/idraw/lib/p14/touch_info.dart @@ -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 _points = []; + int _selectIndex = -1; + + void setPoints(List points) { + _points = points; + } + + + int get selectIndex => _selectIndex; + + List 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]; +} diff --git a/packages/idraw/lib/p15/p15.dart b/packages/idraw/lib/p15/p15.dart new file mode 100644 index 0000000..1e6ba45 --- /dev/null +++ b/packages/idraw/lib/p15/p15.dart @@ -0,0 +1 @@ +export 'p15_page.dart'; \ No newline at end of file diff --git a/packages/idraw/lib/p15/p15_page.dart b/packages/idraw/lib/p15/p15_page.dart new file mode 100644 index 0000000..8a40af0 --- /dev/null +++ b/packages/idraw/lib/p15/p15_page.dart @@ -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(), + ], + ); + } +} diff --git a/packages/idraw/lib/p15/s01.dart b/packages/idraw/lib/p15/s01.dart new file mode 100644 index 0000000..3cd0888 --- /dev/null +++ b/packages/idraw/lib/p15/s01.dart @@ -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; +} \ No newline at end of file diff --git a/packages/idraw/lib/p15/s02.dart b/packages/idraw/lib/p15/s02.dart new file mode 100644 index 0000000..d1da466 --- /dev/null +++ b/packages/idraw/lib/p15/s02.dart @@ -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; +} \ No newline at end of file diff --git a/packages/idraw/lib/p15/s03.dart b/packages/idraw/lib/p15/s03.dart new file mode 100644 index 0000000..440ebf8 --- /dev/null +++ b/packages/idraw/lib/p15/s03.dart @@ -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 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 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; +} \ No newline at end of file diff --git a/packages/idraw/lib/p15/s04.dart b/packages/idraw/lib/p15/s04.dart new file mode 100644 index 0000000..b580bb0 --- /dev/null +++ b/packages/idraw/lib/p15/s04.dart @@ -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 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 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; +} \ No newline at end of file diff --git a/packages/idraw/lib/p15/s05.dart b/packages/idraw/lib/p15/s05.dart new file mode 100644 index 0000000..ca30866 --- /dev/null +++ b/packages/idraw/lib/p15/s05.dart @@ -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 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 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; +} \ No newline at end of file diff --git a/packages/idraw/lib/p15/s06.dart b/packages/idraw/lib/p15/s06.dart new file mode 100644 index 0000000..b22038a --- /dev/null +++ b/packages/idraw/lib/p15/s06.dart @@ -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 + 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 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; +} + diff --git a/packages/idraw/lib/p15/touch_info.dart b/packages/idraw/lib/p15/touch_info.dart new file mode 100644 index 0000000..b24e384 --- /dev/null +++ b/packages/idraw/lib/p15/touch_info.dart @@ -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 _points = []; + int _selectIndex = -1; + + void setPoints(List points) { + _points = points; + } + + + int get selectIndex => _selectIndex; + + List 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]; +} diff --git a/packages/idraw/lib/p16/p16.dart b/packages/idraw/lib/p16/p16.dart new file mode 100644 index 0000000..e4d25ef --- /dev/null +++ b/packages/idraw/lib/p16/p16.dart @@ -0,0 +1 @@ +export 'p16_page.dart'; \ No newline at end of file diff --git a/packages/idraw/lib/p16/p16_page.dart b/packages/idraw/lib/p16/p16_page.dart new file mode 100644 index 0000000..85e81f1 --- /dev/null +++ b/packages/idraw/lib/p16/p16_page.dart @@ -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(), + ], + ); + } +} diff --git a/packages/idraw/lib/p16/s01.dart b/packages/idraw/lib/p16/s01.dart new file mode 100644 index 0000000..40c25a2 --- /dev/null +++ b/packages/idraw/lib/p16/s01.dart @@ -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 yData = [88, 98, 70, 80, 100, 75]; + final List xData = ["7月", "8月", "9月", "10月", "11月", "12月"]; + + // final List 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; +} diff --git a/packages/idraw/lib/p16/s02.dart b/packages/idraw/lib/p16/s02.dart new file mode 100644 index 0000000..f38899b --- /dev/null +++ b/packages/idraw/lib/p16/s02.dart @@ -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 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 yData = [88, 98, 70, 80, 100, 75]; + final List xData = ["7月", "8月", "9月", "10月", "11月", "12月"]; + + // final List xData = [ "语文","数学", "英语", "物理", "化学", "生物"]; + + final Animation 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; +} diff --git a/packages/idraw/lib/p16/s03.dart b/packages/idraw/lib/p16/s03.dart new file mode 100644 index 0000000..45bbdf9 --- /dev/null +++ b/packages/idraw/lib/p16/s03.dart @@ -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 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 yData = [88, 98, 70, 80, 100, 75]; + final List xData = ["7月", "8月", "9月", "10月", "11月", "12月"]; + + // final List xData = [ "语文","数学", "英语", "物理", "化学", "生物"]; + + final Animation 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 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; + +} diff --git a/packages/idraw/lib/p16/s04.dart b/packages/idraw/lib/p16/s04.dart new file mode 100644 index 0000000..ef99993 --- /dev/null +++ b/packages/idraw/lib/p16/s04.dart @@ -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 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 yData = [88, 98, 70, 80, 100, 75]; + final List xData = ["7月", "8月", "9月", "10月", "11月", "12月"]; + + // final List xData = [ "语文","数学", "英语", "物理", "化学", "生物"]; + + final Animation 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 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 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; + +} diff --git a/packages/idraw/lib/p16/s05.dart b/packages/idraw/lib/p16/s05.dart new file mode 100644 index 0000000..9479691 --- /dev/null +++ b/packages/idraw/lib/p16/s05.dart @@ -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 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 yData = [88, 98, 70, 80, 100, 75]; + final List xData = ["7月", "8月", "9月", "10月", "11月", "12月"]; + + // final List xData = [ "语文","数学", "英语", "物理", "化学", "生物"]; + + final Animation 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 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; + +} diff --git a/packages/idraw/lib/p16/s06.dart b/packages/idraw/lib/p16/s06.dart new file mode 100644 index 0000000..0716a58 --- /dev/null +++ b/packages/idraw/lib/p16/s06.dart @@ -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 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 yData = [0.12, 0.25, 0.1, 0.18, 0.15, 0.2]; + final List colors = [ + Colors.red, + Colors.orangeAccent, + Colors.blue, + Colors.green, + Colors.purple, + Colors.pink + ]; + final List xData = ["学习资料", "伙食费", "话费", "游玩", "游戏", "其他"]; + + final Animation 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 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; +} diff --git a/packages/idraw/lib/p17/p17.dart b/packages/idraw/lib/p17/p17.dart new file mode 100644 index 0000000..460b79d --- /dev/null +++ b/packages/idraw/lib/p17/p17.dart @@ -0,0 +1 @@ +export 'p17_page.dart'; \ No newline at end of file diff --git a/packages/idraw/lib/p17/p17_page.dart b/packages/idraw/lib/p17/p17_page.dart new file mode 100644 index 0000000..790bb34 --- /dev/null +++ b/packages/idraw/lib/p17/p17_page.dart @@ -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(), + ], + ); + } +} diff --git a/packages/idraw/lib/p17/s01.dart b/packages/idraw/lib/p17/s01.dart new file mode 100644 index 0000000..c2f01f5 --- /dev/null +++ b/packages/idraw/lib/p17/s01.dart @@ -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 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 _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 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; +} diff --git a/packages/idraw/lib/p17/s02.dart b/packages/idraw/lib/p17/s02.dart new file mode 100644 index 0000000..78888c1 --- /dev/null +++ b/packages/idraw/lib/p17/s02.dart @@ -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 { + final String url = 'https://geo.datav.aliyun.com/areas_v2/bound/100000_full.json'; //全国点位详细信息 + + //请求点位信息地址 + Future 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 _future; + + @override + void initState() { + super.initState(); + _future = getMapRoot(); + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + 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 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> 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; + + MapRoot({ + required this.type, + required this.name, + required this.features, + }); + + static MapRoot? fromJson(jsonRes) { + if (jsonRes == null) return null; + + List? 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 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 toJson() => { + 'type': type, + 'properties': properties, + 'geometry': geometry, + }; + + @override + String toString() { + return json.encode(this); + } +} + +class Properties { + String? adcode; + String? name; + List? center; + List? centroid; + int? childrenNum; + String?level; + Parent? parent; + int? subFeatureIndex; + List? 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? center = jsonRes['center'] is List ? [] : null; + if (center != null) { + for (var item in jsonRes['center']) { + if (item != null) { + center.add(item); + } + } + } + + List? centroid = jsonRes['centroid'] is List ? [] : null; + if (centroid != null) { + for (var item in jsonRes['centroid']) { + if (item != null) { + centroid.add(item); + } + } + } + + List? 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 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 toJson() => { + 'adcode': adcode, + }; + + @override + String toString() { + return json.encode(this); + } +} + +class Geometry { + String type; + List>> coordinates; + + Geometry({ + required this.type, + required this.coordinates, + }); + + static Geometry? fromJson(jsonRes) { + if (jsonRes == null) return null; + + List>>? 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> lever0=[]; + if (level0 != null) { + List 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> items1 = []; + for (var item1 in level0 is List ? level0 : []) { + if (item1 != null) { + List 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 toJson() => { + 'type': type, + 'coordinates': coordinates, + }; + + @override + String toString() { + return json.encode(this); + } +} diff --git a/packages/idraw/lib/p18/p18.dart b/packages/idraw/lib/p18/p18.dart new file mode 100644 index 0000000..6762f03 --- /dev/null +++ b/packages/idraw/lib/p18/p18.dart @@ -0,0 +1 @@ +export 'p18_page.dart'; \ No newline at end of file diff --git a/packages/idraw/lib/p18/p18_page.dart b/packages/idraw/lib/p18/p18_page.dart new file mode 100644 index 0000000..e7f6df5 --- /dev/null +++ b/packages/idraw/lib/p18/p18_page.dart @@ -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(), + ], + ); + } +} diff --git a/packages/idraw/lib/p18/s01.dart b/packages/idraw/lib/p18/s01.dart new file mode 100644 index 0000000..373c285 --- /dev/null +++ b/packages/idraw/lib/p18/s01.dart @@ -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 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 particles = []; + + Size size; + + ParticleManage({this.size = Size.zero}); + + void setParticles(List 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, + }); +} diff --git a/packages/idraw/lib/p18/s02.dart b/packages/idraw/lib/p18/s02.dart new file mode 100644 index 0000000..7c756e0 --- /dev/null +++ b/packages/idraw/lib/p18/s02.dart @@ -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 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 particles = []; + + Size size; + + ParticleManage({this.size = Size.zero}); + + void setParticles(List 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, + }); +} diff --git a/packages/idraw/lib/p18/s03.dart b/packages/idraw/lib/p18/s03.dart new file mode 100644 index 0000000..8bb8db5 --- /dev/null +++ b/packages/idraw/lib/p18/s03.dart @@ -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 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 particles = []; + + Size size; + + ParticleManage({this.size = Size.zero}); + + void setParticles(List 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, + }); +} diff --git a/packages/idraw/lib/p18/s04.dart b/packages/idraw/lib/p18/s04.dart new file mode 100644 index 0000000..14e3bd5 --- /dev/null +++ b/packages/idraw/lib/p18/s04.dart @@ -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 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 particles = []; + + Size size; + + ParticleManage({this.size = Size.zero}); + + void setParticles(List 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, + }); +} diff --git a/packages/idraw/lib/p18/s05.dart b/packages/idraw/lib/p18/s05.dart new file mode 100644 index 0000000..4c253ac --- /dev/null +++ b/packages/idraw/lib/p18/s05.dart @@ -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 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 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 particles = []; + + Size size; + + ParticleManage({this.size = Size.zero}); + + void setParticles(List 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, + }); +} diff --git a/packages/idraw/pubspec.yaml b/packages/idraw/pubspec.yaml index 3d2b1c8..4d16f45 100644 --- a/packages/idraw/pubspec.yaml +++ b/packages/idraw/pubspec.yaml @@ -11,6 +11,7 @@ dependencies: flutter: sdk: flutter image: ^4.1.3 + dio: ^5.4.0 components: path: ../components dev_dependencies: diff --git a/pubspec.lock b/pubspec.lock index af03a45..7cbdb5c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -80,6 +80,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.0.5" + dio: + dependency: transitive + description: + name: dio + sha256: "797e1e341c3dd2f69f2dad42564a6feff3bfb87187d05abb93b9609e6f1645c3" + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.4.0" fake_async: dependency: transitive description: @@ -119,6 +127,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "12.1.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.2" idraw: dependency: "direct main" description: @@ -270,10 +286,11 @@ packages: toly_menu: dependency: "direct main" description: - path: "E:\\Projects\\Flutter\\packages\\toly_menu" - relative: false - source: path - version: "0.0.2" + name: toly_menu + sha256: "0dbc80a3e7d2e18833a914e76411a03c3feff1f4baffbd382b180e8a0051b1e7" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.3" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 98bb146..7be13d3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -68,6 +68,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - assets/images/ + - assets/palettes.json - assets/draw/p01/ - assets/draw/p02/ - assets/draw/p03/