I have ported my simulation from Java to vanilla Javascript. The most important aim was to keep the sum of all energies constant. I have this:

**simulation.js**

    var Configuration = {
        PIXELS_PER_UNIT_LENGTH: 10.0,
        FORCE_CONSTANT: 500.0,
        SLEEP_TIME: 10,
        TIME_STEP: 0.01,
        MINIMUM_PARTICLE_MASS: 10.0,
        MAXIMUM_PARTICLE_MASS: 30.0,
        MAXIMUM_INITIAL_VELOCITY: 40.0,
        DEFAULT_NUMBER_OF_PARTICLES: 10
    };
    
    function Particle(mass, radius) {
        this.mass = mass;
        this.radius = radius;
        this.x = 0.0;
        this.y = 0.0;
        this.velocityX = 0.0;
        this.velocityY = 0.0;
    }
    
    Particle.prototype.getMass = function() {
        return this.mass;
    };
    
    Particle.prototype.getX = function() {
        return this.x;
    };
    
    Particle.prototype.getY = function() {
        return this.y;
    };
    
    Particle.prototype.getVelocityX = function() {
        return this.velocityX;
    };
    
    Particle.prototype.getVelocityY = function() {
        return this.velocityY;
    };
    
    Particle.prototype.setX = function(x) {
        this.x = x;
    };
    
    Particle.prototype.setY = function(y) {
        this.y = y;
    };
    
    Particle.prototype.setVelocityX = function(velocityX) {
        this.velocityX = velocityX;
    };
    
    Particle.prototype.setVelocityY = function(velocityY) {
        this.velocityY = velocityY;
    };
    
    Particle.prototype.getSpeed = function() {
        var vxSquared = this.velocityX * this.velocityX;
        var vySquared = this.velocityY * this.velocityY;
        return Math.sqrt(vxSquared + vySquared);
    };
    
    Particle.prototype.getDistance = function(other) {
        var dx = this.x - other.x;
        var dy = this.y - other.y;
        return Math.sqrt(dx * dx + dy * dy);
    };
    
    Particle.prototype.getKineticEnergy = function() {
        var speed = this.getSpeed();
        return 0.5 * this.mass * speed * speed;
    };
    
    Particle.prototype.getRadius = function() {
        return this.radius;
    };
    
    function getForce(particle1, particle2) {
        var distance = particle1.getDistance(particle2);
        var mass1 = particle1.getMass();
        var mass2 = particle2.getMass();
        return Configuration.FORCE_CONSTANT * mass1 * mass2 / (distance * distance);
    }
    
    function getForceVector(particle1, particle2) {
        var vectorLength = getForce(particle1, particle2);
        var dx = particle1.getX() - particle2.getX();
        var dy = particle1.getY() - particle2.getY();
        var angle = Math.atan2(dy, dx);
        var xComponent = vectorLength * Math.cos(angle);
        var yComponent = vectorLength * Math.sin(angle);
        return new Vector(xComponent, yComponent);
    }
    
    function getPotentialEnergy(particle1, particle2) {
        var mass1 = particle1.getMass();
        var mass2 = particle2.getMass();
        var distance = particle1.getDistance(particle2);
        return Configuration.FORCE_CONSTANT * mass1 * mass2 / distance;
    }
    
    function ParticleRenderer(particle, color, canvasContext) {
        this.particle = particle;
        this.color = color;
        this.canvasContext = canvasContext;
    }
    
    ParticleRenderer.prototype.draw = function() {
        var effectiveX = this.particle.getX() * Configuration.PIXELS_PER_UNIT_LENGTH;
        var effectiveY = this.particle.getY() * Configuration.PIXELS_PER_UNIT_LENGTH;
        
        this.canvasContext.fillStyle = this.color;
        this.canvasContext.beginPath();
        this.canvasContext.arc(effectiveX, 
                               effectiveY, 
                               this.particle.getRadius() * 
                                       Configuration.PIXELS_PER_UNIT_LENGTH, 
                               0, 
                               2 * Math.PI, 
                               false);
        this.canvasContext.fill();
    };
    
    function Vector(x, y) {
        this.x = x;
        this.y = y;
    }
    
    Vector.prototype.getX = function() {
        return this.x;
    };
    
    Vector.prototype.getY = function() {
        return this.y;
    };
    
    Vector.prototype.plus = function(other) {
        return new Vector(this.x + other.x, this.y + other.y);
    };
    
    Vector.prototype.multiply = function(factor) {
        return new Vector(this.x * factor, this.y * factor);
    };
    
    function SimulationEngine(canvasContext, 
                              canvasElement,
                              particles,
                              renderers,
                              timeStep,
                              worldWidth,
                              worldHeight,
                              sleepTime) {
        this.canvasContext            = canvasContext;
        this.canvasElement            = canvasElement;
        this.particles                = particles;
        this.renderers                = renderers;
        this.timeStep                 = timeStep;
        this.totalEnergy              = null;
        this.worldWidth               = worldWidth;
        this.worldHeight              = worldHeight;
        this.sleepTime                = sleepTime;
        this.exit                     = false;
        this.pause                    = true;
        this.particleToForceVectorMap = {};
    }
    
    SimulationEngine.prototype.togglePause = function() {
        this.pause = !this.pause;
    };
    
    SimulationEngine.prototype.run = function() {
        this.redraw();
        this.totalEnergy = this.computeTotalEnergy();
        var self = this;
        
        setInterval(function() {
            if (!self.pause) {
                self.performStep();
                self.redraw();
            }
        }, this.sleepTime);
    };
    
    SimulationEngine.prototype.performStep = function() {
        this.computeForceVectors();
        this.updateParticleVelocities();
        this.moveParticles();
        this.resolveWorldBorderCollisions();
        this.normalizeVelocityVectors();
        this.particleToForceVectorMap = {};
    };
    
    SimulationEngine.prototype.redraw = function() {
        this.canvasContext.fillStyle = "#000";
        this.canvasContext.fillRect(0, 
                                    0, 
                                    this.canvasElement.width, 
                                    this.canvasElement.height);
        
        for (var i = 0; i < this.renderers.length; ++i) {
            var renderer = this.renderers[i];
            renderer.draw();
        }
        
        this.canvasContext.fillStyle = "#fff";
        this.font = "20px Arial";
        this.canvasContext.fillText("Total energy: " + this.computeTotalEnergy(), 
                                    0, 
                                    30);
    };
    
    SimulationEngine.prototype.computeForceVectors = function() {
        this.particleToForceVectorMap = [];
        
        for (var i = 0; i < this.particles.length; ++i) {
            var particle = this.particles[i];
            var vector = new Vector(0.0, 0.0);
            
            for (var j = 0; j < this.particles.length; ++j) {
                var otherParticle = this.particles[j];
                
                if (i === j) {
                    continue;
                }
                
                var aux = getForceVector(particle, otherParticle);
                vector = vector.plus(aux);
            }
            
            this.particleToForceVectorMap.push([particle, vector]);
        }
    };
    
    SimulationEngine.prototype.updateParticleVelocities = function() {
        for (var i = 0; i < this.particleToForceVectorMap.length; ++i) {
            var particle = this.particleToForceVectorMap[i][0];
            var vector   = this.particleToForceVectorMap[i][1];
                
            vector = vector.multiply(1.0 / particle.getMass());
            particle.setVelocityX(particle.getVelocityX() + vector.getX() * this.timeStep);
            particle.setVelocityY(particle.getVelocityY() + vector.getY() * this.timeStep);
        }
    };
    
    SimulationEngine.prototype.moveParticles = function() {
        for (var i = 0; i < this.particles.length; ++i) {
            var particle = this.particles[i];
            particle.setX(particle.getX() + particle.getVelocityX() * this.timeStep);
            particle.setY(particle.getY() + particle.getVelocityY() * this.timeStep);
        }
    };
    
    SimulationEngine.prototype.resolveWorldBorderCollisions = function() {
        for (var i = 0; i < this.particles.length; ++i) {
            var particle = this.particles[i];
            var radius = particle.getRadius();
            
            if (particle.getY() - radius <= 0.0) {
                particle.setVelocityY(-particle.getVelocityY());
            } else if (particle.getY() + radius >= this.worldHeight) {
                particle.setVelocityY(-particle.getVelocityY());
            }
            
            if (particle.getX() - radius <= 0.0) {
                particle.setVelocityX(-particle.getVelocityX());
            } else if (particle.getX() + radius >= this.worldWidth) {
                particle.setVelocityX(-particle.getVelocityX());
            }
        }
    };
    
    SimulationEngine.prototype.normalizeVelocityVectors = function() {
        var totalEnergyDelta = this.computeTotalEnergyDelta();
        var factor = this.getNormalizationFactor(totalEnergyDelta);
        
        for (var i = 0; i < this.particles.length; ++i) {
            var particle = this.particles[i];
            particle.setVelocityX(factor * particle.getVelocityX());
            particle.setVelocityY(factor * particle.getVelocityY());
        }
    };
    
    SimulationEngine.prototype.getNormalizationFactor = function(totalEnergyDelta) {
        var aux = totalEnergyDelta / this.computeTotalKineticEnergy() + 1.0;
        
        if (aux < 0.0) {
            console.log("aux: " + aux);
        }
        
        return Math.sqrt(aux);
    };
    
    SimulationEngine.prototype.computeTotalKineticEnergy = function() {
        var energy = 0.0;
        for (var i = 0; i < this.particles.length; ++i) {
            var particle = this.particles[i];
            energy += particle.getKineticEnergy();
        }
        
        return energy;
    };
    
    SimulationEngine.prototype.computeTotalEnergyDelta = function() {
        return this.totalEnergy - this.computeTotalEnergy();
    };
    
    SimulationEngine.prototype.computeTotalEnergy = function() {
        var totalEnergy = 0.0;
        
        for (var i = 0; i < this.particles.length; ++i) {
            totalEnergy += this.particles[i].getKineticEnergy();
        }
        
        for (var i = 0; i < this.particles.length; ++i) {
            var particle1 = this.particles[i];
            
            for (var j = i + 1; j < this.particles.length; ++j) {
                var particle2 = this.particles[j];
                totalEnergy += getPotentialEnergy(particle1, particle2);
            }
        }
        
        return totalEnergy;
    };
    
    function setCanvasDimensions(canvasElement) {
        canvasElement.width = window.innerWidth;
        canvasElement.height = window.innerHeight;
    }
    
    function createRandomParticles(number_of_particles, 
                                   worldWidth, 
                                   worldHeight,
                                   canvasContext) {
        var particleData = [];
        
        for (var i = 0; i < number_of_particles; ++i) {
            particleData.push(createRandomParticleData(worldWidth, 
                                                       worldHeight, 
                                                       canvasContext));
        }
        
        return particleData;
    }
    
    function getRandomColor() {
        var letters = "0123456789abcdef";
        var color = "#";
        
        for (var i = 0; i < 6; ++i) {
            color += letters[Math.floor(Math.random() * 16)];
        }
        
        return color;
    }
    
    function createRandomParticleData(worldWidth, worldHeight, canvasContext) {
        var mass = Configuration.MINIMUM_PARTICLE_MASS + 
                  (Configuration.MAXIMUM_PARTICLE_MASS - Configuration.MINIMUM_PARTICLE_MASS) 
                 * Math.random();
        var radius = mass / Configuration.PIXELS_PER_UNIT_LENGTH;
        var particle = new Particle(mass, radius);
        particle.setX(worldWidth * Math.random());
        particle.setY(worldHeight * Math.random());
        particle.setVelocityX(Configuration.MAXIMUM_INITIAL_VELOCITY * Math.random());
        particle.setVelocityY(Configuration.MAXIMUM_INITIAL_VELOCITY * Math.random());
        var color = getRandomColor();
        var renderer = new ParticleRenderer(particle, color, canvasContext);
        return [particle, renderer];
    }
    
    function extractParticles(particleData) {
        particles = [];
        
        for (var i = 0; i < particleData.length; ++i) {
            particles.push(particleData[i][0]);
        }
        
        return particles;
    }
    
    function extractRenderers(particleData) {
        particles = [];
        
        for (var i = 0; i < particleData.length; ++i) {
            particles.push(particleData[i][1]);
        }
        
        return particles;
    }
    
    function main() {
        var canvasElement = document.getElementById("cnvs");
        setCanvasDimensions(canvasElement);
        var canvasContext = canvasElement.getContext("2d");
        
        var worldWidth  = canvasElement.width  / Configuration.PIXELS_PER_UNIT_LENGTH;
        var worldHeight = canvasElement.height / Configuration.PIXELS_PER_UNIT_LENGTH;
        
        var particleData = 
                createRandomParticles(Configuration.DEFAULT_NUMBER_OF_PARTICLES,
                                      worldWidth,
                                      worldHeight,
                                      canvasContext);
                                      
        var particles = extractParticles(particleData);
        var renderers = extractRenderers(particleData);
        
        var simulationEngine = new SimulationEngine(canvasContext,
                                                    canvasElement,
                                                    particles,
                                                    renderers,
                                                    Configuration.TIME_STEP,
                                                    worldWidth,
                                                    worldHeight,
                                                    Configuration.SLEEP_TIME);
        window.onkeydown = function(e) {
            if (e.keyCode === 32) {
                simulationEngine.togglePause();
            }
        };                               
        
        simulationEngine.run();
    }
    
    main();

**index.html**

    <!DOCTYPE html>
    <html>
        <head>
            <title>simulating...</title>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
        </head>
        <body>
            <canvas id="cnvs" style="background-color: black; margin:0; padding:0;">Your browser does not support HTML5 canvases!</canvas>
            <script src="simulation.js"></script>
        </body>
    </html>

You can view the simulation [here](http://coderodde.github.io/particles/index.html). (Press Space bar for turning pause on/off.)

# Critique request

Since I am not a professional Javascript developer, it would be nice to hear the experts' opinions. Also, how should I go about making sure that the canvas occupies the entire view port?