locked x axis if zoomed out

white page background
dont allow drawing out of page
This commit is contained in:
lukas-heiligenbrunner 2022-10-27 00:15:13 +02:00
parent 693d0538ef
commit d91a834126
5 changed files with 130 additions and 58 deletions

View File

@ -1,9 +1,7 @@
import 'dart:math';
import 'dart:ui'; import 'dart:ui';
import 'package:equations/equations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:notes/canvas/my_painter.dart'; import 'package:notes/canvas/my_painter.dart';
import 'package:notes/canvas/screen_document_mapping.dart';
import 'document_types.dart'; import 'document_types.dart';
@ -18,8 +16,9 @@ class _DrawingPageState extends State<DrawingPage> {
List<Stroke> _strokes = []; List<Stroke> _strokes = [];
bool allowDrawWithFinger = false; bool allowDrawWithFinger = false;
double zoom = .5; double zoom = .75;
Offset scrollPos = const Offset(.0, .0); double basezoom = 1.0;
Offset offset = const Offset(.0, .0);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -37,57 +36,102 @@ class _DrawingPageState extends State<DrawingPage> {
return basetickness; return basetickness;
// todo do correct linear interpolation and extimate angle // todo do correct linear interpolation and extimate angle
final lininterpol = PolynomialInterpolation( // final lininterpol = PolynomialInterpolation(
nodes: pts // nodes: pts
.map((e) => InterpolationNode(x: e.point.dx, y: e.point.dy)) // .map((e) => InterpolationNode(x: e.point.dx, y: e.point.dy))
.toList(growable: false)); // .toList(growable: false));
lininterpol.compute(1.0); // lininterpol.compute(1.0);
print(lininterpol.buildPolynomial().toString()); // print(lininterpol.buildPolynomial().toString());
//
// double angle = atan((pt2.dy - pt1.dy)/(pt2.dx - pt1.dx)); // // double angle = atan((pt2.dy - pt1.dy)/(pt2.dx - pt1.dx));
//
final angle = 5 / (2 * pi); // final angle = 5 / (2 * pi);
// print("pt1: ${pt1}, pt2: ${pt2}, angle: ${angle}"); // // print("pt1: ${pt1}, pt2: ${pt2}, angle: ${angle}");
//
return basetickness * (angle / .5 + .5); // return basetickness * (angle / .5 + .5);
} }
Widget _buildCanvas() { Widget _buildCanvas() {
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
final zoomedwidth = width * zoom;
return Scaffold( return Scaffold(
body: Listener( body: Listener(
behavior: HitTestBehavior.opaque,
onPointerMove: (event) { onPointerMove: (event) {
// print(event.tilt); Offset pos = event.localPosition;
final pos = event.localPosition; final scale =
calcPageDependentScale(zoom, a4Page, Size(width, height));
pos = translateScreenToDocumentPoint(pos, scale, offset);
if (!a4Page.contains(pos)) {
return;
}
if (allowDrawWithFinger || event.kind != PointerDeviceKind.touch) {
final pts = _strokes.last.points; final pts = _strokes.last.points;
if (pts.last.point == pos) return; if (pts.last.point == pos) return;
if (allowDrawWithFinger || event.kind != PointerDeviceKind.touch) {
double newWidth = _calcTiltedWidth(3.0, event.tilt); double newWidth = _calcTiltedWidth(3.0, event.tilt);
if (_strokes.last.points.length > 1) { if (_strokes.last.points.length > 1) {
// todo current point not in list // todo current point not in list
newWidth = _calcAngleDependentWidth(pts.getRange(pts.length - 10 >= 0 ? pts.length -10 : 0, pts.length).toList(growable: false), event.tilt); newWidth = _calcAngleDependentWidth(
pts
.getRange(pts.length - 10 >= 0 ? pts.length - 10 : 0,
pts.length)
.toList(growable: false),
event.tilt);
} }
setState(() { setState(() {
_strokes = List.from(_strokes, growable: false) _strokes = List.from(_strokes, growable: false)
..last.points.add(Point(pos, newWidth)); ..last.points.add(Point(pos, newWidth));
}); });
} else {
if (zoom > 1.0) {
Offset newOffset = offset + event.delta;
// don't allow navigating out of page if zoomed in
if (newOffset.dx > .0) {
setState(() {
offset = Offset(.0, newOffset.dy);
});
} else if (newOffset.dx < (-width * zoom) + width) {
setState(() {
offset = Offset((-width * zoom) + width, newOffset.dy);
});
print(offset);
} else {
setState(() {
offset = offset + event.delta;
});
}
} else {
setState(() {
// keep page x centered if zoomed out
offset = Offset(
(width - (width * zoom)) / 2, offset.dy + event.delta.dy);
});
}
} }
}, },
onPointerDown: (event) { onPointerDown: (event) {
if (allowDrawWithFinger || event.kind != PointerDeviceKind.touch) { if (allowDrawWithFinger || event.kind != PointerDeviceKind.touch) {
Offset pos = event.localPosition;
final scale =
calcPageDependentScale(zoom, a4Page, Size(width, height));
pos = translateScreenToDocumentPoint(pos, scale, offset);
// todo line drawn on edge where line left page
if (!a4Page.contains(pos)) return;
setState(() { setState(() {
_strokes = List.from(_strokes) _strokes = List.from(_strokes)
..add(Stroke.fromPoints([Point(event.localPosition, _calcTiltedWidth(3.0, event.tilt))])); ..add(Stroke.fromPoints(
[Point(pos, _calcTiltedWidth(3.0, event.tilt))]));
}); });
} }
}, },
onPointerUp: (event) { onPointerUp: (event) {
if (allowDrawWithFinger || event.kind != PointerDeviceKind.touch) { if (allowDrawWithFinger || event.kind != PointerDeviceKind.touch) {
if (_strokes.last.points.length <= 1) { if (_strokes.last.points.length <= 1) {
@ -107,12 +151,18 @@ class _DrawingPageState extends State<DrawingPage> {
}, },
child: GestureDetector( child: GestureDetector(
onScaleUpdate: (details) { onScaleUpdate: (details) {
if (details.scale == 1.0) return;
print('scale; ${details.scale}');
setState(() { setState(() {
zoom = details.scale; zoom = (basezoom * details.scale).clamp(0.25, 5.0);
}); });
}, },
onScaleEnd: (details) {
basezoom = zoom;
},
child: CustomPaint( child: CustomPaint(
painter: MyPainter(strokes: _strokes,offset: scrollPos, zoom: zoom), painter: MyPainter(strokes: _strokes, offset: offset, zoom: zoom),
// todo not working // todo not working
size: Size.infinite, // todo add different paper dimensions size: Size.infinite, // todo add different paper dimensions
), ),

View File

@ -1,7 +1,13 @@
import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:notes/canvas/screen_document_mapping.dart';
import 'document_types.dart'; import 'document_types.dart';
final Rect a4Page =
Rect.fromPoints(const Offset(.0, .0), const Offset(210, 210 * sqrt2));
class MyPainter extends CustomPainter { class MyPainter extends CustomPainter {
List<Stroke> strokes; List<Stroke> strokes;
double zoom; double zoom;
@ -9,40 +15,43 @@ class MyPainter extends CustomPainter {
MyPainter({required this.strokes, required this.zoom, required this.offset}); MyPainter({required this.strokes, required this.zoom, required this.offset});
Offset _translatept(Offset pt, Size canvasSize) {
final scale = calcPageDependentScale(zoom, a4Page, canvasSize);
return translateDocumentToScreenPoint(pt, scale, offset);
}
Paint backgroundPaint = Paint()..color = Colors.white;
@override @override
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
var paint = Paint() var paint = Paint()
..color = Colors.blue ..color = Colors.blue
..strokeCap = StrokeCap.square; ..strokeCap = StrokeCap.square;
canvas.drawColor(const Color(0xff3f3f3f), BlendMode.src);
canvas.drawRect(
// ..strokeWidth = 3.0; Rect.fromPoints(_translatept(const Offset(0, .0), size),
// canvas.scale(zoom); _translatept(a4Page.bottomRight, size)),
print("zoom: ${zoom}"); backgroundPaint);
canvas.drawColor(Color.fromRGBO(255, 255, 255, .1), BlendMode.src);
final pagewidth = size.width * zoom;
final sidewidth = (size.width - pagewidth) / 2;
canvas.drawLine(Offset(sidewidth, .0), Offset(sidewidth, size.height), paint);
canvas.drawLine(Offset(sidewidth + pagewidth, .0), Offset(sidewidth + pagewidth, size.height), paint);
for (final stroke in strokes) { for (final stroke in strokes) {
for (int i = 0; i < stroke.points.length - 1; i++) { for (int i = 0; i < stroke.points.length - 1; i++) {
final pt1 = stroke.points[i].point; Offset pt1 = stroke.points[i].point;
final pt2 = stroke.points[i+1].point; pt1 = _translatept(pt1, size);
Offset pt2 = stroke.points[i + 1].point;
pt2 = _translatept(pt2, size);
// final strokewidth = _calcAngleDependentWidth(pt1, pt2, stroke.points[i].thickness); // final strokewidth = _calcAngleDependentWidth(pt1, pt2, stroke.points[i].thickness);
canvas.drawLine(pt1, pt2, paint..strokeWidth = stroke.points[i].thickness); canvas.drawLine(
pt1, pt2, paint..strokeWidth = stroke.points[i].thickness);
} }
} }
} }
@override @override
bool shouldRepaint(MyPainter oldDelegate) { bool shouldRepaint(MyPainter oldDelegate) {
return oldDelegate.strokes != strokes; return oldDelegate.strokes != strokes ||
oldDelegate.zoom != zoom ||
oldDelegate.offset != offset;
} }
} }

View File

@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
Offset translateScreenToDocumentPoint(Offset pt, double scale, Offset offset) {
return pt.translate(-offset.dx, -offset.dy).scale(1 / scale, 1 / scale);
}
Offset translateDocumentToScreenPoint(Offset pt, double scale, Offset offset) {
return pt.scale(scale, scale).translate(offset.dx, offset.dy);
}
double calcPageDependentScale(double scale, Rect page, Size canvasSize) {
return scale * (canvasSize.width / page.width);
}

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:notes/CollapseDrawer.dart'; import 'package:notes/collapse_drawer.dart';
import 'package:notes/all_notes_page.dart'; import 'package:notes/all_notes_page.dart';
import 'package:notes/canvas/drawing_page.dart'; import 'package:notes/canvas/drawing_page.dart';