white_board.dart 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. import 'dart:convert';
  2. import 'package:fis_common/event/event_type.dart';
  3. import 'package:fis_lib_business_components/components/white_board/utils.dart';
  4. import 'package:fis_lib_business_components/components/white_board/structure.dart';
  5. import 'package:fis_lib_business_components/components/white_board/white_board_painter.dart';
  6. import 'package:fis_ui/index.dart';
  7. import 'package:flutter/material.dart';
  8. class FWhiteBoard extends StatefulWidget implements FWidget {
  9. const FWhiteBoard({
  10. key,
  11. required this.initData,
  12. required this.userId,
  13. required this.patientColor,
  14. required this.paintType,
  15. required this.sendData,
  16. required this.onReceiveData,
  17. required this.onClearCanavs,
  18. });
  19. /// 初始画板副本数据
  20. final List<String> initData;
  21. /// 用户id
  22. final String userId;
  23. /// 用户颜色
  24. final Color patientColor;
  25. /// 当前绘制模式
  26. final PaintType paintType;
  27. /// 发送数据(接 JsonRPC)
  28. final void Function(String data) sendData;
  29. /// 接收数据(接 WebSocket)
  30. final FEventHandler<String> onReceiveData;
  31. /// 画布清除事件
  32. final FEventHandler<String> onClearCanavs;
  33. @override
  34. State<FWhiteBoard> createState() => _FWhiteBoardState();
  35. }
  36. class _FWhiteBoardState extends State<FWhiteBoard> {
  37. /// 画布尺寸
  38. late double canvasWidth = 0.0;
  39. late double canvasHeight = 0.0;
  40. /// 当前用户的画笔
  41. WhiteBoardPen myPen = WhiteBoardPen();
  42. /// 当前用户的画笔颜色
  43. Color get myPenColor => widget.patientColor;
  44. /// 固定的画笔粗细
  45. static const double strokeWidth = 3.0;
  46. /// 异步绘制队列
  47. List<String> _asyncDrawQueue = [];
  48. /// 异步绘制锁
  49. bool _asyncDrawLock = false;
  50. @override
  51. void initState() {
  52. super.initState();
  53. widget.onReceiveData.addListener((sender, data) {
  54. _onReceiveDrawData(data);
  55. });
  56. widget.onClearCanavs.addListener((sender, userId) {
  57. _clearUserLines(userId);
  58. });
  59. /// 加载完后一帧绘制初始数据
  60. WidgetsBinding.instance.addPostFrameCallback((_) {
  61. _paintInitData();
  62. });
  63. }
  64. @override
  65. Widget build(BuildContext context) {
  66. canvasWidth = MediaQuery.of(context).size.width;
  67. canvasHeight = MediaQuery.of(context).size.height;
  68. return MouseRegion(
  69. cursor: SystemMouseCursors.click,
  70. child: GestureDetector(
  71. onPanDown: _onPanDown,
  72. onPanUpdate: _onPanUpdate,
  73. onPanEnd: _onPanEnd,
  74. onPanCancel: _onPanCancel,
  75. onDoubleTap: myPen.clear,
  76. child: CustomPaint(
  77. size: MediaQuery.of(context).size,
  78. painter: WhiteBoardPainter(
  79. pen: myPen,
  80. width: canvasWidth,
  81. height: canvasHeight,
  82. ),
  83. ),
  84. ),
  85. );
  86. }
  87. /// 按下时,生成新的线实体
  88. void _onPanDown(DragDownDetails details) {
  89. Line line = Line(
  90. color: myPenColor,
  91. strokeWidth: strokeWidth,
  92. paintType: widget.paintType,
  93. userId: widget.userId,
  94. );
  95. myPen.pushLine(line);
  96. }
  97. /// 拖动时,生成新的点实体,加入到当前线实体中
  98. void _onPanUpdate(DragUpdateDetails details) {
  99. myPen.pushPoint(Point.fromOffset(
  100. details.localPosition,
  101. canvasWidth,
  102. canvasHeight,
  103. ));
  104. }
  105. /// 抬起时,发送数据
  106. void _onPanEnd(DragEndDetails details) {
  107. _sentDrawAction();
  108. myPen.doneLine();
  109. }
  110. /// 绘制初始数据
  111. void _paintInitData() {
  112. for (int i = 0; i < widget.initData.length; i++) {
  113. _onReceiveDrawDataImmediately(widget.initData[i]);
  114. }
  115. }
  116. /// 发送绘制指令
  117. void _sentDrawAction() {
  118. List<List<double>> pointsList = [];
  119. for (int i = 0; i < myPen.activeLine.points.length; i++) {
  120. pointsList.add(myPen.activeLine.points[i].toList());
  121. }
  122. print(widget.patientColor.value.toString());
  123. widget.sendData(jsonEncode({
  124. "u_Id": widget.userId, // 用户id
  125. "l_Id": "", // 线id
  126. "color": widget.patientColor.value.toString(), // 线的颜色
  127. "points": PointsUtil.compressPointsList(pointsList),
  128. }));
  129. }
  130. /// 接收绘制数据【如果存在数据正在绘制,其他的加入绘制队列,等待当前绘制完成继续绘制】
  131. void _onReceiveDrawData(String jsonData) async {
  132. if (_asyncDrawLock) {
  133. _asyncDrawQueue.add(jsonData);
  134. return;
  135. }
  136. _asyncDrawLock = true;
  137. var data = jsonDecode(jsonData);
  138. /// 清除时走的逻辑
  139. if (data["isClear"] == "true") {
  140. _clearUserLines(data["u_Id"]);
  141. _asyncDrawLock = false;
  142. return;
  143. }
  144. List<dynamic> pointsList = PointsUtil.decompressPointsList(data["points"]);
  145. Line line = Line(
  146. color: Color(int.parse(data["color"])),
  147. strokeWidth: strokeWidth,
  148. userId: data["u_Id"],
  149. );
  150. myPen.pushLine(line);
  151. for (int i = 0; i < pointsList.length; i++) {
  152. myPen.pushPoint(Point.fromList(
  153. pointsList[i],
  154. ));
  155. await Future.delayed(const Duration(milliseconds: 2));
  156. }
  157. myPen.doneLine();
  158. _asyncDrawLock = false;
  159. /// 判断如果队列存在数据,继续绘制
  160. if (_asyncDrawQueue.isNotEmpty) {
  161. _onReceiveDrawData(_asyncDrawQueue.removeAt(0));
  162. }
  163. }
  164. /// 接收绘制数据立即绘制,无 Future.delayed
  165. void _onReceiveDrawDataImmediately(String jsonData) {
  166. var data = jsonDecode(jsonData);
  167. List<dynamic> pointsList = PointsUtil.decompressPointsList(data["points"]);
  168. Line line = Line(
  169. color: ColorUtil.generateColor(data["u_Id"]),
  170. strokeWidth: strokeWidth,
  171. userId: data["u_Id"],
  172. );
  173. myPen.pushLine(line);
  174. for (int i = 0; i < pointsList.length; i++) {
  175. myPen.pushPoint(Point.fromList(
  176. pointsList[i],
  177. ));
  178. }
  179. myPen.doneLine();
  180. }
  181. void _clearUserLines(String userId) {
  182. myPen.clearCurrectUserLines(userId);
  183. }
  184. void _onPanCancel() {
  185. myPen.removeEmpty();
  186. }
  187. }