Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import 'package:flutter/material.dart';
- void main() => runApp(const MyApp());
- class CatmullRomSpline {
- final List<Offset> controlPoints;
- final Offset startHandle;
- final Offset endHandle;
- CatmullRomSpline(this.controlPoints, {required this.startHandle, required this.endHandle});
- Offset transform(double t) {
- final double t2 = t * t;
- final double t3 = t2 * t;
- final double h1 = 2 * t3 - 3 * t2 + 1;
- final double h2 = -2 * t3 + 3 * t2;
- final double h3 = t3 - 2 * t2 + t;
- final double h4 = t3 - t2;
- final double x = h1 * controlPoints[0].dx +
- h2 * controlPoints[1].dx +
- h3 * startHandle.dx +
- h4 * endHandle.dx;
- final double y = h1 * controlPoints[0].dy +
- h2 * controlPoints[1].dy +
- h3 * startHandle.dy +
- h4 * endHandle.dy;
- return Offset(x, y);
- }
- }
- class TreeNode {
- final String label;
- final Offset position;
- final List<TreeNode> children;
- TreeNode(this.label, this.position, {this.children = const []});
- }
- final CatmullRomSpline path = CatmullRomSpline(
- const <Offset>[
- Offset(0.05, 0.75),
- Offset(0.18, 0.23),
- Offset(0.32, 0.04),
- Offset(0.73, 0.5),
- Offset(0.42, 0.74),
- Offset(0.73, 0.01),
- Offset(0.93, 0.93),
- Offset(0.05, 0.75),
- ],
- startHandle: const Offset(0.93, 0.93),
- endHandle: const Offset(0.18, 0.23),
- );
- final TreeNode rootNode = TreeNode('A', Offset(0.5, 0.1), children: [
- TreeNode('B', Offset(0.2, 0.3), children: [
- TreeNode('D', Offset(0.1, 0.5)),
- TreeNode('E', Offset(0.3, 0.5)),
- ]),
- TreeNode('C', Offset(0.8, 0.3), children: [
- TreeNode('F', Offset(0.7, 0.5)),
- TreeNode('G', Offset(0.9, 0.5)),
- ]),
- ]);
- class MyApp extends StatelessWidget {
- const MyApp({Key? key}) : super(key: key);
- static const String _title = 'Flutter Code Sample';
- @override
- Widget build(BuildContext context) {
- return const MaterialApp(
- title: _title,
- home: MyStatelessWidget(),
- );
- }
- }
- class FollowCurve2D extends StatefulWidget {
- const FollowCurve2D({
- Key? key,
- required this.path,
- this.curve = Curves.easeInOut,
- required this.child,
- this.duration = const Duration(seconds: 1),
- }) : super(key: key);
- final CatmullRomSpline path;
- final Curve curve;
- final Duration duration;
- final Widget child;
- @override
- State<FollowCurve2D> createState() => _FollowCurve2DState();
- }
- class _FollowCurve2DState extends State<FollowCurve2D> with TickerProviderStateMixin {
- late AnimationController controller;
- late Animation<double> animation;
- @override
- void initState() {
- super.initState();
- controller = AnimationController(duration: widget.duration, vsync: this);
- animation = CurvedAnimation(parent: controller, curve: widget.curve);
- controller.repeat();
- controller.addListener(() => setState(() {}));
- }
- @override
- void dispose() {
- controller.dispose();
- super.dispose();
- }
- @override
- Widget build(BuildContext context) {
- final Offset position = widget.path.transform(animation.value) * 2.0 - const Offset(1.0, 1.0);
- return Align(
- alignment: Alignment(position.dx, position.dy),
- child: widget.child,
- );
- }
- }
- class MyStatelessWidget extends StatelessWidget {
- const MyStatelessWidget({Key? key}) : super(key: key);
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- backgroundColor: Colors.white,
- body: Center(
- child: FollowCurve2D(
- path: path,
- duration: const Duration(seconds: 3),
- child: buildTree(context, rootNode),
- ),
- ),
- );
- }
- Widget buildTree(BuildContext context, TreeNode node) {
- return Stack(
- children: [
- Positioned(
- left: node.position.dx * 400, // Scale the position to fit the screen
- top: node.position.dy * 800,
- child: CircleAvatar(
- backgroundColor: Colors.yellow,
- child: DefaultTextStyle(
- style: Theme.of(context).textTheme.headline6!,
- child: Text(node.label),
- ),
- ),
- ),
- for (var child in node.children) buildTree(context, child),
- ],
- );
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement