Skip to content

Instantly share code, notes, and snippets.

@roipeker
Created June 4, 2021 19:54
Show Gist options
  • Select an option

  • Save roipeker/169351b6591ffaba82c88e8c3f90f167 to your computer and use it in GitHub Desktop.

Select an option

Save roipeker/169351b6591ffaba82c88e8c3f90f167 to your computer and use it in GitHub Desktop.

Revisions

  1. roipeker created this gist Jun 4, 2021.
    41 changes: 41 additions & 0 deletions main.dart
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,41 @@
    /// live demo: https://graphx-gesture-simple.surge.sh
    import 'package:flutter/material.dart';
    import 'package:graphx/graphx.dart';
    import 'package:graphx_zoompan/simple_zoom.dart';

    void main() {
    runApp(AppSimpleZoom());
    }

    class AppSimpleZoom extends StatefulWidget {
    const AppSimpleZoom({Key? key}) : super(key: key);

    @override
    _AppSimpleZoomState createState() => _AppSimpleZoomState();
    }

    class _AppSimpleZoomState extends State<AppSimpleZoom> {
    final scene = SimpleZoomScene();

    @override
    Widget build(BuildContext context) {
    return MaterialApp(
    home: Scaffold(
    appBar: AppBar(title: Text('Simple transform')),
    body: GestureDetector(
    onScaleStart: scene.onScaleStart,
    onScaleUpdate: scene.onScaleUpdate,
    // onScaleEnd: scene.onScaleEnd,
    child: SceneBuilderWidget(
    builder: () => SceneController(front: scene),
    ),
    ),
    floatingActionButton: FloatingActionButton(
    child: Text('reset'),
    onPressed: scene.resetTransform,
    ),
    ),
    );
    }
    }
    95 changes: 95 additions & 0 deletions simple_zoom.dart
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,95 @@
    import 'package:flutter/material.dart';
    import 'package:graphx/graphx.dart';

    class SimpleZoomScene extends GSprite {
    late GSprite content;
    late GShape box;
    late GIcon pivotIcon;

    GPoint dragPoint = GPoint();
    GPoint grabPoint = GPoint();
    double grabRotation = 0.0;
    double grabScale = 1.0;

    @override
    void addedToStage() {
    super.addedToStage();
    stage!.maskBounds = true;
    stage!.color = Colors.grey.shade700;

    /// a reference icon to understand how the pivot is assign for the
    /// effect.
    pivotIcon = GIcon(Icons.add_circle_outline, Colors.black45, 20);
    pivotIcon.alignPivot(Alignment.center);

    content = GSprite();
    content.graphics
    .beginFill(Colors.grey.shade400)
    .lineStyle(3, Colors.white)
    .drawGRect(stage!.stageRect)
    .endFill();

    box = GShape();
    box.graphics.beginFill(Colors.blue).drawCircle(0, 0, 30).endFill();
    box.setPosition(100, 100);

    addChild(content);
    content.addChild(box);
    content.addChild(pivotIcon);

    stage!.onMouseScroll.add(_onMouseScroll);
    }

    void _onMouseScroll(MouseInputData event) {
    dragPoint = event.stagePosition;
    adjustContentTransform();

    /// use mouse scroll wheel as incrementer for zoom.
    var _scale = content.scale;
    _scale += -event.scrollDelta.y * .001;
    setZoom(_scale);
    }

    void onScaleStart(ScaleStartDetails details) {
    /// If you need, you can detect 1 or more fingers here.
    /// for move vs zoom.
    if (details.pointerCount == 1) {}
    dragPoint = GPoint.fromNative(details.localFocalPoint);
    adjustContentTransform();
    grabRotation = content.rotation;
    grabScale = content.scale;
    }

    void adjustContentTransform() {
    final pivotPoint = content.globalToLocal(dragPoint);
    pivotIcon.x = content.pivotX = pivotPoint.x;
    pivotIcon.y = content.pivotY = pivotPoint.y;
    globalToLocal(dragPoint, grabPoint);
    content.setPosition(grabPoint.x, grabPoint.y);
    }

    void onScaleUpdate(ScaleUpdateDetails details) {
    final focalPoint = GPoint.fromNative(details.localFocalPoint);
    final deltaX = focalPoint.x - dragPoint.x;
    final deltaY = focalPoint.y - dragPoint.y;
    content.setPosition(grabPoint.x + deltaX, grabPoint.y + deltaY);

    /// use touch scale ratio for zoom.
    final _scale = details.scale * grabScale;
    setZoom(_scale);
    content.rotation = details.rotation + grabRotation;
    }

    void setZoom(double zoom) {
    content.scale = zoom.clamp(.5, 3.0);
    }

    void resetTransform() {
    content.pivotX = content.pivotY = content.rotation = 0;
    content.scale = 1;
    content.setPosition(0, 0);
    pivotIcon.setPosition(0, 0);
    // content.transformationMatrix.identity();
    // pivotIcon.transformationMatrix.identity();
    }
    }