Flutter simply implements browser H5 particle animation

We have all the cool particle animations that H5 has, and flutter wants to have.

1. Old rule: Picture first!

2. Analysis of general ideas

1. Consider drawing dots first

As the opportunity creates corresponding points on the screen, the points will move by themselves, and the x and y axes will move at random speeds

When a point hits an edge, the velocity changes direction

2. Draw lines

A point is connected to other points within a certain distance, and the farther the distance, the less transparent the color

There should be a maximum number of connections

3. Mouse movement

The point where the mouse drops is connected to the point at a certain distance around it

3. Concrete implementation classes

1. Mouse listening event: MouseRegion

2. Redraw the control: CustomPainter

3. Customize view-related attributes

 LiziConfig({
    Key key,
    @required this.context,
    this.vx = 4.// Point x velocity, positive is right, negative is left
    this.vy = 4.// Penalty y speed
    this.radius = 2./ / some radius
    this.count = 100./ / point number
    this.color = const Color.fromRGBO(121.162.185.1.0),/ / some color
    this.stroke = const Color.fromRGBO(130.255.255.1.0),// Line color
    this.dist = 100.// Point adsorption distance
    this.eDist = 130.// Mouse adsorption distance
    this.maxConn = 10.// Maximum number of point-to-point connections
  }) : super(key: key);
Copy the code

4. Point related attributes

class Point{
  double x;/ / the x coordinate
  double y;/ / y coordinates
  double vx;// X-axis moving speed
  double vy;// Y-axis moving speed
  int conNum;// Number of connections
  Point(this.x, this.y, this.vx, this.vy,this.conNum);
}
Copy the code

4. Detailed code

1. Draw the different points first

///Coordinates of the initialization point
for (int i = 0; i < count; i++) {
      Point point=new Point(
          Random().nextDouble()*MediaQuery.of(contextO).size.width,
          Random().nextDouble()*MediaQuery.of(contextO).size.height,
          vx / 2 - Random().nextDouble() * vx,
          vy / 2 - Random().nextDouble() * vy,0);
      points.add(point);
    }

  @override
  void paint(Canvas canvas, Size sizes) {
    ///Draw some
    for (int i = 0; i < points.length; i++) { canvas.drawCircle(Offset(points[i].x, points[i].y), radius.toDouble(),_paintPoint); }}Copy the code

2. Moving point

///Timer to change point position
const oneSec = const Duration(milliseconds: 40); // The interval is 1 second
    qrtimer = new Timer.periodic(oneSec, (timer) {
      _drawPoint();
    });

///Moving point
  void _drawPoint() {
      setState(() {
        if(points.isNotEmpty) {
          for (int i = 0; i < count; i++) {
            _borderPoint(points[i]);
            points[i].conNum=0; }}}); }///Boundary processing
  void _borderPoint(Point p) {
    Size size=MediaQuery.of(context).size;
    if(p.x<=0||p.x>=size.width){
      p.vx=-p.vx;
      p.x+=p.vx;
    }else if(p.y<=0||p.y>=size.height){
      p.vy = -p.vy;
      p.y += p.vy;
    }else{ p.x=p.x+p.vx; p.y=p.y+p.vy; }}Copy the code

3. Draw lines

 for (int i = 0; i < points.length; i++) {
      for (int j = 0; j < points.length; j++) {
        if(i! =j){///If it's not the same point
          ///Figure out the distance between the two points
          double dx=points[i].x-points[j].x;
          double dy=points[i].y-points[j].y;
          double distp=sqrt(dx*dx+dy*dy);
          // print(" distp.tostring () ");

          /// If the distance between two points is less than the adsorption distance and the maximum connection number, a line is drawn
          if(distp <= dist && points[i].conNum <maxConn){
              points[i].conNum++;
              _paintLine.strokeWidth=0.5-distp/dist;
              _paintLine.color=Color.fromRGBO(stroke.red, stroke.green, stroke.blue, 1-distp/dist);

              canvas.drawLine(Offset(points[i].x, points[i].y), Offset(points[j].x, points[j].y), _paintLine);
          }

          ///Mouse events
          if(mouseY>0&&mouseX>0) {double dx=points[i].x-mouseX;
            double dy=points[i].y-mouseY;
            double distp=sqrt(dx*dx+dy*dy);
            /// When the mouse adsorption distance is accelerated, directly change the x and Y values of the point to achieve the acceleration effect
            if(distp > dist && distp <= eDist){
              points[i].x = points[i].x + (mouseX - points[i].x) / 20;
              points[i].y = points[i].y + (mouseY - points[i].y) / 20;
            }
            if(distp <= eDist){
              _paintMouseLine.color=Color.fromRGBO(stroke.red, stroke.green, stroke.blue, 1-distp/eDist);
              canvas.drawLine(Offset(points[i].x, points[i].y), Offset(mouseX, mouseY), _paintMouseLine);
            }
          }
        }
      }
    }
Copy the code

4. Mouse events

@override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
      child:  CustomPaint(
        child: MouseRegion(
          onEnter: (event){
            / / print (" enter the x: ${event. Position. Dx} y: ${event. Position. Dy} ");
            _mouseEvent(event.position.dx,event.position.dy);
          },
          onExit: (event){
            //print("onExit:${event.position.dx} y:${event.position.dy}");
            _mouseEvent(- 1.- 1);
          },
          onHover: (event){
            / / print (" mobile x: ${event. Position. Dx} y: ${event. Position. Dy} ");
            _mouseEvent(event.position.dx,event.position.dy);
          },
        ),
        painter: PaintLizi(
            this.radius, this.count, this.color, this.stroke,this.maxConn,this.dist,points,this.mouseX,this.mouseY,this.eDist),
      ),
    );
  }

  ///Mouse events
  void _mouseEvent(double x,double y){
    setState(() {
      mouseX=x;
      mouseY=y;
      Size size=MediaQuery.of(context).size;
      if(mouseX>=size.width- 10||mouseX<=10){
        mouseX=- 1;
      }
      if(mouseY>=size.height- 10||mouseY<=10){
        mouseY=- 1; }}); }Copy the code

5. Problems encountered

Problem 1: MouseRegion wraps CustomPaint. The listening event is invalid as follows

///Listen event failure
return MouseRegion(
      onEnter: (event){
        
      },
      child: CustomPaint(
        painter: PaintLizi(
            this.radius, this.count, this.color, this.stroke,this.maxConn,this.dist,points,this.mouseX,this.mouseY,this.eDist),
          )
    );


///The correct method MouseRegion is the child of CustomPaint
CustomPaint(
        child: MouseRegion(
          onEnter: (event){
            / / print (" enter the x: ${event. Position. Dx} y: ${event. Position. Dy} ");
            _mouseEvent(event.position.dx,event.position.dy);
          },
          onExit: (event){
            //print("onExit:${event.position.dx} y:${event.position.dy}");
            _mouseEvent(- 1.- 1);
          },
          onHover: (event){
            / / print (" mobile x: ${event. Position. Dx} y: ${event. Position. Dy} ");
            _mouseEvent(event.position.dx,event.position.dy);
          },
        ),
        painter: PaintLizi(
            this.radius, this.count, this.color, this.stroke,this.maxConn,this.dist,points,this.mouseX,this.mouseY,this.eDist),
      ),
Copy the code

Problem 2: onExit: (event){}

The mouse remove event is not called back when the mouse moves out of the browser.