├── README.md ├── index.html ├── style.css └── script.js /README.md: -------------------------------------------------------------------------------- 1 | # Gravity-Simulator 2 | Visualization Of Gravity 3 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Gravity Simulator 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Hovering over the objects enables one to grab them and move them 17 | x 18 |

19 |
20 |
21 |
22 |
23 | 25 | 26 |
27 |
28 | 30 | 31 |
32 |
33 |
34 |
35 | 37 | 38 |
39 |
40 | 42 | 43 |
44 |
45 |
46 |
47 | 48 | 49 |
50 |
51 | 52 | 53 |
54 |
55 |
56 |
57 |
58 | 59 |
60 |
61 | 62 |
63 |
64 |
65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0px; 3 | } 4 | 5 | #ins { 6 | background-color: #ff00ff54; 7 | position: absolute; 8 | left: 10%; 9 | top: 2%; 10 | } 11 | 12 | #inst { 13 | color: rgb(201, 191, 191); 14 | padding: 1px 8px; 15 | font-size: 15px; 16 | } 17 | 18 | #close { 19 | cursor: pointer; 20 | position: relative; 21 | padding: 1px 8px; 22 | } 23 | 24 | #close:hover { 25 | background: #ff00ff21; 26 | } 27 | 28 | #canvas { 29 | position: fixed; 30 | z-index: -1; 31 | } 32 | 33 | #start { 34 | color: white; 35 | background-color: green; 36 | right: 100px; 37 | top: 600px; 38 | font-size: 25px; 39 | border: 3px solid green; 40 | border-radius: 15px; 41 | padding: 10px; 42 | height: 60px; 43 | } 44 | 45 | #start:hover { 46 | background-color: lightgreen; 47 | border: 3px solid lightgreen; 48 | cursor: pointer; 49 | transition: ease 300ms; 50 | } 51 | 52 | #stop { 53 | color: white; 54 | background-color: red; 55 | right: 100px; 56 | top: 700px; 57 | font-size: 25px; 58 | border: 3px solid red; 59 | border-radius: 15px; 60 | padding: 10px; 61 | height: 60px; 62 | } 63 | 64 | #stop:hover { 65 | background-color: rgb(247, 193, 193); 66 | border: 3px solid rgb(247, 193, 193); 67 | cursor: pointer; 68 | transition: ease 300ms; 69 | } 70 | 71 | #input { 72 | visibility: visible; 73 | position: absolute; 74 | display: flex; 75 | flex-direction: row; 76 | width: 20%; 77 | padding: 50px; 78 | align-items: center; 79 | } 80 | 81 | #vbx, 82 | #vgx, 83 | #vby, 84 | #vgy, 85 | #mg, 86 | #mb { 87 | padding: 5px; 88 | transition: ease 500ms; 89 | } 90 | 91 | .container { 92 | background-color: transparent; 93 | display: flex; 94 | } 95 | 96 | #buttons { 97 | display: flex; 98 | flex-direction: row; 99 | position: absolute; 100 | top: 700px; 101 | padding: 50px; 102 | } 103 | 104 | .each { 105 | display: flex; 106 | flex-direction: row; 107 | padding: 20px; 108 | } 109 | 110 | .gp { 111 | display: flex; 112 | flex-direction: column; 113 | padding: 20px; 114 | } 115 | 116 | .butn { 117 | padding: 10px; 118 | } 119 | 120 | @media (min-width: 900px) and (max-width: 1070px) { 121 | #buttons { 122 | top: 800px; 123 | } 124 | } 125 | 126 | @media (min-width: 770px) and (max-width: 900px) { 127 | #buttons { 128 | top: 1000px; 129 | } 130 | 131 | label, 132 | #start, 133 | #stop, 134 | #inst { 135 | font-size: 20px; 136 | } 137 | } 138 | 139 | @media (min-width: 550px) and (max-width: 770px) { 140 | #buttons { 141 | top: 1500px; 142 | } 143 | 144 | label, 145 | #start, 146 | #stop { 147 | font-size: 30px; 148 | } 149 | 150 | #inst { 151 | font-size: 22px; 152 | } 153 | 154 | #input { 155 | top: 10%; 156 | } 157 | } 158 | 159 | @media (min-width: 450px) and (max-width: 550px) { 160 | #buttons { 161 | top: 1800px; 162 | } 163 | 164 | label, 165 | #start, 166 | #stop { 167 | font-size: 40px; 168 | } 169 | 170 | #start, 171 | #stop { 172 | padding-bottom: 50px; 173 | } 174 | 175 | #inst { 176 | font-size: 24px; 177 | } 178 | 179 | #input { 180 | top: 10%; 181 | } 182 | } 183 | 184 | @media (max-width: 450px) { 185 | #buttons { 186 | top: 2500px; 187 | } 188 | 189 | label, 190 | #start, 191 | #stop { 192 | font-size: 40px; 193 | } 194 | 195 | #start, 196 | #stop { 197 | padding-bottom: 60px; 198 | } 199 | 200 | #inst { 201 | font-size: 26px; 202 | } 203 | 204 | #input { 205 | top: 15%; 206 | } 207 | } -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | let canvas = document.getElementById("canvas"); 2 | 3 | let c = canvas.getContext("2d"); 4 | 5 | let b1, b2; 6 | let stararray = []; 7 | let color = ['#afc9ff', '#c7d8ff', '#fff4f3', '#ffe5cf', '#ffd9b2', '#ffc78e', '#ffa651']; 8 | let begin = false; 9 | let over = false; 10 | 11 | let mouse = { 12 | x: 0, 13 | y: 0 14 | } 15 | 16 | if (window.matchMedia("(orientation: portrait)").matches) { 17 | alert("For best experience use this website in landscape mode!!"); 18 | } 19 | 20 | var closebtn = document.getElementById("close"); 21 | 22 | closebtn.addEventListener("click", function () { 23 | this.parentElement.style.display = 'none'; 24 | }); 25 | 26 | addEventListener('resize', () => { 27 | canvas.width = innerWidth; 28 | canvas.height = innerHeight; 29 | init(400, canvas.height / 2, 800, canvas.height / 2); 30 | }); 31 | 32 | addEventListener('mousemove', () => { 33 | mouse.x = event.clientX; 34 | mouse.y = event.clientY; 35 | }) 36 | 37 | addEventListener('mousedown', () => { 38 | over = true; 39 | }) 40 | 41 | addEventListener('mouseup', () => { 42 | over = false; 43 | }) 44 | 45 | canvas.height = innerHeight; 46 | canvas.width = innerWidth; 47 | 48 | function init(x1, y1, x2, y2) { 49 | let vbx = parseFloat(document.getElementById('vbx').value); 50 | let vby = -parseFloat(document.getElementById('vby').value); 51 | let vgx = parseFloat(document.getElementById('vgx').value); 52 | let vgy = -parseFloat(document.getElementById('vgy').value); 53 | let mb = parseFloat(document.getElementById('mb').value); 54 | let mg = parseFloat(document.getElementById('mg').value); 55 | if (isNaN(parseFloat(vbx))) vbx = 0; 56 | if (isNaN(parseFloat(vby))) vby = 0; 57 | if (isNaN(parseFloat(vgx))) vgx = 0; 58 | if (isNaN(parseFloat(vgy))) vgy = 0; 59 | if (isNaN(parseFloat(mb))) mb = 0; 60 | if (isNaN(parseFloat(mg))) mg = 0; 61 | if (mb <= 0 || mg <= 0) { 62 | alert('Mass cannot be negetive or zero or empty'); 63 | begin = false; 64 | document.getElementById('input').style.visibility = 'visible'; 65 | } else { 66 | b1 = new Body(x1, y1, 20, 'blue', mb, vbx, vby); 67 | b2 = new Body(x2, y2, 20, 'green', mg, vgx, vgy); 68 | } 69 | } 70 | 71 | function init_star() { 72 | for (let i = 0; i < 1500; i++) { 73 | let x = Math.random() * (canvas.width + 1000) - (canvas.width + 1000) / 2; 74 | let y = Math.random() * (canvas.height + 1000) - (canvas.height + 1000) / 2; 75 | let radius = Math.random() * 2.5; 76 | let colour = color[Math.floor(Math.random() * color.length)]; 77 | stararray.push(new Star(x, y, radius, colour)); 78 | } 79 | } 80 | 81 | class Body { 82 | constructor(x, y, radius, color, m, vel_x, vel_y) { 83 | this.x = x; 84 | this.y = y; 85 | this.radius = radius; 86 | this.color = color; 87 | this.m = m; 88 | this.vel_x = vel_x; 89 | this.vel_y = vel_y; 90 | } 91 | 92 | update = (b1, b2) => { 93 | this.x += this.vel_x; 94 | this.y += this.vel_y; 95 | this.vel_x += ((b1.m * b2.m) / (this.m * Math.sqrt(Math.pow(b2.y - b1.y, 2) + Math.pow(b2.x - b1.x, 2)) * Math.sqrt(Math.pow(b2.y - b1.y, 2) + Math.pow(b2.x - b1.x, 2)))) * Math.cos(Math.atan2(b1.y + b2.y - 2 * this.y, b2.x + b1.x - 2 * this.x)); 96 | this.vel_y += ((b1.m * b2.m) / (this.m * Math.sqrt(Math.pow(b2.y - b1.y, 2) + Math.pow(b2.x - b1.x, 2)) * Math.sqrt(Math.pow(b2.y - b1.y, 2) + Math.pow(b2.x - b1.x, 2)))) * Math.sin(Math.atan2(b1.y + b2.y - 2 * this.y, b2.x + b1.x - 2 * this.x)); 97 | this.draw(); 98 | }; 99 | 100 | draw = () => { 101 | c.beginPath(); 102 | c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); 103 | c.fillStyle = this.color; 104 | c.fill(); 105 | c.closePath(); 106 | }; 107 | } 108 | 109 | class Star { 110 | constructor(x, y, radius, color) { 111 | this.x = x; 112 | this.y = y; 113 | this.radius = radius; 114 | this.color = color; 115 | } 116 | 117 | update = () => { 118 | this.draw(); 119 | } 120 | 121 | draw = () => { 122 | c.beginPath(); 123 | c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); 124 | c.shadowColor = this.color; 125 | c.shadowBlur = 9; 126 | c.fillStyle = this.color; 127 | c.fill(); 128 | c.closePath(); 129 | } 130 | } 131 | 132 | let rotate = 0; 133 | 134 | function animate() { 135 | requestAnimationFrame(animate); 136 | c.fillStyle = 'black'; 137 | c.fillRect(0, 0, canvas.width, canvas.height); 138 | c.save(); 139 | c.translate(canvas.width / 2, canvas.height / 2); 140 | c.rotate(rotate); 141 | stararray.forEach((star) => { 142 | star.update(); 143 | }); 144 | c.restore(); 145 | if (begin) { 146 | b1.update(b1, b2); 147 | b2.update(b1, b2); 148 | } else { 149 | if (mouse.x >= b1.x - b1.radius && mouse.x <= b1.x + b1.radius && mouse.y >= b1.y - b1.radius && mouse.y <= b1.y + b1.radius) { 150 | document.body.style.cursor = 'grab'; 151 | if (over) { 152 | b1.x = mouse.x; 153 | b1.y = mouse.y; 154 | } 155 | } else if (mouse.x >= b2.x - b2.radius && mouse.x <= b2.x + b2.radius && mouse.y >= b2.y - b2.radius && mouse.y <= b2.y + b2.radius) { 156 | document.body.style.cursor = 'grab'; 157 | if (over) { 158 | b2.x = mouse.x; 159 | b2.y = mouse.y; 160 | } 161 | } else { 162 | document.body.style.cursor = 'default'; 163 | } 164 | b1.draw(); 165 | b2.draw(); 166 | } 167 | rotate += 0.0005; 168 | } 169 | 170 | function start() { 171 | begin = true; 172 | document.getElementById('input').style.visibility = 'hidden'; 173 | init(b1.x, b1.y, b2.x, b2.y); 174 | } 175 | 176 | function stop() { 177 | begin = false; 178 | document.getElementById('input').style.visibility = 'visible'; 179 | init(400, canvas.height / 2, 800, canvas.height / 2); 180 | } 181 | 182 | init_star(); 183 | init(400, canvas.height / 2, 800, canvas.height / 2); 184 | animate(); --------------------------------------------------------------------------------