From 6b09c44935375821568c02f5035f6bd1c4b44eb0 Mon Sep 17 00:00:00 2001 From: Youcef-Goudjal Date: Sat, 18 May 2024 13:59:20 +0100 Subject: [PATCH] Refactor imports and enhance line styles with dotted and dashed options --- example/pubspec.lock | 187 +++++++++++++++++++++++---------- lib/src/style.dart | 21 +++- lib/src/tile.dart | 163 +++++++++++++++++++++++++---- lib/src/timeline_divider.dart | 192 +++++++++++++++++++++++++--------- pubspec.yaml | 2 +- 5 files changed, 438 insertions(+), 127 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index a37a172..e429d75 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,70 +5,80 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.3.0" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + sha256: "8e36feea6de5ea69f2199f29cf42a450a855738c498b57c0b980e2d3cca9c362" + url: "https://pub.dev" source: hosted version: "1.2.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.18.0" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: "8be10341257b613566fdc9fd073c46f7c032ed329b1c732bda17aca29f2366c8" + url: "https://pub.dev" source: hosted version: "3.0.0" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.1" ffi: dependency: transitive description: name: ffi - url: "https://pub.dartlang.org" + sha256: d97fffd9d86f3dccc7a9059128b468a99320c69007cc9d41a3a1bda07d4e86dc + url: "https://pub.dev" source: hosted version: "1.0.0" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: "9fd2163d866769f60f4df8ac1dc59f52498d810c356fe78022e383dd3c57c0e1" + url: "https://pub.dev" source: hosted version: "6.1.0" flutter: @@ -80,7 +90,8 @@ packages: dependency: "direct main" description: name: flutter_highlight - url: "https://pub.dartlang.org" + sha256: "7b96333867aa07e122e245c033b8ad622e4e3a42a1a2372cbb098a2541d8782c" + url: "https://pub.dev" source: hosted version: "0.7.0" flutter_test: @@ -92,112 +103,160 @@ packages: dependency: "direct main" description: name: google_fonts - url: "https://pub.dartlang.org" + sha256: a9df6f353ca45d6328c5015e5f7f92a79ba9b781719b631bbf2189a20c12bc49 + url: "https://pub.dev" source: hosted version: "2.0.0" highlight: dependency: transitive description: name: highlight - url: "https://pub.dartlang.org" + sha256: "5353a83ffe3e3eca7df0abfb72dcf3fa66cc56b953728e7113ad4ad88497cf21" + url: "https://pub.dev" source: hosted version: "0.7.0" http: dependency: transitive description: name: http - url: "https://pub.dartlang.org" + sha256: "0a48a4e44ec1b6a52eb93b12d129f5b74ee6dbb27703439c965f1bd86f7be59f" + url: "https://pub.dev" source: hosted version: "0.13.0" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: e362d639ba3bc07d5a71faebb98cde68c05bfbcfbbb444b60b6f60bb67719185 + url: "https://pub.dev" source: hosted version: "4.0.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + url: "https://pub.dev" + source: hosted + version: "10.0.4" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + url: "https://pub.dev" + source: hosted + version: "3.0.3" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" source: hosted - version: "0.12.10" + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + url: "https://pub.dev" + source: hosted + version: "0.8.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.12.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.0" path_provider: dependency: transitive description: name: path_provider - url: "https://pub.dartlang.org" + sha256: aa1b3572707c240d72569ce01756728cf0c8dca0cc381253d8ca2858c13edfe4 + url: "https://pub.dev" source: hosted version: "2.0.1" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.dartlang.org" + sha256: "938d2b6591587bcb009d2109a6ea464fd8fb2a75dc6423171b0d0afb1d27c708" + url: "https://pub.dev" source: hosted version: "2.0.0" path_provider_macos: dependency: transitive description: name: path_provider_macos - url: "https://pub.dartlang.org" + sha256: eb58b896ea3a504f0b0fa7870646bda6935a6f752b2a54df33f97070dacca8d4 + url: "https://pub.dev" source: hosted version: "2.0.0" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.dartlang.org" + sha256: c2af5a8a6369992d915f8933dfc23172071001359d17896e83db8be57db8a397 + url: "https://pub.dev" source: hosted version: "2.0.1" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.dartlang.org" + sha256: ecd4d04c225596bcf0fbb86408a1f40084a02dfa412e60172ad52a7f12a781ef + url: "https://pub.dev" source: hosted version: "2.0.0" pedantic: dependency: transitive description: name: pedantic - url: "https://pub.dartlang.org" + sha256: "8f6460c77a98ad2807cd3b98c67096db4286f56166852d0ce5951bb600a63594" + url: "https://pub.dev" source: hosted version: "1.11.0" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + sha256: ebc79f16b5f6b609aad4a5e63447d4795d16f7adee46e93ed03200848c006735 + url: "https://pub.dev" source: hosted version: "3.0.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: c2c49e16d42fd6983eb55e44b7f197fdf16b4da7aab7f8e1d21da307cad3fb02 + url: "https://pub.dev" source: hosted version: "2.0.0" process: dependency: transitive description: name: process - url: "https://pub.dartlang.org" + sha256: c7b9f7d8a6ee4407ab4f8a7d4a951f8f5659c40df14c0924e2e97c32372e9b14 + url: "https://pub.dev" source: hosted version: "4.1.0" sky_engine: @@ -209,44 +268,50 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + url: "https://pub.dev" source: hosted - version: "0.2.19" + version: "0.7.0" timeline_tile: dependency: "direct main" description: @@ -258,30 +323,42 @@ packages: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" + url: "https://pub.dev" source: hosted version: "1.3.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "14.2.1" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + sha256: c6a3f4e4058b70b46e27b2935de2d1562c50680e7fb44833911d981db73826c2 + url: "https://pub.dev" source: hosted version: "2.0.0" xdg_directories: dependency: transitive description: name: xdg_directories - url: "https://pub.dartlang.org" + sha256: "0186b3f2d66be9a12b0295bddcf8b6f8c0b0cc2f85c6287344e2a6366bc28457" + url: "https://pub.dev" source: hosted version: "0.2.0" sdks: - dart: ">=2.12.0 <3.0.0" - flutter: ">=1.20.0" + dart: ">=3.3.3 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/lib/src/style.dart b/lib/src/style.dart index 498066c..70edd5f 100644 --- a/lib/src/style.dart +++ b/lib/src/style.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:timeline_tile/src/tile.dart'; /// Used to customize the indicator from the line. class IndicatorStyle { @@ -12,10 +11,8 @@ class IndicatorStyle { this.iconStyle, this.indicatorXY = 0.5, this.drawGap = false, - }) : assert(width >= 0, - 'The width must be provided and bigger than 0.0'), - assert(height >= 0, - 'The height must be provided and bigger than 0.0'); + }) : assert(width >= 0, 'The width must be provided and bigger than 0.0'), + assert(height >= 0, 'The height must be provided and bigger than 0.0'); /// The width from the indicator. /// It defaults to 20. @@ -85,6 +82,12 @@ class LineStyle { const LineStyle({ this.color = Colors.grey, this.thickness = 4, + this.dotted = false, + this.dotRadius = 4.0, + this.dotSpacing = 10.0, + this.isDashed = false, + this.dashLength = 4.0, + this.dashSpacing = 4.0, }); /// The color used to paint the line. It defaults to ([Colors.grey]). @@ -93,4 +96,12 @@ class LineStyle { /// The thickness from the line. It can't be bigger than ([IndicatorStyle.width]) /// and defaults to 4. final double thickness; + + final bool dotted; // Flag to indicate dotted line style + final double dotRadius; // Length of each dash + final double dotSpacing; // Space between dashes + + final bool isDashed; + final double dashLength; + final double dashSpacing; } diff --git a/lib/src/tile.dart b/lib/src/tile.dart index 8bc82d6..9ca4884 100644 --- a/lib/src/tile.dart +++ b/lib/src/tile.dart @@ -2,8 +2,9 @@ import 'dart:math'; import 'dart:ui' as ui; import 'package:flutter/material.dart'; -import 'package:timeline_tile/src/axis.dart'; -import 'package:timeline_tile/src/style.dart'; + +import 'axis.dart'; +import 'style.dart'; /// The axis used on the [TimelineTile]. enum TimelineAxis { @@ -363,9 +364,9 @@ class _TimelinePainter extends CustomPainter { this.isFirst = false, this.isLast = false, required IndicatorStyle indicatorStyle, - required LineStyle beforeLineStyle, - required LineStyle afterLineStyle, - }) : beforeLinePaint = Paint() + required this.beforeLineStyle, + required this.afterLineStyle, + }) : beforeLinePaint = Paint() ..color = beforeLineStyle.color ..strokeWidth = beforeLineStyle.thickness, afterLinePaint = Paint() @@ -392,15 +393,9 @@ class _TimelinePainter extends CustomPainter { ? indicatorStyle.padding.bottom : indicatorStyle.padding.right, drawGap = indicatorStyle.drawGap, - iconData = indicatorStyle.iconStyle != null - ? indicatorStyle.iconStyle?.iconData - : null, - iconColor = indicatorStyle.iconStyle != null - ? indicatorStyle.iconStyle?.color - : null, - iconSize = indicatorStyle.iconStyle != null - ? indicatorStyle.iconStyle?.fontSize - : null; + iconData = indicatorStyle.iconStyle?.iconData, + iconColor = indicatorStyle.iconStyle?.color, + iconSize = indicatorStyle.iconStyle?.fontSize; /// The axis used to render the line at the [TimelineAxis.vertical] /// or [TimelineAxis.horizontal]. @@ -429,6 +424,8 @@ class _TimelinePainter extends CustomPainter { /// Used to paint the bottom line final Paint afterLinePaint; + final LineStyle beforeLineStyle; + final LineStyle afterLineStyle; /// Used to paint the indicator final Paint? indicatorPaint; @@ -541,7 +538,28 @@ class _TimelinePainter extends CustomPainter { : position.firstSpace.end, centerAxis, ); - canvas.drawLine(beginTopLine, endTopLine, beforeLinePaint); + if (beforeLineStyle.dotted) { + _drawDottedLine( + canvas, + centerAxis, + beginTopLine, + endTopLine, + beforeLinePaint, + dotRadius: beforeLineStyle.dotRadius, + dotSpacing: beforeLineStyle.dotSpacing, + ); + } else if (beforeLineStyle.isDashed) { + _drawDashedLine( + canvas, + beginTopLine, + endTopLine, + beforeLinePaint, + beforeLineStyle.dashLength, + beforeLineStyle.dashSpacing, + ); + } else { + canvas.drawLine(beginTopLine, endTopLine, beforeLinePaint); + } } if (!isLast) { @@ -561,7 +579,74 @@ class _TimelinePainter extends CustomPainter { final endBottomLine = axis == TimelineAxis.vertical ? Offset(centerAxis, position.secondSpace.end) : Offset(position.secondSpace.end, centerAxis); - canvas.drawLine(beginBottomLine, endBottomLine, afterLinePaint); + + if (afterLineStyle.dotted) { + _drawDottedLine( + canvas, + centerAxis, + beginBottomLine, + endBottomLine, + afterLinePaint, + dotRadius: afterLineStyle.dotRadius, + dotSpacing: afterLineStyle.dotSpacing, + ); + } else if (afterLineStyle.isDashed) { + _drawDashedLine( + canvas, + beginBottomLine, + endBottomLine, + afterLinePaint, + afterLineStyle.dashLength, + afterLineStyle.dashSpacing, + ); + } else { + canvas.drawLine(beginBottomLine, endBottomLine, afterLinePaint); + } + } + } + + void _drawDashedLine(Canvas canvas, Offset start, Offset end, Paint paint, + double dashLength, double dashSpacing) { + final double distance = (end - start).distance; + final double dx = (end.dx - start.dx) / distance; + final double dy = (end.dy - start.dy) / distance; + + final double dashPatternLength = dashLength + dashSpacing; + + for (double i = 0; i < distance; i += dashPatternLength) { + double currentDashEnd = i + dashLength; + + if (currentDashEnd > distance) { + currentDashEnd = distance; + } + + final double px1 = start.dx + (dx * i); + final double py1 = start.dy + (dy * i); + final double px2 = start.dx + (dx * currentDashEnd); + final double py2 = start.dy + (dy * currentDashEnd); + + canvas.drawLine(Offset(px1, py1), Offset(px2, py2), paint); + } + } + + void _drawDottedLine( + Canvas canvas, + double centerAxis, + Offset start, + Offset end, + Paint paint, { + double dotSpacing = 2, + double dotRadius = 2, + }) { + print('_drawDottedLine start:$start end:$paint'); + final double distance = (end - start).distance; + final double dx = (end.dx - start.dx) / distance; + final double dy = (end.dy - start.dy) / distance; + + for (double i = 0; i < distance; i += dotSpacing) { + final double px = start.dx + (dx * i); + final double py = start.dy + (dy * i); + canvas.drawCircle(Offset(px, py), dotRadius, paint); } } @@ -578,7 +663,28 @@ class _TimelinePainter extends CustomPainter { axis == TimelineAxis.vertical ? endTopLine.dy : endTopLine.dx; // if the line size is less or equal than 0, the line shouldn't be rendered if (lineSize > 0) { - canvas.drawLine(beginTopLine, endTopLine, beforeLinePaint); + if (beforeLineStyle.dotted) { + _drawDottedLine( + canvas, + centerAxis, + beginTopLine, + endTopLine, + beforeLinePaint, + dotRadius: beforeLineStyle.dotRadius, + dotSpacing: beforeLineStyle.dotSpacing, + ); + } else if (beforeLineStyle.isDashed) { + _drawDashedLine( + canvas, + beginTopLine, + endTopLine, + beforeLinePaint, + beforeLineStyle.dashLength, + beforeLineStyle.dashSpacing, + ); + } else { + canvas.drawLine(beginTopLine, endTopLine, beforeLinePaint); + } } } @@ -595,7 +701,28 @@ class _TimelinePainter extends CustomPainter { : endBottomLine.dx - beginBottomLine.dx; // if the line size is less or equal than 0, the line shouldn't be rendered if (lineSize > 0) { - canvas.drawLine(beginBottomLine, endBottomLine, afterLinePaint); + if (afterLineStyle.dotted) { + _drawDottedLine( + canvas, + centerAxis, + beginBottomLine, + endBottomLine, + afterLinePaint, + dotRadius: afterLineStyle.dotRadius, + dotSpacing: afterLineStyle.dotSpacing, + ); + } else if (afterLineStyle.isDashed) { + _drawDashedLine( + canvas, + beginBottomLine, + endBottomLine, + afterLinePaint, + afterLineStyle.dashLength, + afterLineStyle.dashSpacing, + ); + } else { + canvas.drawLine(beginBottomLine, endBottomLine, afterLinePaint); + } } } } diff --git a/lib/src/timeline_divider.dart b/lib/src/timeline_divider.dart index 5ea163b..fdddeae 100644 --- a/lib/src/timeline_divider.dart +++ b/lib/src/timeline_divider.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:timeline_tile/src/tile.dart'; + +import 'tile.dart'; /// This is a port from the original [Divider]. -/// Except that this one allows to define the start and end +/// Except that this one allows defining the start and end /// according to the width available, with percentage values /// from 0.0 to 1.0 class TimelineDivider extends StatelessWidget { @@ -14,6 +15,12 @@ class TimelineDivider extends StatelessWidget { this.begin = 0.0, this.end = 1.0, this.color = Colors.grey, + this.isDotted = false, + this.dotSpacing = 4.0, + this.dotRadius = 2.0, + this.isDashed = false, + this.dashLength = 4.0, + this.dashSpacing = 4.0, }) : assert(thickness >= 0.0, 'The thickness must be a positive value'), assert(begin >= 0.0 && begin <= 1.0, 'The begin value must be between 0.0 and 1.0'), @@ -49,54 +56,143 @@ class TimelineDivider extends StatelessWidget { /// It defaults to [Colors.grey]. final Color color; + /// Whether the line should be dotted. + final bool isDotted; + + /// The spacing between dots. + final double dotSpacing; + + /// The radius of each dot. + final double dotRadius; + + /// Whether the line should be dashed. + final bool isDashed; + + /// The length of each dash. + final double dashLength; + + /// The spacing between dashes. + final double dashSpacing; + @override Widget build(BuildContext context) { - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - final double halfThickness = thickness / 2; - - EdgeInsetsDirectional margin; - if (axis == TimelineAxis.horizontal) { - final double width = constraints.maxWidth; - final double beginX = width * begin; - final double endX = width * end; - - margin = EdgeInsetsDirectional.only( - start: beginX - halfThickness, - end: width - endX - halfThickness, - ); - } else { - final double height = constraints.maxHeight; - final double beginY = height * begin; - final double endY = height * end; - - margin = EdgeInsetsDirectional.only( - top: beginY - halfThickness, - bottom: height - endY - halfThickness, - ); - } - - return Container( - height: thickness, - margin: margin, - decoration: BoxDecoration( - border: Border( - left: axis == TimelineAxis.vertical - ? BorderSide( - color: color, - width: thickness, - ) - : BorderSide.none, - bottom: axis == TimelineAxis.horizontal - ? BorderSide( - color: color, - width: thickness, - ) - : BorderSide.none, - ), - ), - ); - }, + return CustomPaint( + painter: _TimelineDividerPainter( + axis: axis, + thickness: thickness, + begin: begin, + end: end, + color: color, + isDotted: isDotted, + dotSpacing: dotSpacing, + dotRadius: dotRadius, + isDashed: isDashed, + dashLength: dashLength, + dashSpacing: dashSpacing, + ), + child: SizedBox( + height: axis == TimelineAxis.horizontal ? thickness : double.infinity, + width: axis == TimelineAxis.vertical ? thickness : double.infinity, + ), ); } } + +class _TimelineDividerPainter extends CustomPainter { + _TimelineDividerPainter({ + required this.axis, + required this.thickness, + required this.begin, + required this.end, + required this.color, + required this.isDotted, + required this.dotSpacing, + required this.dotRadius, + required this.isDashed, + required this.dashLength, + required this.dashSpacing, + }); + + final TimelineAxis axis; + final double thickness; + final double begin; + final double end; + final Color color; + final bool isDotted; + final double dotSpacing; + final double dotRadius; + final bool isDashed; + final double dashLength; + final double dashSpacing; + + @override + void paint(Canvas canvas, Size size) { + final Paint paint = Paint() + ..color = color + ..strokeWidth = thickness; + + final double halfThickness = thickness / 2; + + Offset start, finish; + + if (axis == TimelineAxis.horizontal) { + final double width = size.width; + start = Offset(width * begin, halfThickness); + finish = Offset(width * end, halfThickness); + } else { + final double height = size.height; + start = Offset(halfThickness, height * begin); + finish = Offset(halfThickness, height * end); + } + + if (isDotted) { + _drawDottedLine(canvas, start, finish, paint, dotSpacing, dotRadius); + } else if (isDashed) { + _drawDashedLine(canvas, start, finish, paint, dashLength, dashSpacing); + } else { + canvas.drawLine(start, finish, paint); + } + } + + void _drawDottedLine(Canvas canvas, Offset start, Offset end, Paint paint, + double spacing, double radius) { + final double distance = (end - start).distance; + final double dx = (end.dx - start.dx) / distance; + final double dy = (end.dy - start.dy) / distance; + + for (double i = 0; i < distance; i += spacing) { + final double px = start.dx + (dx * i); + final double py = start.dy + (dy * i); + canvas.drawCircle(Offset(px, py), radius, paint); + } + } + + void _drawDashedLine(Canvas canvas, Offset start, Offset end, Paint paint, + double dashLength, double dashSpacing) { + final double distance = (end - start).distance; + final double dx = (end.dx - start.dx) / distance; + final double dy = (end.dy - start.dy) / distance; + + final double dashPatternLength = dashLength + dashSpacing; + + for (double i = 0; i < distance; i += dashPatternLength) { + double currentDashEnd = i + dashLength; + + if (currentDashEnd > distance) { + currentDashEnd = distance; + } + + final double px1 = start.dx + (dx * i); + final double py1 = start.dy + (dy * i); + final double px2 = start.dx + (dx * currentDashEnd); + final double py2 = start.dy + (dy * currentDashEnd); + + canvas.drawLine(Offset(px1, py1), Offset(px2, py2), paint); + } + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return true; + } +} diff --git a/pubspec.yaml b/pubspec.yaml index e05aa86..230b974 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ homepage: https://github.com/JHBitencourt/timeline_tile issue_tracker: https://github.com/JHBitencourt/timeline_tile/issues environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=3.3.3 <4.0.0" dependencies: flutter: