white_board.dart 5.4 KB

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