canvas.dart 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. import 'dart:ui' as ui;
  2. import 'package:fis_measure/values/colors.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:path_drawing/path_drawing.dart';
  5. extension MeasureCanvasExt on Canvas {
  6. static String? _fontFamily;
  7. /// 设置字体
  8. static void setFontFamily(String? val) {
  9. _fontFamily = val;
  10. }
  11. /// 绘制文本
  12. ///
  13. /// [text] 文本内容
  14. ///
  15. /// [offset] 位置
  16. ///
  17. /// [style] 文字样式
  18. void drawText(
  19. String text,
  20. ui.Offset offset, {
  21. TextStyle? style,
  22. }) {
  23. var displayStyle = style;
  24. if (displayStyle != null) {
  25. if (displayStyle.fontFamily == null) {
  26. displayStyle = displayStyle.copyWith(fontFamily: _fontFamily);
  27. }
  28. }
  29. var textPainter = TextPainter(
  30. text: TextSpan(
  31. text: text,
  32. style: displayStyle,
  33. ),
  34. textAlign: ui.TextAlign.start,
  35. textDirection: TextDirection.ltr,
  36. );
  37. textPainter.layout();
  38. textPainter.paint(this, offset);
  39. }
  40. /// 绘制文本段落
  41. ///
  42. /// [text] 文本内容
  43. ///
  44. /// [offset] 位置
  45. ///
  46. /// [width] 限制长度
  47. ///
  48. /// [style] 文字样式
  49. ///
  50. /// [maxLines] 最大行数
  51. void drawTextParagraph(
  52. String text,
  53. ui.Offset offset,
  54. double width, {
  55. ui.TextStyle? style,
  56. int maxLines = 1,
  57. }) {
  58. var pb = ui.ParagraphBuilder(
  59. ui.ParagraphStyle(
  60. textAlign: TextAlign.left,
  61. textDirection: ui.TextDirection.ltr,
  62. maxLines: maxLines,
  63. ),
  64. );
  65. if (style != null) {
  66. pb.pushStyle(style);
  67. }
  68. pb.addText(text);
  69. final paragraph = pb.build()..layout(ui.ParagraphConstraints(width: width));
  70. drawParagraph(paragraph, offset);
  71. }
  72. /// 画虚线
  73. ///
  74. /// [p1] 第一个点
  75. ///
  76. /// [p2] 第二个点
  77. ///
  78. /// [dashWidth] 虚线点长度
  79. ///
  80. /// [spaceWidth] 虚线点间隔长度
  81. ///
  82. /// [paint] 画笔
  83. void drawDashLine(
  84. Offset p1,
  85. Offset p2,
  86. double dashWidth,
  87. double spaceWidth,
  88. Paint paint,
  89. ) {
  90. final path = Path()
  91. ..moveTo(p1.dx, p1.dy)
  92. ..lineTo(p2.dx, p2.dy);
  93. drawPath(
  94. dashPath(
  95. path,
  96. dashArray: CircularIntervalList<double>([dashWidth, spaceWidth]),
  97. ),
  98. paint,
  99. );
  100. }
  101. /// 画虚线贝塞尔曲线
  102. /// [p1] 第一个点
  103. /// [p2] 第二个点
  104. /// [dashWidth] 虚线点长度
  105. /// [spaceWidth] 虚线点间隔长度
  106. /// [paint] 画笔
  107. /// [c1] 第一个控制点
  108. /// [c2] 第二个控制点
  109. void drawDashBezierLine(
  110. Offset p1,
  111. Offset p2,
  112. double dashWidth,
  113. double spaceWidth,
  114. Paint paint, {
  115. Offset? c1,
  116. Offset? c2,
  117. }) {
  118. final path = Path()
  119. ..moveTo(p1.dx, p1.dy)
  120. ..cubicTo(
  121. c1?.dx ?? p1.dx,
  122. c1?.dy ?? p1.dy,
  123. c2?.dx ?? p2.dx,
  124. c2?.dy ?? p2.dy,
  125. p2.dx,
  126. p2.dy,
  127. );
  128. drawPath(
  129. dashPath(
  130. path,
  131. dashArray: CircularIntervalList<double>([dashWidth, spaceWidth]),
  132. ),
  133. paint,
  134. );
  135. }
  136. /// 画虚线框
  137. ///
  138. /// [p1] 起始顶点
  139. ///
  140. /// [p2] 结束顶点
  141. ///
  142. /// [dashWidth] 虚线点长度
  143. ///
  144. /// [spaceWidth] 虚线点间隔长度
  145. ///
  146. /// [paint] 画笔
  147. void drawDashRect(
  148. Offset p1,
  149. Offset p2,
  150. double dashWidth,
  151. double spaceWidth,
  152. Paint paint,
  153. ) {
  154. final path = Path()
  155. ..moveTo(p1.dx, p1.dy)
  156. ..lineTo(p2.dx, p1.dy)
  157. ..lineTo(p2.dx, p2.dy)
  158. ..lineTo(p1.dx, p2.dy)
  159. ..close();
  160. drawPath(
  161. dashPath(
  162. path,
  163. dashArray: CircularIntervalList<double>([dashWidth, spaceWidth]),
  164. ),
  165. paint,
  166. );
  167. }
  168. /// 画点集连线
  169. /// [points] 点集
  170. /// [paint] 画笔
  171. void drawPointsLine(List<Offset> points, Paint paint) {
  172. final path = Path();
  173. for (var i = 0; i < points.length; i++) {
  174. if (i == 0) {
  175. path.moveTo(points[i].dx, points[i].dy);
  176. } else {
  177. path.lineTo(points[i].dx, points[i].dy);
  178. }
  179. }
  180. drawPath(path, paint);
  181. }
  182. /// 画点集虚线连线
  183. /// [points] 点集
  184. /// [dashWidth] 虚线点长度
  185. /// [spaceWidth] 虚线点间隔长度
  186. /// [paint] 画笔
  187. /// [close] 是否闭合
  188. void drawDashPointsLine(
  189. List<Offset> points,
  190. double dashWidth,
  191. double spaceWidth,
  192. Paint paint, {
  193. bool close = false,
  194. }) {
  195. final path = Path();
  196. for (var i = 0; i < points.length; i++) {
  197. if (i == 0) {
  198. path.moveTo(points[i].dx, points[i].dy);
  199. } else {
  200. path.lineTo(points[i].dx, points[i].dy);
  201. }
  202. }
  203. if (close) {
  204. path.close();
  205. }
  206. drawPath(
  207. dashPath(
  208. path,
  209. dashArray: CircularIntervalList<double>([dashWidth, spaceWidth]),
  210. ),
  211. paint,
  212. );
  213. }
  214. static final Paint _vertexPaint = Paint()
  215. ..strokeWidth = 1
  216. ..style = PaintingStyle.stroke
  217. ..isAntiAlias = true;
  218. /// 画顶点
  219. ///
  220. /// [offset] 位置
  221. ///
  222. /// [size] 尺寸
  223. ///
  224. /// [active] 是否活动
  225. void drawVertex(
  226. Offset offset,
  227. double size, {
  228. bool active = false,
  229. }) {
  230. final radius = size / 2.0;
  231. double x = offset.dx, y = offset.dy;
  232. save();
  233. final path = Path();
  234. // top_left -> bottom_right
  235. path.moveTo(x - radius, y - radius);
  236. path.lineTo(x + radius, y + radius);
  237. // top_right -> bottom_left
  238. path.moveTo(x + radius, y - radius);
  239. path.lineTo(x - radius, y + radius);
  240. _vertexPaint.color =
  241. active ? MeasureColors.ActiveCaliper : MeasureColors.Primary;
  242. drawPath(path, _vertexPaint);
  243. restore();
  244. }
  245. static final Paint _markPaint = Paint()
  246. ..strokeWidth = 1
  247. ..style = PaintingStyle.stroke
  248. ..isAntiAlias = false;
  249. ///绘制短横标记
  250. ///ifHorizontal true:横向标记 false:纵向标记
  251. void drawMark(
  252. Offset offset,
  253. double size, {
  254. bool active = false,
  255. bool ifHorizontal = true,
  256. }) {
  257. final radius = size / 3.0;
  258. double x = offset.dx, y = offset.dy;
  259. save();
  260. final path = Path();
  261. // top_left -> bottom_right
  262. if (ifHorizontal) {
  263. path.moveTo(x - radius, y);
  264. path.lineTo(x + radius, y);
  265. } else {
  266. path.moveTo(x, y - radius);
  267. path.lineTo(x, y + radius);
  268. }
  269. _markPaint.color =
  270. active ? MeasureColors.ActiveCaliper : MeasureColors.Primary;
  271. drawPath(path, _markPaint);
  272. restore();
  273. }
  274. }