GithubHelp home page GithubHelp logo

nateshmbhat / touchable Goto Github PK

View Code? Open in Web Editor NEW
230.0 4.0 74.0 6.38 MB

Flutter library to add gestures and animations to each Shape you draw on your canvas in your CustomPainter

Home Page: https://pub.dev/packages/touchable

License: Mozilla Public License 2.0

Dart 98.22% Kotlin 0.12% Swift 0.34% Objective-C 0.03% HTML 1.28%
touchable canvas flutter dart custompaint custom-paint custom-painter paint shapes custompainter

touchable's Introduction

Flutter library to bring your CustomPainter 🎨 to Life ✨⚡️

touchable library gives you the ability to add various gestures and animations to each Shape you draw on your canvas in the CustomPainter


           

Index :

Why Use Touchable ?

  • The CustomPainter lets you only draw shapes on the canvas. But most would want to let user interact with the drawings.

  • Add all kinds of gesture callbacks to each drawing to give interaction capability to the shapes you draw on the canvas.

  • Animating individual shapes has never been this easy.

  • Auto Handles the painting style (filled ▮ , stroke ▯) and detects touch accordingly.

  • Handles Painting stroke width. So if your shapes are painted thick , we still got it covered ✓

  • Supports clipping and different clipping modes for the drawings.

  • Supports HitTestBehavior for each shape.

  • Simple and Easy API. Just wrap your CustomPaint with CanvasTouchDetector and use the TouchyCanvas in your painter.

With touchable , you get what the normal canvas always missed : touchability 😉

Installation

Add the touchable package as dependency in your pubspec.yaml

dependencies:
  touchable:

Usage

  • Just Wrap your CustomPaint widget with CanvasTouchDetector. It takes a builder function as argument that expects your CustomPaint widget as shown below.
CanvasTouchDetector(
    builder: (context) => 
        CustomPaint(
            painter: MyPainter(context)
        )
)
  • Inside your CustomPainter class's paint method , create and use the TouchyCanvas object (using the context obtained from the CanvasTouchDetector and canvas) to draw any shape with different gesture callbacks.
var myCanvas = TouchyCanvas(context,canvas);
myCanvas.drawRect( rect , Paint() , onTapDown: (tapDetail){
    //Do stuff here. Probably change your state and animate
});

MyPainter example :

class MyPainter extends CustomPainter {

  final BuildContext context ;
  MyPainter(this.context); // context from CanvasTouchDetector

  @override
  void paint(Canvas canvas, Size size) {
    var myCanvas = TouchyCanvas(context,canvas); 

    myCanvas.drawCircle(Offset(10, 10), 60, Paint()..color=Colors.orange ,
        onTapDown: (tapdetail) {
         print("orange Circle touched");
       },
        onPanDown:(tapdetail){
          print("orange circle swiped");
        } 
    );

    myCanvas.drawLine(
        Offset(0, 0),
        Offset(size.width - 100, size.height - 100),
        Paint()
          ..color = Colors.black
          ..strokeWidth = 50, 
        onPanUpdate: (detail) {
            print('Black line Swiped'); //do cooler things here. Probably change app state or animate
    });
  }
}


How Touchable Works

When you draw shapes on the canvas (TouchyCanvas) , it keeps track of the dimensions of each shape you draw and their painting style , stroke , order , clippings etc.

When user performs any gesture on the screen , based on the location of the gesture , the appropriate shape is selected from the lot taking clipping regions , paint , hitTest behaviour etc into account in an optimized way. Callbacks of the corresponding shapes (one or more depending on the hitTest behavior) are executed.

Road Map

  • Basic Shape Detection
    • Line
    • Rectangle (Rect)
    • Circle
    • Oval or Ellipse
    • Arc
      • segment
      • sector
    • Rounded Rectangle (RRect)
    • Custom Path [only supports opaque hittest]
    • Points (PointMode.points , PointMode.lines , PointMode.polygon)
    • Vertices
      • Traingle
      • Traingle Strip
      • Traingle Fan
  • Support for proper edge detection based on the Paint object properties :
    • Paint style
    • Stroke Width
    • Stroke Cap
      • StrokeCap to draw Points
      • StrokeCap.round for lines with huge width.
  • Support Clipping and clipping modes
    • ClipRect
      • intersect mode [Touch detection enabled only inside the clipped region]
      • difference mode [Touch detection enabled only outside the clipped region]
    • ClipRRect
    • ClipPath
  • Support for HitTestBehavior
  • Make the touch detection handling to run in a seperate isolate.
  • Support for translation , rotation , scaling and skewing transformations that needs some vector math

