Q:

Corner Collision angles in p5.js

Summary:
In attempt to make a simple collision detection system between a moving rect and a falling circle, I would like to make it more realistic. 
Main question:
-The main thing I would like to solve is detecting when the circle Object is hitting the corner of the rect and in return having the circle bounce based off of that angle.
The Code:

var balls = [];
var obstacle;

function setup() {
  createCanvas(400, 400);
  obstacle = new Obstacle();
}

function draw() {
  background(75);
  obstacle.display();
  obstacle.update();
  
  for (var i = 0; i < balls.length; i++) {
    balls[i].display();
   if (!RectCircleColliding(balls[i], obstacle)){
        balls[i].update();
        balls[i].edges();
   }
    
    //console.log(RectCircleColliding(balls[i], obstacle));
  }
}

function mousePressed() {
  balls.push(new Ball(mouseX, mouseY));
}

function Ball(x, y) {
  this.x = x;
  this.y = y;
  this.r = 15;
  this.gravity = 0.5;
  this.velocity = 0;
  this.display = function() {
    fill(255, 0, 100);
    stroke(255);
    ellipse(this.x, this.y, this.r * 2);
  }
  this.update = function() {
    this.velocity += this.gravity;
    this.y += this.velocity;
  }
  this.edges = function() {
    if (this.y >= height - this.r) {
      this.y = height - this.r;
      this.velocity = this.velocity * -1;
      this.gravity = this.gravity * 1.1;
    }
  }
}

function Obstacle() {
  this.x = width - width;
  this.y = height / 2;
  this.w = 200;
  this.h = 25;

  this.display = function() {
    fill(0);
    stroke(255);
    rect(this.x, this.y, this.w, this.h);
  }
  
  this.update = function() {
    this.x++;
    
    if (this.x > width + this.w /2) {
       this.x = -this.w;
    }
  }
}

