diff --git a/.metadata b/.metadata index a7c68c6..276608f 100644 --- a/.metadata +++ b/.metadata @@ -1,11 +1,11 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled. +# This file should be version controlled and should not be manually edited. version: - revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 - channel: stable + revision: "603104015dd692ea3403755b55d07813d5cf8965" + channel: "stable" project_type: app @@ -13,20 +13,17 @@ project_type: app migration: platforms: - platform: root - create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 - base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 - - platform: android - create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 - base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 - - platform: ios - create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 - base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + - platform: linux + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 - platform: macos - create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 - base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 - - platform: web - create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 - base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1 + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + - platform: windows + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 # User provided section diff --git a/lib/src/domain/models/drawing_tool.dart b/lib/src/domain/models/drawing_tool.dart index c737e7d..0771ee3 100644 --- a/lib/src/domain/models/drawing_tool.dart +++ b/lib/src/domain/models/drawing_tool.dart @@ -5,6 +5,7 @@ enum DrawingTool { eraser, polygon, square, + pan, circle; bool get isEraser => this == DrawingTool.eraser; @@ -14,4 +15,5 @@ enum DrawingTool { bool get isPolygon => this == DrawingTool.polygon; bool get isSquare => this == DrawingTool.square; bool get isCircle => this == DrawingTool.circle; + bool get isPan => this == DrawingTool.pan; } diff --git a/lib/src/extensions/drawing_tool_extensions.dart b/lib/src/extensions/drawing_tool_extensions.dart index e167bed..2076d51 100644 --- a/lib/src/extensions/drawing_tool_extensions.dart +++ b/lib/src/extensions/drawing_tool_extensions.dart @@ -18,6 +18,8 @@ extension DrawingToolExtensions on DrawingTool { return StrokeType.square; case DrawingTool.circle: return StrokeType.circle; + default: + return StrokeType.normal; } } @@ -32,6 +34,8 @@ extension DrawingToolExtensions on DrawingTool { return SystemMouseCursors.precise; case DrawingTool.fill: return SystemMouseCursors.click; + case DrawingTool.pan: + return SystemMouseCursors.grab; } } } diff --git a/lib/src/presentation/widgets/canvas_side_bar.dart b/lib/src/presentation/widgets/canvas_side_bar.dart index 216979c..067af97 100644 --- a/lib/src/presentation/widgets/canvas_side_bar.dart +++ b/lib/src/presentation/widgets/canvas_side_bar.dart @@ -139,6 +139,12 @@ class _CanvasSideBarState extends State { widget.drawingTool.value = DrawingTool.eraser, tooltip: 'Eraser', ), + _IconBox( + iconData: Icons.pan_tool, + selected: widget.drawingTool.value == DrawingTool.pan, + onTap: () => widget.drawingTool.value = DrawingTool.pan, + tooltip: 'Pan', + ), _IconBox( iconData: FontAwesomeIcons.square, selected: widget.drawingTool.value == DrawingTool.square, diff --git a/lib/src/presentation/widgets/drawing_canvas.dart b/lib/src/presentation/widgets/drawing_canvas.dart index 0cec0a0..09b848b 100644 --- a/lib/src/presentation/widgets/drawing_canvas.dart +++ b/lib/src/presentation/widgets/drawing_canvas.dart @@ -39,6 +39,10 @@ class _DrawingCanvasState extends State { ValueNotifier> get _strokes => widget.strokesListenable; + final TransformationController _transformationController = + TransformationController(); + double _minX = 0, _maxX = 0, _minY = 0, _maxY = 0; + CurrentStrokeValueNotifier get _currentStroke => widget.currentStrokeListenable; @@ -46,6 +50,8 @@ class _DrawingCanvasState extends State { final box = context.findRenderObject() as RenderBox?; if (box == null) return; final offset = box.globalToLocal(event.position); + final localPosition = + _transformationController.toScene(event.localPosition); // convert the offset to standard size so that it // can be scaled back to the device size final standardOffset = offset.scaleToStandard(box.size); @@ -59,17 +65,66 @@ class _DrawingCanvasState extends State { filled: widget.options.fillShape, ); widget.onDrawingStrokeChanged?.call(_currentStroke.value); + _minX = _strokes.value.isEmpty + ? localPosition.dx + : _minX < localPosition.dx + ? _minX + : localPosition.dx; + + _maxX = _strokes.value.isEmpty + ? localPosition.dx + : _maxX > localPosition.dx + ? _maxX + : localPosition.dx; + + _minY = _strokes.value.isEmpty + ? localPosition.dy + : _minY < localPosition.dy + ? _minY + : localPosition.dy; + + _maxY = _strokes.value.isEmpty + ? localPosition.dy + : _minY > localPosition.dy + ? _minY + : localPosition.dy; } void _onPointerMove(PointerMoveEvent event) { final box = context.findRenderObject() as RenderBox?; if (box == null) return; final offset = box.globalToLocal(event.position); + final localPosition = + _transformationController.toScene(event.localPosition); // convert the offset to standard size so that it // can be scaled back to the device size final standardOffset = offset.scaleToStandard(box.size); _currentStroke.addPoint(standardOffset); widget.onDrawingStrokeChanged?.call(_currentStroke.value); + + _minX = _strokes.value.isEmpty + ? localPosition.dx + : _minX < localPosition.dx + ? _minX + : localPosition.dx; + + _maxX = _strokes.value.isEmpty + ? localPosition.dx + : _maxX > localPosition.dx + ? _maxX + : localPosition.dx; + + _minY = _strokes.value.isEmpty + ? localPosition.dy + : _minY < localPosition.dy + ? _minY + : localPosition.dy; + + _maxY = _strokes.value.isEmpty + ? localPosition.dy + : _minY > localPosition.dy + ? _minY + : localPosition.dy; } void _onPointerUp(PointerUpEvent event) { @@ -89,36 +144,46 @@ class _DrawingCanvasState extends State { onPointerUp: _onPointerUp, onPointerMove: _onPointerMove, onPointerDown: _onPointerDown, - child: Stack( - children: [ - Positioned.fill( - child: RepaintBoundary( - key: widget.canvasKey, - child: CustomPaint( - isComplex: true, - painter: _DrawingCanvasPainter( - strokesListenable: _strokes, - backgroundColor: widget.options.backgroundColor, + child: InteractiveViewer( + transformationController: _transformationController, + panEnabled: currentTool.isPan ? true : false, + minScale: 0.1, + maxScale: 5.0, + child: SizedBox( + width: (_maxX - _minX).abs() + 2000, + height: (_maxY - _minY).abs() + 2000, + child: Stack( + children: [ + Positioned.fill( + child: RepaintBoundary( + key: widget.canvasKey, + child: CustomPaint( + isComplex: true, + painter: _DrawingCanvasPainter( + strokesListenable: _strokes, + backgroundColor: widget.options.backgroundColor, + ), + ), + ), ), - ), - ), - ), - - // Draw the current stroke on top of the rest of the strokes. - Positioned.fill( - child: RepaintBoundary( - child: CustomPaint( - isComplex: true, - painter: _DrawingCanvasPainter( - strokeListenable: _currentStroke, - backgroundColor: widget.options.backgroundColor, - showGridListenable: _showGrid, - backgroundImageListenable: widget.backgroundImageListenable, + + // Draw the current stroke on top of the rest of the strokes. + Positioned.fill( + child: RepaintBoundary( + child: CustomPaint( + isComplex: true, + painter: _DrawingCanvasPainter( + strokeListenable: _currentStroke, + backgroundColor: widget.options.backgroundColor, + showGridListenable: _showGrid, + backgroundImageListenable: + widget.backgroundImageListenable, + ), + ), + ), ), - ), - ), - ), - ], + ], + )), ), ), );