Links

touchable's People

Contributors

jja08111 avatar nateshmbhat avatar sadhorsephile avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

touchable's Issues

onScaleStart onScaleUpdate Events?

Is there a reason the onScaleStart and onScaleUpdate Event handlers are not currently supported by the library?

Do they cause conflicts with other handlers? They are commented out in the canvas_touch_detector.dart and arent available on any of the drawable shapes in the canvas. I would be very grateful if you could explain why that is.

Error: Having both a Pan Gesture Recogniser and a Scale Gesture Recogniser is redundant

Since upgrading to Flutter 2.10.4, the plugin is returning an error:

The following assertion was thrown building CanvasTouchDetector(dirty, state: _CanvasTouchDetectorState#55157):
Incorrect GestureDetector arguments.

Having both a pan gesture recognizer and a scale gesture recognizer is redundant; scale is a superset of pan.

Just use the scale gesture recognizer.

My implementation uses onTapDown with an svg. Prior to upgrading Flutter, the plugin was working perfectly.

Any solutions to this?

onPanUpdate does not work in Flutter Web

Hi,

I just tried the example in https://medium.com/flutter-community/bring-your-custompainter-paintings-to-life-in-flutter-using-touchable-c2413cd1897 and it was working for Android but not for web. In web I was not able to drag the earth.

Here is the sample program

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:touchable/touchable.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home:MyCoolPage(),
    );
  }
}

class MyCoolPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(child: MyWidget());
  }
}

class PaintingController extends ChangeNotifier {
  Offset circlePosition;
  Color backgroundColor = Colors.yellow;

  void moveCircle(Offset newPosition) {
    circlePosition = newPosition;
    notifyListeners();
  }

  void toggleBackGroundColor() {
    backgroundColor = backgroundColor == Colors.white ? Colors.blueGrey : Colors.white;
    notifyListeners();
  }
}

class MyWidget extends StatelessWidget {
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<PaintingController>(
      create: (context) => PaintingController(),
      child: Consumer<PaintingController>(
        builder: (context, controller, child) => AnimatedContainer(
          color: controller.backgroundColor,
          duration: Duration(seconds: 1),
          child: CanvasTouchDetector(
            builder: (context) => CustomPaint(painter: MyPainter(context)),
          ),
        ),
      ),
    );
  }
}

class MyPainter extends CustomPainter {
  final BuildContext context;
  final PaintingController controller;

  MyPainter(this.context) : controller = Provider.of<PaintingController>(context, listen: false);

  @override
  void paint(Canvas canvas, Size size) {
    TouchyCanvas touchyCanvas = TouchyCanvas(context, canvas);
    drawEarth(touchyCanvas, size);
    drawSun(touchyCanvas, size);
  }

  void drawEarth(TouchyCanvas canvas, Size size) {
    var blueCircleCenter = controller.circlePosition ?? Offset(size.width / 2, size.height / 2 - 100);

    canvas.drawCircle(blueCircleCenter, 60, Paint()..color = Colors.lightGreen, onPanUpdate: (details) {
      print("pan update called");
      controller
          .moveCircle(Offset(blueCircleCenter.dx + details.delta.dx * 2, blueCircleCenter.dy + details.delta.dy * 2));
    },
      onPanDown: (details) {
        print("pan down called");
        controller.moveCircle(Offset(details.localPosition.dx, details.localPosition.dy));
      },
    );

    canvas.drawCircle(blueCircleCenter, 30, Paint()..color = Colors.lightBlueAccent,
        hitTestBehavior: HitTestBehavior.translucent);
  }

