{"id":19273016,"url":"https://github.com/fluttercandies/flutter_drawing_board","last_synced_at":"2025-10-10T17:10:12.224Z","repository":{"id":40321722,"uuid":"354828888","full_name":"fluttercandies/flutter_drawing_board","owner":"fluttercandies","description":"A new Flutter package of drawing board","archived":false,"fork":false,"pushed_at":"2025-06-11T02:13:18.000Z","size":3983,"stargazers_count":219,"open_issues_count":10,"forks_count":82,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-06-11T03:29:42.220Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fluttercandies.png","metadata":{"files":{"readme":"README-zh-CN.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-04-05T12:35:04.000Z","updated_at":"2025-06-11T02:13:22.000Z","dependencies_parsed_at":"2024-03-05T03:28:30.939Z","dependency_job_id":"0db22576-c76b-429c-8c07-cae0a3f5e2c6","html_url":"https://github.com/fluttercandies/flutter_drawing_board","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fluttercandies/flutter_drawing_board","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Fflutter_drawing_board","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Fflutter_drawing_board/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Fflutter_drawing_board/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Fflutter_drawing_board/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fluttercandies","download_url":"https://codeload.github.com/fluttercandies/flutter_drawing_board/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Fflutter_drawing_board/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279004815,"owners_count":26083783,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T20:40:03.485Z","updated_at":"2025-10-10T17:10:12.205Z","avatar_url":"https://github.com/fluttercandies.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Flutter Drawing Board\n\nA Flutter package of drawing board.  \nFlutter 画板\n\n[English](./README.md) | [中文](./README-zh-CN.md)\n\n[![pub package](https://img.shields.io/pub/v/flutter_drawing_board?logo=dart\u0026label=stable\u0026style=flat-square)](https://pub.dev/packages/flutter_drawing_board)\n[![GitHub stars](https://img.shields.io/github/stars/fluttercandies/flutter_drawing_board?logo=github\u0026style=flat-square)](https://github.com/fluttercandies/flutter_drawing_board/stargazers)\n[![GitHub forks](https://img.shields.io/github/forks/fluttercandies/flutter_drawing_board?logo=github\u0026style=flat-square)](https://github.com/fluttercandies/flutter_drawing_board/network/members)\n[![CodeFactor](https://img.shields.io/codefactor/grade/github/fluttercandies/flutter_drawing_board?logo=codefactor\u0026logoColor=%23ffffff\u0026style=flat-square)](https://www.codefactor.io/repository/github/fluttercandies/flutter_drawing_board)\n\u003ca target=\"_blank\" href=\"https://jq.qq.com/?_wv=1027\u0026k=5bcc0gy\"\u003e\u003cimg border=\"0\" src=\"https://pub.idqqimg.com/wpa/images/group.png\" alt=\"FlutterCandies\" title=\"FlutterCandies\"\u003e\u003c/a\u003e\n\n\u003e `0.3.0` 后存在破坏性更新，移除了文本添加，文本的添加与编辑请移步 [![pub package](https://img.shields.io/pub/v/stack_board?logo=dart\u0026label=stack_board\u0026style=flat-square)](https://pub.dev/packages/stack_board)  \n\n### 特性\n* 基础绘制\n* 自定义绘制\n* 画布旋转、多指移动缩放\n* 撤销、重做\n\n### 预览\n\n* 在线体验:[Demo](https://xsilencex.github.io/flutter_drawing_board_demo/)  \n\n* 基础功能预览  \n\n\u003cimg src=\"https://raw.githubusercontent.com/xSILENCEx/flutter_drawing_board/master/preview/pre1.gif\" height=300\u003e\n\u003cimg src=\"https://raw.githubusercontent.com/xSILENCEx/flutter_drawing_board/master/preview/pre2.gif\" height=300\u003e\n\u003cimg src=\"https://raw.githubusercontent.com/xSILENCEx/flutter_drawing_board/master/preview/pre3.gif\" height=300\u003e\n\u003cimg src=\"https://raw.githubusercontent.com/xSILENCEx/flutter_drawing_board/master/preview/pre4.gif\" height=300\u003e\n\u003cimg src=\"https://raw.githubusercontent.com/xSILENCEx/flutter_drawing_board/master/preview/pre5.gif\" height=300\u003e\n\u003cimg src=\"https://raw.githubusercontent.com/xSILENCEx/flutter_drawing_board/master/preview/pre6.gif\" height=300\u003e  \n\n\u0026nbsp;\n\n### 使用方法  \n\n* 创建\n\n```dart\n//simple example\n\nimport 'package:flutter_drawing_board/flutter_drawing_board.dart';\n\nDrawingBoard(\n  background: Container(width: 400, height: 400, color: Colors.white),\n  showDefaultActions: true, /// 开启默认操作选项\n  showDefaultTools: true,   /// 开启默认工具栏\n),\n```\n\n* 通过 DrawingController.getImageData 获取画板数据\n\n```dart\nimport 'package:flutter_drawing_board/flutter_drawing_board.dart';\n\nfinal DrawingController _drawingController = DrawingController();\n\nDrawingBoard(\n  controller: _drawingController,\n  background: Container(width: 400, height: 400, color: Colors.white),\n  showDefaultActions: true,\n  showDefaultTools: true,\n),\n\n/// 获取画板数据\nFuture\u003cvoid\u003e _getImageData() async {\n  print((await _drawingController.getImageData()).buffer.asInt8List());\n}\n```\n\n* 通过 DrawingController.getJsonList 获取内容 Json\n\n```dart\nimport 'package:flutter_drawing_board/flutter_drawing_board.dart';\n\nfinal DrawingController _drawingController = DrawingController();\n\nDrawingBoard(\n  controller: _drawingController,\n  background: Container(width: 400, height: 400, color: Colors.white),\n  showDefaultActions: true,\n  showDefaultTools: true,\n),\n\n/// 获取内容 Json\nFuture\u003cvoid\u003e _getJsonList() async {\n  print(const JsonEncoder.withIndent('  ').convert(_drawingController.getJsonList()));\n}\n```\n\u003cdetails\u003e\n  \u003csummary\u003eView Json\u003c/summary\u003e\n\n```json\n[\n  {\n    \"type\": \"StraightLine\",\n    \"startPoint\": {\n      \"dx\": 114.5670061088183,\n      \"dy\": 117.50547159585983\n    },\n    \"endPoint\": {\n      \"dx\": 252.9362813512929,\n      \"dy\": 254.91849554320638\n    },\n    \"paint\": {\n      \"blendMode\": 3,\n      \"color\": 4294198070,\n      \"filterQuality\": 3,\n      \"invertColors\": false,\n      \"isAntiAlias\": false,\n      \"strokeCap\": 1,\n      \"strokeJoin\": 1,\n      \"strokeWidth\": 4.0,\n      \"style\": 1\n    }\n  },\n  {\n    \"type\": \"StraightLine\",\n    \"startPoint\": {\n      \"dx\": 226.6379349225167,\n      \"dy\": 152.11430225316613\n    },\n    \"endPoint\": {\n      \"dx\": 135.67632523940733,\n      \"dy\": 210.35948249064901\n    },\n    \"paint\": {\n      \"blendMode\": 3,\n      \"color\": 4294198070,\n      \"filterQuality\": 3,\n      \"invertColors\": false,\n      \"isAntiAlias\": false,\n      \"strokeCap\": 1,\n      \"strokeJoin\": 1,\n      \"strokeWidth\": 4.0,\n      \"style\": 1\n    }\n  }\n]\n```\n\u003c/details\u003e\n\n\n* 通过 `Json` 添加绘制内容\n\n```dart\nconst Map\u003cString, dynamic\u003e _testLine1 = \u003cString, dynamic\u003e{\n  'type': 'StraightLine',\n  'startPoint': \u003cString, dynamic\u003e{'dx': 68.94337550070736, 'dy': 62.05980083656557},\n  'endPoint': \u003cString, dynamic\u003e{'dx': 277.1373386828114, 'dy': 277.32029957032194},\n  'paint': \u003cString, dynamic\u003e{\n    'blendMode': 3,\n    'color': 4294198070,\n    'filterQuality': 3,\n    'invertColors': false,\n    'isAntiAlias': false,\n    'strokeCap': 1,\n    'strokeJoin': 1,\n    'strokeWidth': 4.0,\n    'style': 1\n  }\n};\n\nconst Map\u003cString, dynamic\u003e _testLine2 = \u003cString, dynamic\u003e{\n  'type': 'StraightLine',\n  'startPoint': \u003cString, dynamic\u003e{'dx': 106.35164817830423, 'dy': 255.9575653134524},\n  'endPoint': \u003cString, dynamic\u003e{'dx': 292.76034659254094, 'dy': 92.125586665872},\n  'paint': \u003cString, dynamic\u003e{\n    'blendMode': 3,\n    'color': 4294198070,\n    'filterQuality': 3,\n    'invertColors': false,\n    'isAntiAlias': false,\n    'strokeCap': 1,\n    'strokeJoin': 1,\n    'strokeWidth': 4.0,\n    'style': 1\n  }\n};\n\n  ...\n\n/// 添加Json测试内容\nvoid _addTestLine() {\n  _drawingController.addContent(StraightLine.fromJson(_testLine1));\n  _drawingController.addContents(\u003cPaintContent\u003e[StraightLine.fromJson(_testLine2)]);\n}\n```\n\n* 设置绘制内容\n\n```dart\n/// 将绘制内容设置为普通线条\n_drawingController.setPaintContent = SimpleLine();\n```\n\n|  内置图形   | 说明  | 参数 |\n|  ----  | ----  | ---- |\n| SimpleLine  | 普通线条 | / |\n| SmoothLine  | 笔触线条 | double brushPrecision = 0.4 |\n| StraightLine  | 直线 | / |\n| Rectangle  | 矩形 | / |\n| Circle  | 椭圆 | bool isEllipse = false \u003cbr\u003ebool startFromCenter = true |\n| Eraser  | 橡皮 | / |\n\n* 设置Paint\n\n```dart\n_drawingController.setStyle();\n\n/// 可选参数\nvoid setStyle({\n  BlendMode? blendMode,\n  Color? color,\n  ColorFilter? colorFilter,\n  FilterQuality? filterQuality,\n  ui.ImageFilter? imageFilter,\n  bool? invertColors,\n  bool? isAntiAlias,\n  MaskFilter? maskFilter,\n  Shader? shader,\n  StrokeCap? strokeCap,\n  StrokeJoin? strokeJoin,\n  double? strokeMiterLimit,\n  double? strokeWidth,\n  PaintingStyle? style,\n})\n```\n\n* 画布操作\n\n```dart\n/// 撤销\n_drawingController.undo();\n\n/// 重做\n_drawingController.redo();\n\n/// 旋转画布\n_drawingController.turn();\n\n///清理画布\n_drawingController.clear();\n```\n\n### 自定义绘制\n\n* 创建继承自 [PaintContent](https://github.com/fluttercandies/flutter_drawing_board/blob/master/lib/src/paint_contents/paint_content.dart) 的自定义绘制类 (以三角形为例)\n\n```dart\n/// 自定义绘制三角形\nclass Triangle extends PaintContent {\n  Triangle();\n\n  Triangle.data({\n    required this.startPoint,\n    required this.A,\n    required this.B,\n    required this.C,\n    required Paint paint,\n  }) : super.paint(paint);\n\n  factory Triangle.fromJson(Map\u003cString, dynamic\u003e data) {\n    return Triangle.data(\n      startPoint: jsonToOffset(data['startPoint'] as Map\u003cString, dynamic\u003e),\n      A: jsonToOffset(data['A'] as Map\u003cString, dynamic\u003e),\n      B: jsonToOffset(data['B'] as Map\u003cString, dynamic\u003e),\n      C: jsonToOffset(data['C'] as Map\u003cString, dynamic\u003e),\n      paint: jsonToPaint(data['paint'] as Map\u003cString, dynamic\u003e),\n    );\n  }\n\n  Offset startPoint = Offset.zero;\n\n  Offset A = Offset.zero;\n  Offset B = Offset.zero;\n  Offset C = Offset.zero;\n\n  @override\n  void startDraw(Offset startPoint) =\u003e this.startPoint = startPoint;\n\n  @override\n  void drawing(Offset nowPoint) {\n    A = Offset(startPoint.dx + (nowPoint.dx - startPoint.dx) / 2, startPoint.dy);\n    B = Offset(startPoint.dx, nowPoint.dy);\n    C = nowPoint;\n  }\n\n  @override\n  void draw(Canvas canvas, Size size, bool deeper) {\n    final Path path = Path()\n      ..moveTo(A.dx, A.dy)\n      ..lineTo(B.dx, B.dy)\n      ..lineTo(C.dx, C.dy)\n      ..close();\n\n    canvas.drawPath(path, paint);\n  }\n\n  @override\n  Triangle copy() =\u003e Triangle();\n\n  @override\n  Map\u003cString, dynamic\u003e toJson() {\n    return \u003cString, dynamic\u003e{\n      'startPoint': startPoint.toJson(),\n      'A': A.toJson(),\n      'B': B.toJson(),\n      'C': C.toJson(),\n      'paint': paint.toJson(),\n    };\n  }\n}\n```\n\n* 在默认工具栏中添加工具(可选)\n\n\u003e `showDefaultTools` 必须为 `true` 否则默认工具栏不会显示\n\n\u003e `List\u003cDefToolItem\u003e DrawingBoard.defaultTools(Type currType, DrawingController controller);`  \n\u003e 为默认工具包  \n\u003e 可以使用 `defaultToolsBuilder` 对默认绘制工具进行重写，或者直接在 `defaultTools` 中插入 `DefToolItem` 自定义工具\n\n```dart\nDrawingBoard(\n  ...\n  showDefaultTools: true,\n  defaultToolsBuilder: (Type t, _) {\n    return DrawingBoard.defaultTools(t, _drawingController)\n      ..insert(   /// 将三角形工具插入默认工具栏的第二位\n        1,\n        DefToolItem(\n          icon: Icons.change_history_rounded,\n          isActive: t == Triangle,\n          onTap: () =\u003e _drawingController.setPaintContent = Triangle(),\n      ),\n    );\n  },\n)\n```\n\n* 效果预览  \n\n\u003cimg src=\"https://raw.githubusercontent.com/xSILENCEx/flutter_drawing_board/master/preview/pre7.gif\" height=300\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluttercandies%2Fflutter_drawing_board","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffluttercandies%2Fflutter_drawing_board","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluttercandies%2Fflutter_drawing_board/lists"}