refactor into separate files: display, overlay, obj
This commit is contained in:
parent
08c3657baf
commit
205b1cf899
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.swp
|
||||
64
display.js
Normal file
64
display.js
Normal file
@ -0,0 +1,64 @@
|
||||
export class Display {
|
||||
sim = undefined;
|
||||
|
||||
VELOCITY_VECTOR_SCALE = 0.2;
|
||||
|
||||
constructor(sim) {
|
||||
this.sim = sim;
|
||||
// Create canvas that fills the window
|
||||
// If the window resizes, also resize the canvas
|
||||
const canvas = document.createElement('canvas')
|
||||
this.canvas = canvas;
|
||||
this.ctx = canvas.getContext("2d");
|
||||
this.sim.div.appendChild(canvas);
|
||||
canvas.style.position = 'absolute';
|
||||
canvas.style.top = 0;
|
||||
canvas.style.left = 0;
|
||||
this.fullscreen();
|
||||
window.addEventListener('resize', () => this.fullscreen());
|
||||
}
|
||||
|
||||
fullscreen() {
|
||||
this.canvas.width = document.documentElement.clientWidth;
|
||||
this.canvas.height = document.documentElement.clientHeight;
|
||||
// this.info['Canvas'] = `${this.canvas.width} x ${this.canvas.height}`;
|
||||
}
|
||||
|
||||
fillCanvas() {
|
||||
const ctx = this.ctx;
|
||||
ctx.fillStyle = '#000';
|
||||
ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
}
|
||||
|
||||
drawObject(idx) {
|
||||
const obj = this.sim.objects[idx];
|
||||
const ctx = this.ctx;
|
||||
const {r, g, b} = obj.color;
|
||||
const {x, y} = obj.position;
|
||||
const {x: vx, y: vy} = obj.velocity;
|
||||
const radius = obj.radius;
|
||||
|
||||
// Draw filled circle for the object
|
||||
ctx.fillStyle = `rgb(${r}, ${g}, ${b})`;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, radius, 0, 2*Math.PI);
|
||||
ctx.fill();
|
||||
|
||||
// Draw line for the velocity
|
||||
// TODO: Arrow
|
||||
ctx.strokeStyle = ctx.fillStyle;
|
||||
ctx.lineWidth = 2.0;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y);
|
||||
ctx.lineTo(x + this.VELOCITY_VECTOR_SCALE * vx, y + this.VELOCITY_VECTOR_SCALE * vy);
|
||||
ctx.stroke();
|
||||
|
||||
// TODO: Draw line for acceleration
|
||||
}
|
||||
|
||||
drawObjects() {
|
||||
for (let i = 0; i < this.sim.objects.length; i++) {
|
||||
this.drawObject(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
obj.js
Normal file
27
obj.js
Normal file
@ -0,0 +1,27 @@
|
||||
export class MassObject {
|
||||
mass = 0;
|
||||
density = 1;
|
||||
position = {x: undefined, y: undefined};
|
||||
velocity = {x: 0, y: 0};
|
||||
color = {r: undefined, g: undefined, b: undefined};
|
||||
created = undefined;
|
||||
|
||||
constructor(x, y) {
|
||||
this.position.x = x;
|
||||
this.position.y = y;
|
||||
this.color.r = Math.random() * 256;
|
||||
this.color.g = Math.random() * 256;
|
||||
this.color.b = Math.random() * 256;
|
||||
this.created = document.timeline.currentTime;
|
||||
}
|
||||
|
||||
get age() {
|
||||
return document.timeline.currentTime - this.created;
|
||||
}
|
||||
|
||||
get radius() {
|
||||
// radius should be proportional to cube root of mass
|
||||
return Math.pow(this.mass / this.density, 1/3);
|
||||
}
|
||||
}
|
||||
|
||||
37
overlay.js
Normal file
37
overlay.js
Normal file
@ -0,0 +1,37 @@
|
||||
export class Overlay {
|
||||
sim = undefined;
|
||||
constructor(sim) {
|
||||
this.sim = sim;
|
||||
|
||||
// Add info text box
|
||||
const infoBox = document.createElement('div');
|
||||
this.sim.div.appendChild(infoBox);
|
||||
this.infoBox = infoBox;
|
||||
infoBox.style.position = 'absolute';
|
||||
infoBox.style.top = 0;
|
||||
infoBox.style.left = 0;
|
||||
infoBox.width = 'fit-content';
|
||||
infoBox.style.zIndex = 1;
|
||||
|
||||
}
|
||||
|
||||
renderInfo() {
|
||||
this.infoBox.innerHTML = '';
|
||||
const table = document.createElement('table');
|
||||
for (let [k, v] of Object.entries(this.sim.info)) {
|
||||
let row = document.createElement('tr');
|
||||
let keyCell = document.createElement('td');
|
||||
keyCell.innerHTML = `${k}: `;
|
||||
row.appendChild(keyCell);
|
||||
let vs = Array.isArray(v) ? v : [v];
|
||||
for (let x of vs) {
|
||||
let valueCell = document.createElement('td');
|
||||
valueCell.innerHTML = x;
|
||||
row.appendChild(valueCell);
|
||||
}
|
||||
table.appendChild(row);
|
||||
}
|
||||
this.infoBox.appendChild(table);
|
||||
}
|
||||
|
||||
}
|
||||
2
pointer.js
Normal file
2
pointer.js
Normal file
@ -0,0 +1,2 @@
|
||||
class Pointer {
|
||||
}
|
||||
133
simulator.js
133
simulator.js
@ -1,29 +1,6 @@
|
||||
export class MassObject {
|
||||
mass = 0;
|
||||
density = 1;
|
||||
position = {x: undefined, y: undefined};
|
||||
velocity = {x: 0, y: 0};
|
||||
color = {r: undefined, g: undefined, b: undefined};
|
||||
created = undefined;
|
||||
|
||||
constructor(x, y) {
|
||||
this.position.x = x;
|
||||
this.position.y = y;
|
||||
this.color.r = Math.random() * 256;
|
||||
this.color.g = Math.random() * 256;
|
||||
this.color.b = Math.random() * 256;
|
||||
this.created = document.timeline.currentTime;
|
||||
}
|
||||
|
||||
get age() {
|
||||
return document.timeline.currentTime - this.created;
|
||||
}
|
||||
|
||||
get radius() {
|
||||
// radius should be proportional to cube root of mass
|
||||
return Math.pow(this.mass / this.density, 1/3);
|
||||
}
|
||||
}
|
||||
import { MassObject } from './obj.js';
|
||||
import { Display } from './display.js';
|
||||
import { Overlay } from './overlay.js';
|
||||
|
||||
export class Sim {
|
||||
info = {};
|
||||
@ -32,79 +9,28 @@ export class Sim {
|
||||
time = undefined;
|
||||
pointerHistory = [];
|
||||
|
||||
display = undefined;
|
||||
overlay = undefined;
|
||||
|
||||
POINTER_HISTORY_SIZE = 20;
|
||||
MASS_CREATION_RATE = 0.001;
|
||||
DISPLAY_OBJECTS_INFO = false;
|
||||
DISPLAY_CURSOR_INFO = false;
|
||||
DISPLAY_VELOCITY_VECTORS = true;
|
||||
VELOCITY_VECTOR_SCALE = 0.2;
|
||||
|
||||
fullscreen() {
|
||||
this.canvas.width = document.documentElement.clientWidth;
|
||||
this.canvas.height = document.documentElement.clientHeight;
|
||||
// this.info['Canvas'] = `${this.canvas.width} x ${this.canvas.height}`;
|
||||
this.fillCanvas();
|
||||
this.renderInfo();
|
||||
}
|
||||
|
||||
fillCanvas() {
|
||||
const ctx = this.ctx;
|
||||
ctx.fillStyle = '#000';
|
||||
ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
}
|
||||
|
||||
renderInfo() {
|
||||
this.infoBox.innerHTML = '';
|
||||
const table = document.createElement('table');
|
||||
for (let [k, v] of Object.entries(this.info)) {
|
||||
let row = document.createElement('tr');
|
||||
let keyCell = document.createElement('td');
|
||||
keyCell.innerHTML = `${k}: `;
|
||||
row.appendChild(keyCell);
|
||||
let vs = Array.isArray(v) ? v : [v];
|
||||
for (let x of vs) {
|
||||
let valueCell = document.createElement('td');
|
||||
valueCell.innerHTML = x;
|
||||
row.appendChild(valueCell);
|
||||
}
|
||||
table.appendChild(row);
|
||||
}
|
||||
this.infoBox.appendChild(table);
|
||||
}
|
||||
|
||||
init(divId) {
|
||||
this.divId = divId;
|
||||
const div = document.getElementById(this.divId);
|
||||
this.div = div;
|
||||
|
||||
// Add info text box
|
||||
const infoBox = document.createElement('div');
|
||||
this.div.appendChild(infoBox);
|
||||
this.infoBox = infoBox;
|
||||
infoBox.style.position = 'absolute';
|
||||
infoBox.style.top = 0;
|
||||
infoBox.style.left = 0;
|
||||
infoBox.width = 'fit-content';
|
||||
infoBox.style.zIndex = 1;
|
||||
this.display = new Display(this);
|
||||
this.overlay = new Overlay(this);
|
||||
|
||||
// Create canvas that fills the window
|
||||
// If the window resizes, also resize the canvas
|
||||
const canvas = document.createElement('canvas')
|
||||
this.canvas = canvas;
|
||||
this.ctx = canvas.getContext("2d");
|
||||
this.div.appendChild(canvas);
|
||||
canvas.style.position = 'absolute';
|
||||
canvas.style.top = 0;
|
||||
canvas.style.left = 0;
|
||||
this.fullscreen();
|
||||
window.addEventListener('resize', () => this.fullscreen());
|
||||
|
||||
// Monitor mouse movements
|
||||
const el = window;
|
||||
el.addEventListener('mousemove', e => {
|
||||
if (this.DISPLAY_CURSOR_INFO) {
|
||||
this.info['Mouse move'] = [`${e.clientX}, `, `${e.clientY}`];
|
||||
this.renderInfo();
|
||||
}
|
||||
this.handlePointerMove(e.clientX, e.clientY);
|
||||
});
|
||||
@ -113,7 +39,6 @@ export class Sim {
|
||||
el.addEventListener('touchmove', e => {
|
||||
if (this.DISPLAY_CURSOR_INFO) {
|
||||
this.info['Touch move'] = [`${e.touches[0].pageX}, `, `${e.touches[0].pageY}`];
|
||||
this.renderInfo();
|
||||
}
|
||||
this.handlePointerMove(e.touches[0].pageX, e.touches[0].pageY);
|
||||
});
|
||||
@ -121,7 +46,6 @@ export class Sim {
|
||||
el.addEventListener('pointerdown', e => {
|
||||
if (this.DISPLAY_CURSOR_INFO) {
|
||||
this.info['Pointer down'] = [`${e.clientX}, `, `${e.clientY}`];
|
||||
this.renderInfo();
|
||||
}
|
||||
this.handlePointerDown(e.clientX, e.clientY);
|
||||
});
|
||||
@ -129,7 +53,6 @@ export class Sim {
|
||||
el.addEventListener('pointerup', e => {
|
||||
if (this.DISPLAY_CURSOR_INFO) {
|
||||
this.info['Pointer up'] = [`${e.clientX}, `, `${e.clientY}`];
|
||||
this.renderInfo();
|
||||
}
|
||||
this.handlePointerUp(e.clientX, e.clientY);
|
||||
});
|
||||
@ -137,7 +60,6 @@ export class Sim {
|
||||
el.addEventListener('click', e => {
|
||||
if (this.DISPLAY_CURSOR_INFO) {
|
||||
this.info['Click'] = [`${e.clientX}, `, `${e.clientY}`];
|
||||
this.renderInfo();
|
||||
}
|
||||
});
|
||||
|
||||
@ -166,7 +88,6 @@ export class Sim {
|
||||
const start = this.pointerHistory[0];
|
||||
const end = this.pointerHistory[this.pointerHistory.length - 1];
|
||||
const dt = (end.t - start.t) / 1000;
|
||||
this.renderInfo();
|
||||
return {
|
||||
x: (end.x - start.x) / dt,
|
||||
y: (end.y - start.y) / dt,
|
||||
@ -254,45 +175,13 @@ export class Sim {
|
||||
`${obj.mass.toPrecision(6)} kg, `,
|
||||
`${speed.toPrecision(2)} m/s, ${direction.toPrecision(2)}°`,
|
||||
];
|
||||
this.renderInfo();
|
||||
}
|
||||
}
|
||||
|
||||
this.fillCanvas();
|
||||
this.renderObjects();
|
||||
this.display.fillCanvas();
|
||||
this.display.drawObjects();
|
||||
this.overlay.renderInfo();
|
||||
|
||||
requestAnimationFrame(t => this.loop(t));
|
||||
}
|
||||
|
||||
renderObject(idx) {
|
||||
const obj = this.objects[idx];
|
||||
const ctx = this.ctx;
|
||||
const {r, g, b} = obj.color;
|
||||
const {x, y} = obj.position;
|
||||
const {x: vx, y: vy} = obj.velocity;
|
||||
const radius = obj.radius;
|
||||
|
||||
// Draw filled circle for the object
|
||||
ctx.fillStyle = `rgb(${r}, ${g}, ${b})`;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, radius, 0, 2*Math.PI);
|
||||
ctx.fill();
|
||||
|
||||
// Draw line for the velocity
|
||||
// TODO: Arrow
|
||||
ctx.strokeStyle = ctx.fillStyle;
|
||||
ctx.lineWidth = 2.0;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y);
|
||||
ctx.lineTo(x + this.VELOCITY_VECTOR_SCALE * vx, y + this.VELOCITY_VECTOR_SCALE * vy);
|
||||
ctx.stroke();
|
||||
|
||||
// TODO: Draw line for acceleration
|
||||
}
|
||||
|
||||
renderObjects() {
|
||||
for (let i = 0; i < this.objects.length; i++) {
|
||||
this.renderObject(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user