canvas
View Compiled
const canvas = document.getElementsByTagName("canvas")[0];

canvas.height = window.innerHeight;
canvas.width = window.innerWidth;

const c = canvas.getContext("2d");

const threshold = 30;
const mousePos = {
    x: 0,
    y: 0
};
const innerHeight = window.innerHeight;
const innerWidth = window.innerWidth;

window.addEventListener("mousemove", event => {
    mousePos.x = event.x;
    mousePos.y = event.y;
});
window.addEventListener("resize", () => {
    canvas.height = window.innerHeight;
    canvas.width = window.innerWidth;
});

function Circle(x, y, r, dx, dy) {
    this.baseR = r;
    this.r = r;
    this.x = x;
    this.y = y;
    this.dx = dx;
    this.dy = dy;
    this.isHit = false;

    this.draw = () => {
        c.beginPath();
        c.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
        c.stroke();
        c.lineWidth = 2;
        c.strokeStyle = "#333";
        c.fillStyle = "#00f";
        c.fill();
    };
    this.update = () => {
        if (
            this.x > mousePos.x - threshold &&
            this.x < mousePos.x + threshold &&
            this.y > mousePos.y - threshold &&
            this.y < mousePos.y + threshold
        ) {
            if (this.r < this.baseR * 2) {
                this.r += 1;
                if (!this.isHit) {
                    if (this.dx < 0 && mousePos.x < this.x) {
                        this.dx = this.dx * -1;
                    } else if (this.dx > 0 && mousePos.x > this.x) {
                        this.dx = this.dx * -1;
                    } else {
                        if (this.dx < 0) {
                            this.dx = this.dx - 0.5;
                        } else {
                            this.dx = this.dx + 0.5;
                        }
                    }

                    if (this.dy < 0 && mousePos.y < this.y) {
                        this.dy = this.dy * -1;
                    } else if (this.dy > 0 && mousePos.y > this.y) {
                        this.dy = this.dy * -1;
                    } else {
                        if (this.dy < 0) {
                            this.dy = this.dy - 0.5;
                        } else {
                            this.dy = this.dy + 0.5;
                        }
                    }
                }
                this.isHit = true;
            }
        } else {
            if (this.r > this.baseR) {
                this.r -= 1;
                this.isHit = false;
            }
        }

        if (this.x + this.r > window.innerWidth || this.x - this.r < 0) {
            this.dx = this.dx * -1;
        }

        if (this.y + this.r > window.innerHeight || this.y - this.r < 0) {
            this.dy = this.dy * -1;
        }

        const maxV = 6;

        if (this.dx > maxV) {
            this.dx = maxV;
        }
        if (this.dy > maxV) {
            this.dy = maxV;
        }

        this.x += this.dx;
        this.y += this.dy;

        this.draw();
    };
}

function getRndInteger(min, max) {
    return Math.floor(Math.random() * (max - min)) + min;
}
function getRndVelocity(seed) {
    let value = Math.ceil((Math.random() - 0.5) * seed);

    if (value === 0) {
        value = getRndVelocity(seed);
    }

    return value;
}

const randMax = getRndInteger(11, 20);
const baseRadius = 10;
const cirlces = [];

for (let i = 0; i < randMax; i++) {
    cirlces.push(
        new Circle(
            getRndInteger(baseRadius, innerWidth - baseRadius),
            getRndInteger(baseRadius, innerHeight - baseRadius),
            getRndInteger(baseRadius - 2, baseRadius + 2),
            getRndVelocity(4),
            getRndVelocity(3)
        )
    );
}

function animation() {
    requestAnimationFrame(animation);

    c.clearRect(0, 0, window.innerWidth, window.innerHeight);

    cirlces.forEach((circle, index) => {
        let nextCircle;
        let nextCircle2;

        if (index < cirlces.length - 1) {
            nextCircle = cirlces[index + 1];
            nextCircle2 = cirlces[index + 2];
        }
        if (nextCircle) {
            c.beginPath();
            c.moveTo(circle.x, circle.y);
            c.lineTo(nextCircle.x, nextCircle.y);
            c.stroke();
            c.closePath();
        }
        if (nextCircle2) {
            c.beginPath();
            c.moveTo(circle.x, circle.y);
            c.lineTo(nextCircle2.x, nextCircle2.y);
            c.stroke();
            c.closePath();
        }
        circle.update();
    });
}
animation();
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.