Custom drawing implementation

This commit is contained in:
2026-02-05 17:47:03 +01:00
parent e1d72de718
commit d4d6e41a9d
14 changed files with 1291 additions and 147 deletions

View File

@@ -0,0 +1,93 @@
import 'dart:ui';
/// Represents a single stroke/line drawn on the canvas.
///
/// Points are stored in normalized coordinates (0.0 to 1.0) where:
/// - (0, 0) is the top-left corner of the drawing area
/// - (1, 1) is the bottom-right corner of the drawing area
///
/// This allows drawings to scale correctly when the canvas size changes.
class DrawingLine {
/// Points in normalized coordinates (0.0 to 1.0)
final List<Offset> points;
/// Color of the line (stored as ARGB integer for JSON serialization)
final Color color;
/// Stroke width in normalized units (relative to canvas width)
/// A value of 0.01 means the stroke is 1% of the canvas width
final double strokeWidth;
const DrawingLine({
required this.points,
required this.color,
required this.strokeWidth,
});
/// Creates a DrawingLine from JSON data.
factory DrawingLine.fromJson(Map<String, dynamic> json) {
final pointsList = (json['points'] as List)
.map((p) => Offset(
(p['x'] as num).toDouble(),
(p['y'] as num).toDouble(),
))
.toList();
return DrawingLine(
points: pointsList,
color: Color(json['color'] as int),
strokeWidth: (json['strokeWidth'] as num).toDouble(),
);
}
/// Converts this line to a JSON-serializable map.
Map<String, dynamic> toJson() {
return {
'points': points.map((p) => {'x': p.dx, 'y': p.dy}).toList(),
'color': color.toARGB32(),
'strokeWidth': strokeWidth,
};
}
/// Creates a copy of this line with an additional point.
DrawingLine addPoint(Offset normalizedPoint) {
return DrawingLine(
points: [...points, normalizedPoint],
color: color,
strokeWidth: strokeWidth,
);
}
/// Creates a copy with updated points.
DrawingLine copyWith({
List<Offset>? points,
Color? color,
double? strokeWidth,
}) {
return DrawingLine(
points: points ?? this.points,
color: color ?? this.color,
strokeWidth: strokeWidth ?? this.strokeWidth,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! DrawingLine) return false;
if (points.length != other.points.length) return false;
if (color != other.color) return false;
if (strokeWidth != other.strokeWidth) return false;
for (int i = 0; i < points.length; i++) {
if (points[i] != other.points[i]) return false;
}
return true;
}
@override
int get hashCode => Object.hash(
Object.hashAll(points),
color,
strokeWidth,
);
}