  void drawSun(TouchyCanvas canvas, Size size) {
    var orangeCircleCenter = Offset(size.width / 2, size.height / 2 + 100);
    canvas.drawCircle(orangeCircleCenter, 80, Paint()..color = Colors.orangeAccent, onTapDown: (_) {
      controller.toggleBackGroundColor();
    });
    canvas.drawCircle(orangeCircleCenter, 50, Paint()..color = Colors.orange,
        hitTestBehavior: HitTestBehavior.translucent);
    canvas.drawCircle(orangeCircleCenter, 30, Paint()..color = Colors.deepOrangeAccent,
        hitTestBehavior: HitTestBehavior.translucent);
    canvas.drawCircle(orangeCircleCenter, 20, Paint()..color = Colors.deepOrange,
        hitTestBehavior: HitTestBehavior.translucent);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }

I want to change the mouse cursor.

Hello
I'm using this plug-in in the Flutter web project and it works properly.

In general, mouse over a clickable element in a web browser, the shape of the mouse cursor changes to pointer.

https://developer.mozilla.org/en-US/docs/Web/CSS/cursor

When using this plug-in in a web environment, is there a way to change the shape of the cursor to pointer?

Normally, I solved it with MouseResion()
ex: MouseRegion(cursor: SystemMouseCursors.click, child: ...)

However, as a result of applying MouseResion to this plug-in, the cursor of the entire container displaying the CanvasTouchDetector is changed.

Click on the failure

import 'dart:math';
import 'dart:ui';

import 'package:flutter/material.dart';

import 'package:touchable/touchable.dart';

void main() => runApp(MyApp());

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

@OverRide
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State {
@OverRide
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
color: Colors.white,
//wrap CustomPaint with CanvasTouchDetector
child: CanvasTouchDetector(
builder: (context) => CustomPaint(
painter: MyPaintere(context),
),
),
),
));
}
}

class MyPaintere extends CustomPainter {
final BuildContext context;
MyPaintere(this.context); // context from CanvasTouchDetector
@OverRide
void paint(Canvas canvas, Size size) {
//Create and use TouchyCanvas to draw
TouchyCanvas touchyCanvas = TouchyCanvas(context, canvas);

var blueCircle = Offset(size.width / 2 + 200, size.height / 2 + 100);
var greenCircle = Offset(size.width / 2 + 200, size.height / 2 + 300);

touchyCanvas.drawCircle(blueCircle, 60, Paint()..color = Colors.blue, onTapDown: (_) {
  print('You clicked BLUE circle');
});

touchyCanvas.drawCircle(greenCircle, 30, Paint()..color = Colors.green, onLongPressStart: (_) {
  print('long pressed on GREEN circle');
});

}

@OverRide
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
}

Gesture detection broken with canvas.rotate canvas.translate

Drawing an onTapDown shape before rotation or translation works ok, however; if you rotate or translate the canvas and then draw a shape - the shape does not register onTapDown. If I do not rotate or translate the canvas, the shape is drawn in the wrong location, but onTapDown now works.

I've tried attaching the canvas with touchyCanvas = TouchyCanvas(context, canvas) after the rotation events but this does not fix the onTapDown behaviour.

Is there a workaround for this?

[edit] I found the onTapDown gestures located at the side of the canvas layered on top of each other (clicking one activates them all). Ultimately, it appears the gestures are being inserted and tracked - but they are not attached to the shapes drawn using touchyCanvas that have been rotated.

There is different license information on pub.dev.

Hi, I found great flutter package you made on pub.dev, and it says its License is 'GPL 3.0' on the upper right section of pub.dev.
However, in the documentation says it is under 'MPL 2.0' License.

Can you tell me what is the correct license applied to this package? Thank you.

Crashes when trying to use onPanUpdte to draw new points

Hi
I am trying to achieve a drawing functionality using this library. I want to draw a shape using path & then want user to draw within that area. This library have all the events to implement that but when I am trying to draw all the generated points then it crashes my app.

myCanvas.drawPath(AlphabetPaths.getAlphabetA(size), paint,
        onPanUpdate: (details) {
      points.add(details.localPosition);
      drawNewPath(myCanvas, points);
    });
drawNewPath(myCanvas, points) {
    print(points);
    points.removeWhere((value) => value == null);
    var _pointPaint = Paint()
      ..color = Colors.black
      ..strokeWidth = 5
      ..style = PaintingStyle.fill
      ..strokeCap = StrokeCap.square;
      myCanvas.drawPoints(PointMode.points, points, _pointPaint);
  }

