Search code examples
flutterdartdiagram

i need to get a sankey diagram or arrow shape


Hey i need to drow a sample sankey diagram because i can't find any one like that in syncfusion_flutter_charts or fl_chart so i started to write a class it will give me the same Diagrame but i can't makee the same shape can anyone helpe me by any idea, i will be greatful. i need some thing like this pic.

enter image description here

 class sankey_diagram extends StatefulWidget {
  sankey_diagram({required this.size});
  double size;
  @override
  State<sankey_diagram> createState() => _sankey_diagramState(size: size);
}

class _sankey_diagramState extends State<sankey_diagram> {
  _sankey_diagramState({required this.size});
  double size;
  int? id;
  double ratio = 29;
  @override
  Widget build(BuildContext context) {
    id = context.watch<indexDashboard>().getvesselid();
    return ListView(children: [
      Card(
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
                width: 100,
                height: size,
                decoration: const BoxDecoration(
                    // borderRadius: BorderRadius.only(topLeft: Radius.circular(10.0),bottomLeft: Radius.circular(10.0)),
                    color: Colors.orange)),
            Column(children: [
              Container(
                width: 130,
                height: size * (ratio / 100),
                decoration: BoxDecoration(
                  color: get_color(ratio),
                ),
              ),
              Container(
                width: 130,
                height: size * ((100.0 - ratio) / 100),
                decoration: BoxDecoration(
                    borderRadius: BorderRadius.only(
                      topRight: Radius.circular(size * ((100.0 - ratio) / 100)),
                    ),
                    color: get_color((100.0 - ratio))),
              ),
              Container(
                padding: EdgeInsets.only(left: 25),
                child: Container(
                  width: 85,
                  height: 25,
                  decoration: BoxDecoration(color: get_color((100.0 - ratio))),
                ),
              ),
              Container(
                padding: EdgeInsets.only(left: 25),
                child: Container(
                  width: 100,
                  height: size * ((100.0 - ratio) / 100),
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.only(
                        bottomLeft:
                            Radius.circular(size * ((100.0 - ratio) / 100)),
                        bottomRight:
                            Radius.circular(size * ((100.0 - ratio) / 100)),
                      ),
                      color: get_color((100.0 - ratio))),
                ),
              ),
            ]),
            Column(
              children: [
                SizedBox(
                  height: 10,
                ),
                Container(
                  width: 30,
                  height: size * (ratio / 100) - 20,
                  decoration: BoxDecoration(
                    color: get_color(ratio),
                  ),
                ),
              ],
            ),
            Container(
              width: 30,
              height: size * (ratio / 100),
              decoration: BoxDecoration(
                borderRadius: BorderRadius.only(
                    topRight: Radius.circular(size * (ratio / 100)),
                    bottomRight: Radius.circular(size * (ratio / 100))),
                color: get_color(ratio),
              ),
            ),
          ],
        ),
      ),
    ]);
  }
}

Color get_color(double ratio) {
  if (ratio <= 30) {
    return Colors.green;
  } else if (ratio > 30 && ratio <= 70) {
    return Colors.yellow;
  } else {
    return Colors.red;
  }
}

this is output from my code ...i need to know how can i get the arrow shape

enter image description here


Solution

  • I am using CustomPaint for this. Run on dartPad, you can play offset, that will improve the ui.

    Painter Class

    class SankyPaint extends CustomPainter {
      @override
      void paint(Canvas canvas, Size size) {
        Paint paint = Paint()..color = Colors.blue;
        final double padding = size.height * .05;
    
        //top arrow
        Path greenArrowPath = Path()
          ..moveTo(size.width * .4, padding * 2)
          ..lineTo(size.width * .75, padding * 2)
          ..lineTo(size.width * .75, padding / 2) //top most
          ..lineTo(size.width * .9, padding * 4) // arrow pin
          ..lineTo(size.width * .75, padding * 7.5) //bottom most
          ..lineTo(size.width * .75, padding * 6)
          ..lineTo(size.width * .4, padding * 6);
    
        canvas.drawPath(greenArrowPath, paint..color = Colors.green);
    
        Path downwardPath = Path()
          ..moveTo(
            size.width * .4,
            size.height * .45,
          )
          ..lineTo(size.width * .75, size.height * .45)
          ..quadraticBezierTo(
            //top curve
            size.width * .9,
            size.height * .45,
            size.width * .9,
            size.height * .6,
          )
          ..lineTo(size.width * .9, size.height * .8)
          ..lineTo(size.width * .95, size.height * .8) //most left
          ..lineTo(size.width * .85, size.height * .93) //bottom pin
          ..lineTo(size.width * .75, size.height * .8)
          ..lineTo(size.width * .8, size.height * .8)
          ..lineTo(size.width * .8, size.height * .6)
          ..quadraticBezierTo(
            size.width * .8,
            size.height * .55,
            size.width * .75,
            size.height * .55,
          )
          ..lineTo(
            size.width * .4,
            size.height * .55,
          );
    
        canvas.drawPath(downwardPath, paint..color = Colors.orange);
    
        //left blue  rect
        canvas.drawRect(
          Rect.fromLTRB(
            padding,
            padding * 2,
            size.width * .4,
            padding + size.height * .55,
          ),
          paint..color = Colors.blue,
        );
      }
    
      @override
      bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
    }
    

    Use case

          SizedBox(
                width: 500,
                height: 500,
                child: CustomPaint(
                  painter: SankyPaint(),
                ),
              ),
    

    image