I always want to give the end user (at least some) control of how they view and interact with data. Earlier we gave users control over gravity. Here let’s give them control over the canvas edges. Rather than having our dots bounce on the edges of the canvas, lets have them wrap across to the other side. Like in the asteroids game the ship can fly to the edge of the screen and see space wrap them back to the other side. We’ll set this up as a control exposed to the user much like gravity. Let’s call it wrap and use a boolean value to store the setting. We’ll need to add another block of conditionals for this case where we have the set already with the bouncing. I took some care with the values so that the dots leave the canvas before they make the hyper-jump to the other side. Otherwise you’d see the magic. interactive physics animations via javascript & canvas | 16.
[cc lang=”javascript”]
$(function () {
var canvas, context, width, height, x, y, radius = 25, clickX, clickY, drag = false;
var total_dots = 10;
var fps = 24;
canvas = $(“#canvas”)[0];
context = canvas.getContext(“2d”);
var dots = new Array();
var drag_i = -1;
var gravity = 0;
var friction = .98;
var bounce = -.96;
var wrap = true;
var this_dot = {};
for (var i=0; i < total_dots; i++){
createDot();
}
function createDot(x, y, r, vx, vy){
var this_dot = {
x: typeof(x) != 'undefined' ? x : Math.random()*canvas.width,
y: typeof(y) != 'undefined' ? y : Math.random()*canvas.height,
radius: typeof(r) != 'undefined' ? r : Math.random()*20+10,
vx: typeof(vx) != 'undefined' ? vx : Math.random()*30-10,
vy: typeof(vy) != 'undefined' ? vy : Math.random()*30-10
};
dots.push(this_dot);
}
draw();
$("#canvas").mousedown(function (event) {
var dx, dy, dist;
for (var i=0; i < dots.length; i++){
dx = event.pageX - this.offsetLeft - dots[i].x;
dy = event.pageY - this.offsetTop - dots[i].y;
dist = Math.sqrt(dx * dx + dy * dy);
if(dist < radius) {
drag = true;
drag_i = i
clickX = dx;
clickY = dy;
continue;
}
}
//none clicked
if (!drag) {
createDot(event.pageX - this.offsetLeft, event.pageY - this.offsetTop);
}
});
$("#canvas").mouseup(function (event) {
drag = false;
drag_i = -1;
});
$("#canvas").mousemove(function (event) {
if(drag) {
dots[drag_i].old_x = dots[drag_i].x;
dots[drag_i].old_y = dots[drag_i].y;
dots[drag_i].x = event.pageX - this.offsetLeft - clickX;
dots[drag_i].y = event.pageY - this.offsetTop - clickY;
dots[drag_i].vx = dots[drag_i].x - dots[drag_i].old_x;
dots[drag_i].vy = dots[drag_i].y - dots[drag_i].old_y;
draw();
}
});
function update(){
for (var i=0; i < dots.length; i++){
if (drag_i != i){
var this_dot = dots[i];
this_dot.vx *= friction;
this_dot.vy = this_dot.vy * friction + gravity;
this_dot.x += this_dot.vx;
this_dot.y += this_dot.vy;
if (wrap){
if (this_dot.x > canvas.width + this_dot.radius){
this_dot.x -= canvas.width + this_dot.radius*2;
}
else if(this_dot.x < 0 - this_dot.radius){
this_dot.x += canvas.width + this_dot.radius*2;
}
if (this_dot.y > canvas.height + this_dot.radius){
this_dot.y -= canvas.height + this_dot.radius*2;
}
else if(this_dot.y < 0 - this_dot.radius){
this_dot.y += canvas.height + this_dot.radius*2;
}
}
else if (!wrap) {
if (this_dot.x > canvas.width – this_dot.radius){
this_dot.x = canvas.width – this_dot.radius;
this_dot.vx = this_dot.vx * bounce;
}
else if(this_dot.x < 0 + this_dot.radius){
this_dot.x = this_dot.radius;
this_dot.vx = this_dot.vx * bounce;
}
if (this_dot.y > canvas.height – this_dot.radius){
this_dot.y = canvas.height – this_dot.radius;
this_dot.vy = this_dot.vy * bounce;
}
else if(this_dot.y < 0 + this_dot.radius){
this_dot.y = this_dot.radius;
this_dot.vy = this_dot.vy * bounce;
}
}
}
}
}
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
for (var i=0; i < dots.length; i++){
context.beginPath();
context.arc(dots[i].x, dots[i].y, dots[i].radius, 0, Math.PI * 2, false);
context.fill();
context.closePath();
}
}
setInterval(function() {
update();
draw();
}, 1000/fps);$("#gravity").click(function(){
if($("#gravity").is(':checked')){
gravity = 2;
}
else{
gravity = 0;
}
});
$("#wrap").click(function(){
if($("#wrap").is(':checked')){
wrap = true;
}
else{
wrap = false;
}
});
});
[/cc]Follow the whole Interactive Physics Animations via Javascript & Canvas series.