When I am trying to draw new points using onPanUpdate it always crashing on both mobile & web. If I try to add those points directly its working fine.

I am getting following error

I/flutter ( 8546): [Offset(123.0, 469.3), Offset(123.0, 472.4)]
F/libc    ( 8546): Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x28 in tid 10318 (1.ui), pid 8546 (le.gesture_demo)
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'OnePlus/OnePlus5/OnePlus5:10/QKQ1.191014.012/2010292059:user/release-keys'
Revision: '0'
ABI: 'arm64'
Timestamp: 2021-03-30 13:56:54+0530
pid: 8546, tid: 10318, name: 1.ui  >>> com.example.gesture_demo <<<
uid: 11240
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x28
Cause: null pointer dereference
    x0  0000000000000000  x1  000000701f108908  x2  000000701f108958  x3  0000000000000000
    x4  000000701f108960  x5  000000702153a0d0  x6  0000000000000002  x7  000000000000003c
    x8  0000000000000000  x9  0000000000000002  x10 0000000000000001  x11 0000000000000000
    x12 0000000000000005  x13 0000008000000000  x14 000a68cc29c0d93d  x15 000000701f108a10
    x16 0000007021ccb398  x17 00000071116a98b8  x18 000000701ee8a000  x19 0000000000000000
    x20 000000702153a0d0  x21 0000007021539954  x22 0000007021c70278  x23 0000007021c6e2c0
    x24 000000701030ced1  x25 000000701f030000  x26 000000700e7c3800  x27 0000007010310730
    x28 0000000000000004  x29 000000701f108a48
    sp  000000701f108900  lr  000000702153b63c  pc  000000702153a0d0
backtrace:
      #00 pc 00000000013220d0  /data/app/com.example.gesture_demo-pJ5hsmnHb2pDpOT8vlkuyA==/lib/arm64/libflutter.so (BuildId: 4f453a1bb64d1244a9dd8bd68e926b4779043b43)
      #01 pc 00000000000f6914  <anonymous:701f012000>
Lost connection to device.
Exited (sigterm)

There are no null values in the array as you can see in the first line of crash log which are the list of points.
I also added code to remove if there is any null value available.

You can see that right now points only have 2 items but its still crashing.

I tried multiple things but not able to fix this. I don't have any idea why its crashing with only 2 points.
Do you have any idea why this is happening or can you fix this?
If you found the issue let me know. I might be able to help you with this.

Thanks

touchable need to accpect canvas transform data.

The canvas transform(translate, scale, clilpRect) has no effect on TouchyCanvas
demo

import 'package:flutter/material.dart';
import 'package:touchable/touchable.dart';

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

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Home(),
    );
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CanvasTouchDetector(
        builder: (context) => CustomPaint(painter: MyPainter(context)));
  }
}

class MyPainter extends CustomPainter {
  final BuildContext context;

  MyPainter(this.context);

