locked x axis if zoomed out
white page background dont allow drawing out of page
This commit is contained in:
parent
693d0538ef
commit
d91a834126
@ -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
|
||||||
),
|
),
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
lib/canvas/screen_document_mapping.dart
Normal file
13
lib/canvas/screen_document_mapping.dart
Normal 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);
|
||||||
|
}
|
@ -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';
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user