Skip to content

Commit 5ad448f

Browse files
author
Vivek Chib
committed
added cubic interactive graph
1 parent 109ae09 commit 5ad448f

File tree

2 files changed

+209
-4
lines changed

2 files changed

+209
-4
lines changed

lib/views/home_page.dart

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
3333
void initState() {
3434
super.initState();
3535

36-
for (final list in CurveModel.list.values) {
37-
debugPrint(list.length.toString());
38-
}
39-
4036
customCubicControllers = List.generate(4, (index) {
4137
final value = switch (index) {
4238
0 => "0.5",

lib/views/widgets/cubic_graph.dart

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
import 'package:flutter/material.dart';
2+
3+
class CubicGraph extends StatefulWidget {
4+
const CubicGraph({super.key});
5+
6+
@override
7+
State<CubicGraph> createState() => _CubicGraphState();
8+
}
9+
10+
class _CubicGraphState extends State<CubicGraph> {
11+
Offset x2Position = const Offset(100, 100);
12+
Offset y2Position = const Offset(200, 200);
13+
bool isDraggingX2 = false;
14+
bool isDraggingY2 = false;
15+
16+
// Size of the actual graph area
17+
static const graphSize = Size(350, 300);
18+
19+
// Size of the draggable area
20+
static const containerSize = Size(500, 500);
21+
22+
// Offset to center the graph in the container
23+
static final graphOffset = Offset(
24+
(containerSize.width - graphSize.width) / 2,
25+
(containerSize.height - graphSize.height) / 2,
26+
);
27+
28+
void _updatePosition(Offset position) {
29+
setState(() {
30+
if (isDraggingX2) {
31+
x2Position = position;
32+
} else if (isDraggingY2) {
33+
y2Position = position;
34+
}
35+
});
36+
}
37+
38+
@override
39+
Widget build(BuildContext context) {
40+
return MouseRegion(
41+
cursor: isDraggingX2 || isDraggingY2
42+
? SystemMouseCursors.grabbing
43+
: SystemMouseCursors.basic,
44+
child: GestureDetector(
45+
onTapDown: (details) {
46+
final pos = details.localPosition;
47+
if ((pos - (x2Position + graphOffset)).distance < 20) {
48+
setState(() => isDraggingX2 = true);
49+
} else if ((pos - (y2Position + graphOffset)).distance < 20) {
50+
setState(() => isDraggingY2 = true);
51+
}
52+
_updatePosition(details.localPosition - graphOffset);
53+
},
54+
onPanStart: (details) {
55+
final pos = details.localPosition;
56+
if ((pos - (x2Position + graphOffset)).distance < 20) {
57+
setState(() => isDraggingX2 = true);
58+
} else if ((pos - (y2Position + graphOffset)).distance < 20) {
59+
setState(() => isDraggingY2 = true);
60+
}
61+
},
62+
onPanUpdate: (details) =>
63+
_updatePosition(details.localPosition - graphOffset),
64+
onPanEnd: (_) => setState(() {
65+
isDraggingX2 = false;
66+
isDraggingY2 = false;
67+
}),
68+
onPanCancel: () => setState(() {
69+
isDraggingX2 = false;
70+
isDraggingY2 = false;
71+
}),
72+
child: Container(
73+
width: containerSize.width,
74+
height: containerSize.height,
75+
color: Colors.white,
76+
child: CustomPaint(
77+
size: containerSize,
78+
painter: CubicGraphPainter(
79+
x2Position: x2Position,
80+
y2Position: y2Position,
81+
isX2Active: isDraggingX2,
82+
isY2Active: isDraggingY2,
83+
graphSize: graphSize,
84+
graphOffset: graphOffset,
85+
),
86+
),
87+
),
88+
),
89+
);
90+
}
91+
}
92+
93+
class CubicGraphPainter extends CustomPainter {
94+
final Offset x2Position;
95+
final Offset y2Position;
96+
final bool isX2Active;
97+
final bool isY2Active;
98+
final Size graphSize;
99+
final Offset graphOffset;
100+
101+
CubicGraphPainter({
102+
required this.x2Position,
103+
required this.y2Position,
104+
required this.isX2Active,
105+
required this.isY2Active,
106+
required this.graphSize,
107+
required this.graphOffset,
108+
});
109+
110+
@override
111+
bool shouldRepaint(covariant CubicGraphPainter oldDelegate) {
112+
return x2Position != oldDelegate.x2Position ||
113+
y2Position != oldDelegate.y2Position ||
114+
isX2Active != oldDelegate.isX2Active ||
115+
isY2Active != oldDelegate.isY2Active;
116+
}
117+
118+
@override
119+
void paint(Canvas canvas, Size size) {
120+
canvas.translate(graphOffset.dx, graphOffset.dy);
121+
_drawAxisLines(canvas, graphSize);
122+
_drawBezierCurve(canvas, graphSize);
123+
_drawControlPoints(canvas, graphSize);
124+
}
125+
126+
void _drawAxisLines(Canvas canvas, Size size) {
127+
final height = size.height;
128+
final width = size.width;
129+
130+
final linePaint = Paint()
131+
..color = Colors.grey
132+
..strokeWidth = 1.75
133+
..strokeCap = StrokeCap.round
134+
..style = PaintingStyle.stroke;
135+
136+
// Graph background
137+
canvas.drawRect(
138+
Offset.zero & size,
139+
Paint()..color = Colors.grey.withOpacity(0.1),
140+
);
141+
142+
// x axis
143+
canvas.drawLine(Offset(0, height), Offset(width, height), linePaint);
144+
145+
// y axis
146+
canvas.drawLine(Offset.zero, Offset(0, height), linePaint);
147+
}
148+
149+
void _drawBezierCurve(Canvas canvas, Size size) {
150+
final curvePaint = Paint()
151+
..color = Colors.purple
152+
..strokeWidth = 2
153+
..style = PaintingStyle.stroke;
154+
155+
final path = Path();
156+
path.moveTo(0, size.height);
157+
path.cubicTo(
158+
x2Position.dx,
159+
x2Position.dy,
160+
y2Position.dx,
161+
y2Position.dy,
162+
size.width,
163+
0,
164+
);
165+
166+
canvas.drawPath(path, curvePaint);
167+
168+
final controlLinePaint = Paint()
169+
..color = Colors.grey
170+
..strokeWidth = 1
171+
..strokeCap = StrokeCap.round
172+
..style = PaintingStyle.stroke;
173+
174+
canvas.drawLine(Offset(0, size.height), x2Position, controlLinePaint);
175+
canvas.drawLine(y2Position, Offset(size.width, 0), controlLinePaint);
176+
}
177+
178+
void _drawControlPoints(Canvas canvas, Size size) {
179+
final pointerPaint = Paint()
180+
..strokeCap = StrokeCap.round
181+
..style = PaintingStyle.fill;
182+
183+
// Fixed points
184+
canvas.drawCircle(
185+
Offset(0, size.height),
186+
10,
187+
pointerPaint..color = Colors.red,
188+
);
189+
190+
canvas.drawCircle(
191+
Offset(size.width, 0),
192+
10,
193+
pointerPaint..color = Colors.red,
194+
);
195+
196+
// Draggable points
197+
canvas.drawCircle(
198+
x2Position,
199+
10,
200+
pointerPaint..color = isX2Active ? Colors.blue : Colors.green,
201+
);
202+
203+
canvas.drawCircle(
204+
y2Position,
205+
10,
206+
pointerPaint..color = isY2Active ? Colors.blue : Colors.green,
207+
);
208+
}
209+
}

0 commit comments

Comments
 (0)