  @override
  void paint(Canvas canvas, Size size) {
    canvas.scale(10);
    canvas.translate(50, 50);
    /// set the transform before create the TouchyCanvas
    var myCanvas = TouchyCanvas(context, canvas);
    myCanvas.drawCircle(Offset(10, 10), 60, Paint()..color = Colors.orange,
        onTapDown: (tapdetail) {
      print("orange Circle touched");
    }, onPanDown: (tapdetail) {
      print("orange circle swiped");
    });
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

touch ripple animation when touch occurs?

How would one get a touch ripple effect on a canvas here, to indicate to the user the touch did occur? (noting that in some apps the touch may only 'do something' if they touch the appropriate point, but still want to highlight there touch in general whether over a touchable object or not - i.e. for any touch on the canvas)

An effect such as InkRipple (https://api.flutter.dev/flutter/material/InkRipple-class.html) however not sure it this works on a canvas?

Problems with Gesture Detector

Hi,

I'm using a GestureDetector around the CanvasTouchDetector, as I want to draw the shapes dynamically and the for example move the shapes per drag and drop!

When I use my coding

@override
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    return Scaffold(
      body: GestureDetector(
        behavior: HitTestBehavior.translucent,
        onPanUpdate: (details) {
          setState(() {
            RenderBox renderBox = context.findRenderObject() as RenderBox;
            points.add(DrawingPoints(
                points: renderBox.globalToLocal(details.globalPosition),
                paint: Paint()
                  ..strokeCap = strokeCap
                  ..isAntiAlias = true
                  ..color = selectedColor.withOpacity(opacity)
                  ..strokeWidth = strokeWidth));
          });
        },
        onPanStart: (details) {
          setState(() {
            RenderBox renderBox = context.findRenderObject() as RenderBox;
            points.add(DrawingPoints(
                points: renderBox.globalToLocal(details.globalPosition),
                paint: Paint()
                  ..strokeCap = strokeCap
                  ..isAntiAlias = true
                  ..color = selectedColor.withOpacity(opacity)
                  ..strokeWidth = strokeWidth));
          });
        },
        onPanEnd: (details) {
          setState(() {
            //points.add(null);
            print("Area: ${_calcualteArea()}");
          });
        },
        // child: CustomPaint(size: Size.infinite, painter: DrawingPainter(context, pointsList: points)),
        child: CanvasTouchDetector(
          builder: (context) => CustomPaint(size: Size.infinite, painter: DrawingPainter(context, pointsList: points)),
        ),
      ),
    );
  }

nothing happens no touch events where triggered :-/

How to change state of shapes using touchable?

class MyPainter extends CustomPainter { 

  @override
  void paint(Canvas canvas, Size size) {
var myCanvas = TouchyCanvas(context,canvas);
  myCanvas.drawRect( rect , paint , onPanDown: (tapDetail){
   print("rectangle touch");
  print(rect.width);
paint.color=Colors.black;

  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }

}

Changing the color by paint.color doesn't change the color of the rectangle... how would the state change ? it's only printing stuff.

Thank you for this library.

FEATURE: onHover

Hi @nateshmbhat, great package!

I was looking for an onHover feature, and I can see two open pull requests here:
#50
#52

Is there any way I can help to get them merged into the main branch?

Touch event fire multi times unexpected

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Expanded(
          child: CustomPaint(
            foregroundPainter: SelectionPainter(notifier: notifierForeground),
            child: RepaintBoundary(
              child: CanvasTouchDetector(
                //key: UniqueKey(),
                gesturesToOverride: const [
                  GestureType.onTapDown,
                ],
                builder: (BuildContext context) {
                  return CustomPaint(
                    isComplex: true,
                    willChange: false,
                    painter: ChartPainter<D, Rx, Ry>(
                      onItemSelected: (List<Rect> selectionRects, item, index, xAxisIndex, layer, tapEvent) {
                        notifierForeground.value = selectionRects;
                        _showTooltip(selectionRects);
                      },
                    ),
                  );
                },
              ),
            ),
          ),
        ),
      ],
    );
  }

After state.build called multi times, onTapDown event will also fire multi times with one click. It seems pre touch rects not cleared ?

Workaround: add UniqueKey to CanvasTouchDetector

How can I force a repaint on click; Change color on click event

Hi,

I am trying to use this library to create this behaviour:

I have a filled Path. When I tap on the path it should turn into red. So using this, I can catch the onTapDown event:

myCanvas.drawPath(path, paint, onTapDown: (tapDetail) {
  print('Tapped');
});

What do I have to do to force the repaint with a new color?

Thanks in advance!

few questions

(few questions - not sure if this is correct place to ask)

New to Flutter & come across this package. In terms of doing a small 2D point & click apps, that has a backage image, with clickable polygons aligned with the image over key objects in the image, say running landscape, but can rescale to handle different devices:

Q1 - Is the Flutter Canvas the only way of doing this in flutter, and this package assists? i.e. or is there an alternative to having to use canvas / Custom Painter? (e.g. only using an image flutter widget)

Q2 - I'm noticing when I run on IOS simulator with a Rect and Circle overlapping I'm not getting consistent results with touchable (e.g. onTapDown) and it seems to be missing capturing some clicks? Any known issues with reliability here? Or is this likely to be related to using the simulator?

Q3 - Would the module support scaling across different devices ok?

Q4 - (an aside) - happen to know a tool that would one create a polygon over an image, then export the data in the right format to copy/paste into a flutter app to be used to create a polygon on the canvas? (then use touchable to detect taps in this area)

tks

Incorrect Gesture Arguments

Error :
"The following assertion was thrown building CanvasTouchDetector(dirty, state: _CanvasTouchDetectorState#56194):
Incorrect GestureDetector arguments.

Having both a pan gesture recognizer and a scale gesture recognizer is redundant; scale is a superset of pan.

Just use the scale gesture recognizer."

I wanted to use only tap so deleting other gesture detectors solved the problem for me

Example doesn't work out of the box

Steps to repro:

