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