A short demo of how HTML5 can be used for visualizing simulations.
This simulation of the motion of multiple bodies makes it obvious why in multi-star solar systems there are no stable planetary trajectories. Not very convenient for life …
Solar radiation on the planets:
window.requestAnimFrame = (function(callback){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback){ window.setTimeout(callback, 1000 / 30); }; })();
var objects = [ {position:{x:350, y:300}, speed: {x:0.0,y:0.5}, mass:1000, radius:10, style:"#FFFF00"}, {position:{x:450, y:300}, speed: {x:0.0,y:-0.5}, mass:1000, radius:10, style:"#FFFF00"}, {position:{x:400, y:200}, speed: {x:0.10,y:-0.01}, mass:10, radius:3, style:"#0000ff"}, {position:{x:290, y:400}, speed: {x:-0.05,y:-0.15}, mass:15, radius:4, style:"#aa44cc"}, {position:{x:550, y:300}, speed: {x:-0.04,y:0.15}, mass:20, radius:5, style:"#88cc99"}, ];
var MAX_TRAIL_LENGTH = 50; var trails = [[], [], [], [], []]; var frameCounter = 0;
function subtract(a, b) { return {x: a.x - b.x, y: a.y - b.y }; }
function add(a, b) { return { x: a.x + b.x, y: a.y + b.y }; }
function distanceSquared(a, b) { var distance = subtract(a, b); return distance.x * distance.x + distance.y * distance.y; }
function distance(a, b) { return Math.sqrt(distanceSquared(a, b)); }
function calculateGravity(obj1, obj2) { var dist = distanceSquared(obj1.position, obj2.position); var gravity = (obj1.mass * obj2.mass) / dist; return gravity / 1000000; }
function physicsCalculation() { for (index in objects) { var obj = objects[index]; for (index2 in objects) { if (index != index2) { var obj2 = objects[index2]; var gravity = calculateGravity(obj, obj2); var dx = gravity * (obj.position.x - obj2.position.x); var dy = gravity * (obj.position.y - obj2.position.y); obj.speed.x -= dx; obj.speed.y -= dy; } } } for (index in objects) { var obj = objects[index]; obj.position.x += obj.speed.x; obj.position.y += obj.speed.y; } }
function drawTrails(context) { for (index in objects) { var obj = objects[index]; var trail = trails[index]; if (frameCounter % 3 == 0) { if (trail.length > MAX_TRAIL_LENGTH) { trail.shift(); } trail.push({x: obj.position.x, y: obj.position.y}); }
if (trail.length > 1) { context.beginPath(); context.moveTo(trail[0].x, trail[0].y); for (var i = 1; i < trail.length; i++) { context.lineTo(trail[i].x,trail[i].y); } context.stroke(); } } } function drawElement(context, position, radius, color) { context.strokeStyle = "#000000"; context.fillStyle = color; context.beginPath(); context.arc(position.x,position.y,radius,0,Math.PI*2,true); context.closePath(); context.stroke(); context.fill(); } function drawMain() { var canvas = document.getElementById("myDrawing"); var context = canvas.getContext("2d"); if (clearBoard) { context.clearRect(0, 0, canvas.width, canvas.height); } physicsCalculation(); physicsCalculation(); physicsCalculation(); drawTrails(context); for (index in objects) { var obj = objects[index]; drawElement(context, obj.position, obj.radius, obj.style); } } var MAX_STATS_LENGTH = 103; var stats = [[], [], [], [], []]; function drawStats() { var height = 200; var canvas = document.getElementById("stats"); var context = canvas.getContext("2d"); context.clearRect(0, 0, canvas.width, canvas.height); for (var i = 2; i < 5; i++) { var stat = stats[i]; var obj = objects[i]; var dist = distanceSquared(obj.position, objects[0].position) + distanceSquared(obj.position, objects[1].position); var radiation = 500000 / dist; if (stat.length > MAX_STATS_LENGTH) { stat.shift(); }
if (frameCounter % 5 == 0) { stat.push(radiation); }
if (stat.length > 1) { context.beginPath(); context.strokeStyle = obj.style; context.moveTo(0, height - stat[0]); for (var j = 1; j < stat.length; j++) { context.lineTo(j * 8, height - stat[j]); } context.stroke(); } } } function animate(){ frameCounter++; drawMain(); drawStats(); requestAnimFrame(function(){ animate(); }); } window.onload = function(){ animate(); };