  1. clone this repo.
  2. run the example
  3. click on screen1 button.

You get this error:

Incorrect GestureDetector arguments.

Having both a pan gesture recognizer and a scale gesture recognizer is redundant; scale is a superset of pan.

Just use the scale gesture recognizer.

draw textspan

  drawText(TouchyCanvas canvas) {
    TextSpan span = new TextSpan(
        style: new TextStyle(color: Colors.blue[800]), text: "name");
    TextPainter tp = new TextPainter(
        text: span,
        textAlign: TextAlign.left,
        textDirection: TextDirection.ltr);
    tp.layout();
    tp.paint(canvas as Canvas, new Offset(5.0, 5.0));
  }

Expected a value of type 'Canvas', but got one of type 'TouchyCanvas'

Touch area is wrong

I'm using this plugin for make some chart that has fade in animation. That animation change width.
By the way, touch area is wrong when animation is done. I think touch area is saved during animating.

Here is some code.

...

_isVisible = false;

...

@override
void initState() {
  super.initState();
  WidgetsBinding.instance.addPostFrameCallback(_setFadeInAnimation);
}

void _setFadeInAnimation(Duration timeStamp) {
  setState(() {
    _visible = true;
  });
}

...
@override
Widget build(BuildContext context) {
  return AnimatedContainer(
    duration: kThemeChangeDuration,
    curve: Curves.easeOut,
    width: _isVisible ? 100 : 80,
    child: CanvasTouchDetector(
      builder: (context) => CustomPaint(
        size: Size(100, 100),
        painter: _myChartPainter(context),
      ),
    ),
  ),
}

Circles cannot be touched in the bottom right quadrant

hello. circles don't appear to receive touch events on the bottom right corner.

This is not much of an issue on mobile where the contact area is huge but with mice there are obvious issues.

am I missing something or is this a bug?

Panning and scaling inside an InteractiveViewer

I have a CanvasTouchDetector with a CustomPainter and I want it to be zoomed, panned, etc. so I have put it inside a Flutter's InteractiveViewer.

The touchable features (I'm using onTapDown) work fine, but you cannot pinch inside the CustomPainter in order to zoom or pan the picture.

How would you arrange the CanvasTouchDetector inside the InteractiveViewer in order for these features to keep working?

Regarding the evolution of touchable, I believe the TouchyCanvas would need to detect zoom/pan gestures and bubble them up?

Incorrect GestureDetector arguments.

Incorrect GestureDetector arguments.
Having both a pan gesture recognizer and a scale gesture recognizer is redundant; scale is a
superset of pan.
Just use the scale gesture recognizer.

Add support for Null Safety

This is not a bug or issue, but i wanted to upgrade my current application to Flutter 2, but detected that Touchable does not have support for null safety.

It could be good if this package upgraded to null safety in case someone want to upgrade to Flutter 2

Doesn't recognize touch event when has a GestureRecognizer in child tree

CanvasTouchDetector(
  builder: (context) => CustomPaint(
    child: SizedBox(
      width: MediaQuery.of(context).size.width,
      height: MediaQuery.of(context).size.width * 9 / 16,
      child: VlcPlayer(
        aspectRatio: 16 / 9,
        url: videoUri,
        controller: _playerController,
        placeholder: CircularProgressIndicator(),
      ),
    ),
    foregroundPainter: CameraControlPainter(camera, context),
  ),
),

Swipe effect with drawarc function

I've detected inside library, that drawArc receives optional parameter GestureDragUpdateCallback? onPanUpdate, but inside that function it sends null as a parameter to the nested function. Do you plan to implement this functionality somehow or this library is dead?

void drawArc(
    Rect rect,
    double startAngle,
    double sweepAngle,
    bool useCenter,
    Paint paint, {
    HitTestBehavior? hitTestBehavior,
    GestureTapDownCallback? onTapDown,
    PaintingStyle? paintStyleForTouch,
    GestureTapUpCallback? onTapUp,
    GestureLongPressStartCallback? onLongPressStart,
    GestureLongPressEndCallback? onLongPressEnd,
    GestureLongPressMoveUpdateCallback? onLongPressMoveUpdate,
    GestureForcePressStartCallback? onForcePressStart,
    GestureForcePressEndCallback? onForcePressEnd,
    GestureForcePressPeakCallback? onForcePressPeak,
    GestureForcePressUpdateCallback? onForcePressUpdate,
    GestureDragStartCallback? onPanStart,
    GestureDragUpdateCallback? onPanUpdate,
    GestureDragDownCallback? onPanDown,
    GestureTapDownCallback? onSecondaryTapDown,
    GestureTapUpCallback? onSecondaryTapUp,
  }) {
    _canvas.drawArc(rect, startAngle, sweepAngle, useCenter, paint);
    var arc = Arc(rect, startAngle, sweepAngle, useCenter,
        paint: paint,
        hitTestBehavior: hitTestBehavior,
        gestureMap: TouchCanvasUtil.getGestureCallbackMap(
            onTapDown: onTapDown,
            onTapUp: null,
            onLongPressStart: null,
            onLongPressEnd: null,
            onLongPressMoveUpdate: null,
            onForcePressStart: null,
            onForcePressEnd: null,
            onForcePressPeak: null,
            onForcePressUpdate: null,
            onPanStart: null,
            onPanUpdate: null,
            onPanDown: null,
            onSecondaryTapDown: null,
            onSecondaryTapUp: null));
    _shapeHandler.addShape(arc);
  }

solution to make text receive touchs detector

Hello ...
first thanks you for developing awesome library
I noticed that drawParagraph function didn't have any touch detector
so I created my workaround solution :
1- draw text via textPainter class, like this :

  double x = 100; // Offset -> x
  double y = 100; // Offset -> y

  final textSpan = TextSpan(
      text: 'Hello world',
      style: TextStyle(color: Colors.black, fontSize: 20),
    );

    final textPainter = TextPainter(
      text: textSpan, textDirection: TextDirection.ltr
    );

    textPainter.layout(minWidth: 0, maxWidth: double.infinity);
    textPainter.paint(canvas, Offset(x, y));
    // canvas is the original canvas ( not TouchyCanvas )

2- create new transparent rect with same size as text like this:

  TouchyCanvas myCanvas = TouchyCanvas(context, canvas);
  Paint rectPaint = Paint()..color = Colors.transparent;
  Rect rect = Offset(x, y) & Size(textPainter.width, textPainter.height);
  myCanvas.drawRect(rect, rectPaint);

now you could do anything like translating 👍
just don't forget to translate text and rect

waiting for your big update !!

Pass an object to touchableCanvas to retrieve from TapDownDetails on tap

Hi, thank you for this awesome package.
I was wondering if it was possible to pass an object to the canvas that would be collected after tap down?

Something like:

touchableCanvas.drawOval(Rect...., Paint..., customIndexOrObject, onTapDown: (tapDetails) {
    print(tapDetails.customIndexOrObject);
});

where the customIndexOrObject would be something like a tag; an integer to identify the drawing on the canvas that was clicked on or some small object to retrieve and act upon.

onTapDown only for last drawn polygon

I'm drawing multiple polygons but the event is only triggered on the last drawn one.
Any clue what the issue could be?

For each Polygon a new TouchyCanvas is added, is this a problem?

how to paint many elements? loop?

Hello. I am new to programming. But it is the first time that I write a question about a problem that I cannot solve.
I have to reproduce about 100 drawings on the canvas, which are mostly the same shapes but in different positions. Do I have to create a function to draw each of them, or is there a way to reuse the same function using a loop? The only way I get each form to be toucheable by itself is by calling its own function, I can't reuse it.
I've seen an example from Joshep Muller on Medium, but it offers the full code and I'm not able to reproduce it.
Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.