I can’t adjust collision and gravity in canvas

I am trying to implement a fairly simple merge fruit game using canvas, in which the balls must fall into a glass, and if the balls are the same size, they touch each other. They turn into one big ball. But there is a problem with gravity and collision. Over time, they just start to squeeze into each other. Most likely, this is due to gravity, which attracts them until they touch the floor. But I do not know how to manipulate her. And do not lose gravity in a collision. Because it is necessary that the balls still have the opportunity to roll over each other. Please help me!

Sorry if the code looks clumsy. I just tried everything I could and eventually started getting confused in my own code.

you can check it in code pen version

https://codepen.io/njtbmhbh-the-animator/pen/wvLrmdK


  //Функция для ограничения количества кадров в секунду
       var limitLoop = function (fn, fps) {
     
                // Use var then = Date.now(); if you
                // don't care about targetting < IE9
                var then = new Date().getTime();
            
                // custom fps, otherwise fallback to 60
                fps = fps || 60;
                var interval = 1000 / fps;
             
                return (function loop(time){
                    requestAnimationFrame(loop);
             
                    // again, Date.now() if it's available
                    var now = new Date().getTime();
                    var delta = now - then;
             
                    if (delta > interval) {
                        // Update time
                        // now - (delta % interval) is an improvement over just 
                        // using then = now, which can end up lowering overall fps
                        then = now - (delta % interval);
             
                        // call the fn
                        fn();
                    }
                }(0));
            };



            //Полезные функции

            function randomIntFromRange(min,max) {
                return Math.floor(Math.random() * (max - min + 1) + min);
            }

            function frameCheck(ball){
              if(ball.y + ball.radius  + ball.velocity.y > canvas.height){
                ball.velocity.y = -ball.velocity.y * 0.6;
              } else {
                if(!ball.colideState){
                ball.velocity.y += gravity;
            }
              }
              
              if(ball.x + ball.radius + ball.velocity.x >= canvas.width || ball.x - ball.radius + ball.velocity.x<= 0){
                ball.velocity.x = -ball.velocity.x;
              }
            }


            function getDistance(x1, y1, x2, y2){
              let xDistance = x2 - x1;
              let yDistance = y2 - y1;

              return Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2))
            }
            
            //Утилита для рассчета коллизии

            /**
     * Rotates coordinate system for velocities
     *
     * Takes velocities and alters them as if the coordinate system they're on was rotated
     *
     * @param  Object | velocity | The velocity of an individual particle
     * @param  Float  | angle    | The angle of collision between two objects in radians
     * @return Object | The altered x and y velocities after the coordinate system has been rotated
     */

    function rotate(velocity, angle) {
      const rotatedVelocities = {
          x: velocity.x * Math.cos(angle) - velocity.y * Math.sin(angle),
          y: velocity.x * Math.sin(angle) + velocity.y * Math.cos(angle)
      };

      return rotatedVelocities;
    }

    /**
    * Swaps out two colliding particles' x and y velocities after running through
    * an elastic collision reaction equation
    *
    * @param  Object | particle      | A particle object with x and y coordinates, plus velocity
    * @param  Object | otherParticle | A particle object with x and y coordinates, plus velocity
    * @return Null | Does not return a value
    */

    function resolveCollision(particle, otherParticle) {
      const xVelocityDiff = particle.velocity.x - otherParticle.velocity.x;
      const yVelocityDiff = particle.velocity.y - otherParticle.velocity.y;

      const xDist = otherParticle.x - particle.x;
      const yDist = otherParticle.y - particle.y;

      // Prevent accidental overlap of particles
      if (xVelocityDiff * xDist + yVelocityDiff * yDist >= 0) {

          // Grab angle between the two colliding particles
          const angle = -Math.atan2(otherParticle.y - particle.y, otherParticle.x - particle.x);

          // Store mass in var for better readability in collision equation
          const m1 = particle.mass;
          const m2 = otherParticle.mass;

          // Velocity before equation
          const u1 = rotate(particle.velocity, angle);
          const u2 = rotate(otherParticle.velocity, angle);

          // Velocity after 1d collision equation
          const v1 = { x: u1.x * (m1 - m2) / (m1 + m2) + u2.x * 2 * m2 / (m1 + m2), y: u1.y };
          const v2 = { x: u2.x * (m1 - m2) / (m1 + m2) + u1.x * 2 * m2 / (m1 + m2), y: u2.y };

          // Final velocity after rotating axis back to original location
          const vFinal1 = rotate(v1, -angle);
          const vFinal2 = rotate(v2, -angle);
          if(particle.y != particle.pastY){
          // Swap particle velocities for realistic bounce effect
          if(particle.y + particle.radius  + particle.velocity.y < canvas.height){
            particle.velocity.y = vFinal2.y * 0.8;
          }
          
          if(otherParticle.y + otherParticle.radius  + otherParticle.velocity.y < canvas.height){
            otherParticle.velocity.y = vFinal2.y * 0.8;
          }
        }
          if(particle.x + particle.radius + particle.velocity.x < canvas.width && particle.x - particle.radius + particle.velocity.x > 0){
            particle.velocity.x = vFinal1.x ;
          } else {}

         if(otherParticle.x + otherParticle.radius + otherParticle.velocity.x < canvas.width && otherParticle.x - otherParticle.radius + otherParticle.velocity.x > 0){
           otherParticle.velocity.x = vFinal2.x ;
         } else {}





      }
    }




            //game
            const canvas = document.querySelector('canvas')
            const c = canvas.getContext('2d');
            canvas.height = window.screen.height - window.screen.height * 0.6; // window heigh - 20 percents
            canvas.width = document.querySelector('.container').clientWidth * 0.5; // container width
            let objects = []
       //Массив шариков
            let  ballsTemplates = {
              1:{
                y: 50,
                direction: 0,
                radius: 20,
                color: "blue",
                level: 1
              },
              2:{
                y: 50,
                direction: 0,
                radius: 25,
                color: "green",
                level: 2
              },
              3:{
                y: 50,
                direction: 0,
                radius: 30,
                color: "black",
                level: 3
              },
              4:{
                y: 50,
                direction: 0,
                radius: 35,
                color: "red",
                level: 4
              },
            }


            const gravity = 0.5;
            //objects
            class Ball {
                constructor(x, y, dx, dy, bp, radius, color, level) {
                  this.x = x
                  this.y = y
                  this.pastX = 0
                  this.pastY = 0
                  this.colideState = false;
                  this.velocity = {
                    x: dx,
                    y: dy
                  }
                  this.level = level
                  this.bp = bp;
                  this.radius = radius
                  this.color = color
                  this.mass = 1;
                }
              
                draw() {
                  c.beginPath()
                  c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false)
                  c.fillStyle = this.color
                  c.fill()
                  c.closePath()
                }
              
                update = objects => {

                  this.pastX = this.x;
                      this.pastY = this.y

                  this.y += this.velocity.y
                  this.velocity.x = this.velocity.x * 0.99;
                  this.x += this.velocity.x;
                  //Не даём шарику возможности упать за границы карты
                  frameCheck(this);

                  for (let i=0; i < objects.length; i++){
                    if(objects[i]){
                    if(this === objects[i]) continue;
                    if(getDistance(this.x, this.y, objects[i].x, objects[i].y) - (this.radius + objects[i].radius) < -0.8){
                      
                      //Вызов функции коллизии
                      resolveCollision(this, objects[i]);
                      

                     
                      let lvl = this.level;
                      let lvl2 = objects[i].level;
                      if(lvl === lvl2){
                        if(lvl < 4){
                        let x = (this.x + objects[i].x) / 2
                        let y = (this.y + objects[i].y) / 2

                        this.x = x;
                        this.y = y;
                        this.direction = ballsTemplates[lvl + 1].direction;
                        this.dy = 0.5;
                        this.bp =  0.9;
                        this.radius =  ballsTemplates[lvl + 1].radius;
                        this.color =  ballsTemplates[lvl + 1].color;
                        this.level =  ballsTemplates[lvl + 1].level;
                        
                      delete objects[i];
                    }
                      }
                      
                        if(this.y == this.pastY){
                      this.colideState = true;
                    }
                      } else {
                      this.colideState = false;
                      }

                }
            }

              this.draw()
            
                }
              }


      //функция для создания шарика по клику
              canvas.addEventListener('mouseup', function (event) {
               // Implementation
               const rect = canvas.getBoundingClientRect();
               const computedStyle = getComputedStyle(canvas);
               const borderLeftWidth = parseInt(computedStyle.borderLeftWidth, 10);
               const borderTopWidth = parseInt(computedStyle.borderTopWidth, 10);
               let numb = randomIntFromRange(1,4);
               let x = event.clientX - rect.left - borderLeftWidth
               let y = event.clientY - rect.top - borderTopWidth

               let radius = 55;

                let dxWerid = 5;

               if(x + radius * 2 > canvas.width){
                x = canvas.width - radius;
               } else if (x - radius * 2 < canvas.width){
                x = x + radius;
               }

              let ball = new Ball( x , y, ballsTemplates[numb].direction , 1 , 0.9,ballsTemplates[numb].radius, ballsTemplates[numb].color, ballsTemplates[numb].level)
            
               objects.push(ball)

                
              });



            const animate = async () => {
                c.fillStyle="white"
              
                c.fillRect(0, 0, canvas.width, canvas.height) //background :/
                 objects.forEach(object => {
                  object.update(objects)
                 })
                
            }
        
            
            limitLoop(animate, 60);

<!-- language: lang-css -->




    .gameScreen {
        border: 10px solid white;
        background-color: black;
    }

<!-- language: lang-html -->

    <body>
        <noscript>You need to enable JavaScript to run this app.</noscript>
        <div id="root"><div class="container" height="200" width="332"><div><div><canvas class="gameScreen"></canvas> <- С попощью левой кнопки мыши заспавни много шариков. Чтобы было несколько рядок</div></div></div></div>
      

    </body>```





I tried to implement a mechanic in which the balls push each other out when they collide. But it really spoils the physics and the external component. I'm trying to figure out how to do the right thing here.