function RectCircleColliding(Ball, Obstacle) {
  // define obstacle borders
  var oRight = Obstacle.x + Obstacle.w;
  var oLeft = Obstacle.x;
  var oTop = Obstacle.y;
  var oBottom = Obstacle.y + Obstacle.h;

  //compare ball's position (acounting for radius) with the obstacle's border
  if (Ball.x + Ball.r > oLeft) {
    if (Ball.x - Ball.r < oRight) {
      if (Ball.y + Ball.r > oTop) {
        if (Ball.y - Ball.r < oBottom) {
          
         let oldY = Ball.y;
         Ball.y = oTop - Ball.r;
         Ball.velocity = Ball.velocity * -1;
           if (Ball.gravity < 2.0){
              Ball.gravity = Ball.gravity * 1.1;  
           } else {
             Ball.velocity = 0;
             Ball.y = oldY;
         }   
         return (true);
        } 
      }
    }
  }
    return false;
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.js"></script>

Expected output:
I would like to see the falling circles bounce off the rectangle with respect to where they are hitting on the rectangle. 
If the circles hit the corners they should bounce differently versus hitting dead center.

A:

Prerequisite
The ball's velocity must be a vector (XY components), not just a single number.

1. Determine if the circle might hit a side or a corner
Obtain the components of the vector from the center of the rectangle to the circle, and check it against the rectangle's dimensions:
// Useful temporary variables for later use
var hx = 0.5 * obstacle.w;
var hy = 0.5 * obstacle.h;
var rx = obstacle.x + hx;
var ry = obstacle.y + hy;

// displacement vector
var dx = ball.x - rx;
var dy = ball.y - ry;

// signs
var sx = dx < -hx ? -1 : (dx > hx ? 1 : 0);
var sy = dy < -hy ? -1 : (dy > hy ? 1 : 0);

If both sx, sy are non-zero, the ball might hit a corner, otherwise it might hit a side.

2. Determine whether the circle collides
Multiply each sign by the respective half-dimension:
// displacement vector from the nearest point on the rectangle
var tx = sx * (Math.abs(dx) - hx);
var ty = sy * (Math.abs(dy) - hy);

// distance from p to the center of the circle
var dc = Math.hypot(tx, ty);

if (dc <= ball.r) {
    /* they do collide */
}

3. Determine the collision normal vector
(tx, ty) are the components of the normal vector, but only if the ball's center is outside the rectangle:
// epsilon to account for numerical imprecision
const EPSILON = 1e-6;

var nx = 0, ny = 0, nl = 0;
if (sx == 0 && sy == 0) {  // center is inside
  nx = dx > 0 ? 1 : -1;
  ny = dy > 0 ? 1 : -1;
  nl = Math.hypot(nx, ny);
} else {                   // outside
  nx = tx;
  ny = ty;
  nl = dc;
}
nx /= nl;
ny /= nl;

4. Resolve any "penetration"
(No immature jokes please)
This ensures that the ball will never penetrate into the surface of the rectangle, which improves the visual quality of the collisions:
ball.x += (ball.r - dc) * nx; 
ball.y += (ball.r - dc) * ny;

5. Resolve the collision
If the circle is travelling in the direction of the normal, don't resolve the collision as the ball might stick to the surface:
// dot-product of velocity with normal
var dv = ball.vx * nx + ball.vy * ny;

if (dv >= 0.0) {
    /* exit and don't do anything else */
}

// reflect the ball's velocity in direction of the normal
ball.vx -= 2.0 * dv * nx;
ball.vy -= 2.0 * dv * ny;

Working JS snippet

const GRAVITY = 250.0;

function Ball(x, y, r) {
  this.x = x;
  this.y = y;
  this.r = r;
  this.vx = 0;
  this.vy = 0;

  this.display = function() {
    fill(255, 0, 100);
    stroke(255);
    ellipse(this.x, this.y, this.r * 2);
  }

  this.collidePage = function(b) {
    if (this.vy > 0 && this.y + this.r >= b) {
      this.y = b - this.r;
      this.vy = -this.vy;
    }
  }

  this.updatePosition = function(dt) {
    this.x += this.vx * dt;
    this.y += this.vy * dt;
  }
  this.updateVelocity = function(dt) {
    this.vy += GRAVITY * dt;
  }
}

function Obstacle(x, y, w, h) {
  this.x = x;
  this.y = y;
  this.w = w;
  this.h = h;

  this.display = function() {
    fill(0);
    stroke(255);
    rect(this.x, this.y, this.w, this.h);
  }

  this.update = function() {
    this.x++;
    if (this.x > width + this.w /2) {
      this.x = -this.w;
    }
  }
}

var balls = [];
var obstacle;

function setup() {
  createCanvas(400, 400);
  obstacle = new Obstacle(0, height / 2, 200, 25);
}

const DT = 0.05;

function draw() {
  background(75);
  obstacle.update();
  obstacle.display();
  for (var i = 0; i < balls.length; i++) {
    balls[i].updatePosition(DT);
    balls[i].collidePage(height);
    ResolveRectCircleCollision(balls[i], obstacle);
    balls[i].updateVelocity(DT);
    balls[i].display();
  }
}

function mousePressed() {
  balls.push(new Ball(mouseX, mouseY, 15));
}

const EPSILON = 1e-6;

function ResolveRectCircleCollision(ball, obstacle) {
  var hx = 0.5 * obstacle.w, hy = 0.5 * obstacle.h;
  var rx = obstacle.x + hx, ry = obstacle.y + hy;
  var dx = ball.x - rx, dy = ball.y - ry;

  var sx = dx < -hx ? -1 : (dx > hx ? 1 : 0);
  var sy = dy < -hy ? -1 : (dy > hy ? 1 : 0);

  var tx = sx * (Math.abs(dx) - hx);
  var ty = sy * (Math.abs(dy) - hy);
  var dc = Math.hypot(tx, ty);
  if (dc > ball.r)
    return false;

  var nx = 0, ny = 0, nl = 0;
  if (sx == 0 && sy == 0) {
    nx = dx > 0 ? 1 : -1; ny = dy > 0 ? 1 : -1;
    nl = Math.hypot(nx, ny);
  } else {
    nx = tx; ny = ty;
    nl = dc;
  }
  nx /= nl; ny /= nl;

  ball.x += (ball.r - dc) * nx; ball.y += (ball.r - dc) * ny;

  var dv = ball.vx * nx + ball.vy * ny;
  if (dv >= 0.0)
    return false;
  ball.vx -= 2.0 * dv * nx; ball.vy -= 2.0 * dv * ny;

  return true;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>

A:

I'll try to present a solution, which keeps as may from the original code as possible. The solution intends to be a evolution of the code presented in the question.
Add a sideward movement (selv.sideV) to the Ball object, which is initialized by 0: 
function Ball(x, y) {
    this.x = x;
    this.y = y;
    this.r = 15;
    this.gravity = 0.5;
    this.velocity = 0;
    this.sideV = 0 

    // ...
}

Move the ball to the side in update, by the sideward movement and reduce the sideward movment:
this.update = function() {
    this.velocity += this.gravity;
    this.y += this.velocity;
    this.x += this.sideV;
    this.sideV *= 0.98;
}

Create function for an intersection test of 2 boxes: 
function IsectRectRect(l1, r1, t1, b1, l2, r2, t2, b2) {
    return l1 < r2 && l2 < r1 && t1 < b2 && t2 < b1;
}

And a function which can calculate the refection vector R of an incident vector V to a the normal vector of surface N (the reflection like a billiard ball):
function reflect( V, N ) {
    R = V.copy().sub(N.copy().mult(2.0 * V.dot(N)));
    return R;
}

When the Ball collides with the Obstacle, then you've to handle 3 situations.

The Ball fully hits the top of the Obstacle: IsectRectRect(oL, oR, oT, oB, Ball.x, Ball.x, bT, bB)
The Ball hits the left edge of the Obstacle: IsectRectRect(oL, oL, oT, oB, bL, bR, bT, bB)
The Ball hits the right edge of the Obstacle: IsectRectRect(oR, oR, oT, oB, bL, bR, bT, bB)

In each case the normal vector for the reflection has to be calculated. This is the vector from either the top or the edge of the Obstacle to the center of the Ball.
Use the function reflect to bounce the Ball on the Obstacle:
function RectCircleColliding(Ball, Obstacle) {
    let oL = Obstacle.x;
    let oR = Obstacle.x + Obstacle.w;
    let oT = Obstacle.y;
    let oB = Obstacle.y + Obstacle.h;
    let bL = Ball.x - Ball.r;
    let bR = Ball.x + Ball.r;
    let bT = Ball.y - Ball.r;
    let bB = Ball.y + Ball.r;

    let isect = false;
    let hitDir = createVector(0, 1);
    if ( IsectRectRect(oL, oR, oT, oB, Ball.x, Ball.x, bT, bB) ) {
        isect = true;
    } else if ( IsectRectRect(oL, oL, oT, oB, bL, bR, bT, bB) ) {
        hitDir = createVector(Ball.x, Ball.y).sub(createVector(oL, oT))
        isect = hitDir.mag() < Ball.r;
    } else if ( IsectRectRect(oR, oR, oT, oB, bL, bR, bT, bB) ) {
        hitDir = createVector(Ball.x, Ball.y).sub(createVector(oR, oT))
        isect = hitDir.mag() < Ball.r;
    }

    if ( isect ) {
        let dir = createVector(Ball.sideV, Ball.velocity);
        R = reflect(dir, hitDir.normalize());
        Ball.velocity = R.y;
        Ball.sideV = R.x;
        let oldY = Ball.y;
        Ball.y = oT - Ball.r;
        if (Ball.gravity < 2.0){
            Ball.gravity = Ball.gravity * 1.1;  
        } else {
            Ball.velocity = 0;
            Ball.y = oldY;
        }   
        return true;
    }
    return false;
}

See the example, where I applied the changes to your original code:

var balls = [];
var obstacle;

function setup() {
  createCanvas(400, 400);
  obstacle = new Obstacle();
}

function draw() {
  background(75);
  obstacle.display();
  obstacle.update();

  for (var i = 0; i < balls.length; i++) {
    balls[i].display();
      if (!RectCircleColliding(balls[i], obstacle)){
        balls[i].update();
        balls[i].edges();
      }

    //console.log(RectCircleColliding(balls[i], obstacle));
  }
}

function mousePressed() {
  balls.push(new Ball(mouseX, mouseY));
}

function Ball(x, y) {
  this.x = x;
  this.y = y;
  this.r = 15;
  this.gravity = 0.5;
  this.velocity = 0;
  this.sideV = 0 
  this.display = function() {
    fill(255, 0, 100);
    stroke(255);
    ellipse(this.x, this.y, this.r * 2);
  }
  this.update = function() {
      this.velocity += this.gravity;
      this.y += this.velocity;
      this.x += this.sideV;
      this.sideV *= 0.98;
  }
  this.edges = function() {
    if (this.y >= height - this.r) {
      this.y = height - this.r;
      this.velocity = this.velocity * -1;
      this.gravity = this.gravity * 1.1;
    }
  }
}

function Obstacle() {
  this.x = width - width;
  this.y = height / 2;
  this.w = 200;
  this.h = 25;

  this.display = function() {
    fill(0);
    stroke(255);
    rect(this.x, this.y, this.w, this.h);
  }

  this.update = function() {
    this.x++;

    if (this.x > width + this.w /2) {
       this.x = -this.w;
    }
  }
}

function IsectRectRect(l1, r1, t1, b1, l2, r2, t2, b2) {
    return l1 < r2 && l2 < r1 && t1 < b2 && t2 < b1;
}

function reflect( V, N ) {
    R = V.copy().sub(N.copy().mult(2.0 * V.dot(N)));
    return R;
}

function RectCircleColliding(Ball, Obstacle) {
    let oL = Obstacle.x;
    let oR = Obstacle.x + Obstacle.w;
    let oT = Obstacle.y;
    let oB = Obstacle.y + Obstacle.h;
    let bL = Ball.x - Ball.r;
    let bR = Ball.x + Ball.r;
    let bT = Ball.y - Ball.r;
    let bB = Ball.y + Ball.r;

    let isect = false;
    let hitDir = createVector(0, 1);
    if ( IsectRectRect(oL, oR, oT, oB, Ball.x, Ball.x, bT, bB) ) {
        isect = true;
    } else if ( IsectRectRect(oL, oL, oT, oB, bL, bR, bT, bB) ) {
        hitDir = createVector(Ball.x, Ball.y).sub(createVector(oL, oT))
        isect = hitDir.mag() < Ball.r;
    } else if ( IsectRectRect(oR, oR, oT, oB, bL, bR, bT, bB) ) {
        hitDir = createVector(Ball.x, Ball.y).sub(createVector(oR, oT))
        isect = hitDir.mag() < Ball.r;
    }

    if ( isect ) {
        let dir = createVector(Ball.sideV, Ball.velocity);
        R = reflect(dir, hitDir.normalize());
        Ball.velocity = R.y;
        Ball.sideV = R.x;
        let oldY = Ball.y;
        Ball.y = oT - Ball.r;
        if (Ball.gravity < 2.0){
            Ball.gravity = Ball.gravity * 1.1;  
        } else {
            Ball.velocity = 0;
            Ball.y = oldY;
        }   
        return true;
    }
    return false;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.js"></script>

