Compare commits
2 Commits
403ce4b683
...
c882749786
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c882749786 | ||
|
|
a6678ced37 |
@ -8,7 +8,7 @@ Uses `npm` for `eslint`.
|
|||||||
TODO
|
TODO
|
||||||
----
|
----
|
||||||
|
|
||||||
[ ] Numeric Option Type
|
[x] Numeric Option Type
|
||||||
[ ] Time Indicator
|
[ ] Time Indicator
|
||||||
[ ] Selection Box
|
[ ] Selection Box
|
||||||
[ ] Object List
|
[ ] Object List
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { MassObject } from './object.js';
|
|||||||
import {
|
import {
|
||||||
MASS_CREATION_RATE,
|
MASS_CREATION_RATE,
|
||||||
DISPLAY_OBJECTS_INFO,
|
DISPLAY_OBJECTS_INFO,
|
||||||
GRAVITATIONAL_CONSTANT,
|
|
||||||
ZOOM_TO_FIT_PADDING,
|
ZOOM_TO_FIT_PADDING,
|
||||||
} from './config.js';
|
} from './config.js';
|
||||||
|
|
||||||
@ -169,6 +168,7 @@ export class Objects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
computeForces() {
|
computeForces() {
|
||||||
|
const gravity = this.sim.getOption('param.gravity');
|
||||||
if (this.objects.length < 2) return;
|
if (this.objects.length < 2) return;
|
||||||
this.forEachObject(obj => {
|
this.forEachObject(obj => {
|
||||||
obj.forces = [];
|
obj.forces = [];
|
||||||
@ -179,7 +179,7 @@ export class Objects {
|
|||||||
const dy = (B.position.y - A.position.y);
|
const dy = (B.position.y - A.position.y);
|
||||||
const dSquared = dx ** 2 + dy ** 2;
|
const dSquared = dx ** 2 + dy ** 2;
|
||||||
const d = Math.sqrt(dSquared);
|
const d = Math.sqrt(dSquared);
|
||||||
const F = GRAVITATIONAL_CONSTANT * A.mass * B.mass / dSquared;
|
const F = gravity * A.mass * B.mass / dSquared;
|
||||||
const Fx = F * dx / d;
|
const Fx = F * dx / d;
|
||||||
const Fy = F * dy / d;
|
const Fy = F * dy / d;
|
||||||
A.forces.push({ x: Fx, y: Fy });
|
A.forces.push({ x: Fx, y: Fy });
|
||||||
|
|||||||
18
style.css
18
style.css
@ -47,7 +47,7 @@ div.lhg-toolbar div.lhg-tool {
|
|||||||
border-color: #282;
|
border-color: #282;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.lhg-tool button {
|
div.lhg-tool button, div.lhg-tool input {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
width: 6em;
|
width: 6em;
|
||||||
@ -66,6 +66,10 @@ div.lhg-tool button {
|
|||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.lhg-tool input {
|
||||||
|
width: 5EM;
|
||||||
|
}
|
||||||
|
|
||||||
div.lhg-tool button:hover {
|
div.lhg-tool button:hover {
|
||||||
background-color: #444;
|
background-color: #444;
|
||||||
}
|
}
|
||||||
@ -86,16 +90,24 @@ div.lhg-toolbar-header > * {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.lhg-tool button.lhg-tool-info {
|
div.lhg-tool .lhg-tool-info {
|
||||||
background-color: #111;
|
background-color: #111;
|
||||||
border-color: #282;
|
border-color: #282;
|
||||||
border-width: 0px;
|
border-width: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.lhg-tool button.lhg-wide {
|
div.lhg-tool .lhg-wide {
|
||||||
width: 12em;
|
width: 12em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.lhg-tool input.lhg-wide {
|
||||||
|
width: 11em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.lhg-tool .lhg-tool-info.lhg-wide {
|
||||||
|
width: 11em;
|
||||||
|
}
|
||||||
|
|
||||||
div.lhg-tool > div {
|
div.lhg-tool > div {
|
||||||
/* border: 2px red solid; */
|
/* border: 2px red solid; */
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,12 @@
|
|||||||
import {
|
import {
|
||||||
DISPLAY_ACCELERATION_VECTORS,
|
DISPLAY_ACCELERATION_VECTORS,
|
||||||
DISPLAY_VELOCITY_VECTORS,
|
DISPLAY_VELOCITY_VECTORS,
|
||||||
|
GRAVITATIONAL_CONSTANT,
|
||||||
MERGE_ON_COLLIDE,
|
MERGE_ON_COLLIDE,
|
||||||
PATH_TRACES_DASHED,
|
PATH_TRACES_DASHED,
|
||||||
PAUSE_DURING_CREATION,
|
PAUSE_DURING_CREATION,
|
||||||
PAUSE_DURING_SELECTION,
|
PAUSE_DURING_SELECTION,
|
||||||
|
TOOL_INFO_CLASSNAME,
|
||||||
WIDE_CLASSNAME,
|
WIDE_CLASSNAME,
|
||||||
} from '../config.js';
|
} from '../config.js';
|
||||||
import {Tool} from '../tool.js';
|
import {Tool} from '../tool.js';
|
||||||
@ -30,6 +32,11 @@ export class Options extends Tool {
|
|||||||
items: [
|
items: [
|
||||||
{type: 'boolean', name: 'merge', title: 'Merge Masses', default: MERGE_ON_COLLIDE, wide: true},
|
{type: 'boolean', name: 'merge', title: 'Merge Masses', default: MERGE_ON_COLLIDE, wide: true},
|
||||||
]
|
]
|
||||||
|
}, {
|
||||||
|
type: 'group', name: 'param', title: 'Parameters',
|
||||||
|
items: [
|
||||||
|
{type: 'number', name: 'gravity', title: 'Gravity', default: GRAVITATIONAL_CONSTANT},
|
||||||
|
]
|
||||||
}];
|
}];
|
||||||
|
|
||||||
values = {};
|
values = {};
|
||||||
@ -62,6 +69,32 @@ export class Options extends Tool {
|
|||||||
});
|
});
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
case 'number': {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const title = document.createElement('button');
|
||||||
|
const input = document.createElement('input');
|
||||||
|
const maxLength = item.maxLength || 8;
|
||||||
|
div.appendChild(title);
|
||||||
|
div.appendChild(input);
|
||||||
|
div.classList.add(WIDE_CLASSNAME);
|
||||||
|
title.classList.add(TOOL_INFO_CLASSNAME);
|
||||||
|
if (item.wide) {
|
||||||
|
// title.classList.add(WIDE_CLASSNAME);
|
||||||
|
input.classList.add(WIDE_CLASSNAME);
|
||||||
|
}
|
||||||
|
title.innerHTML = item.title;
|
||||||
|
input.value = item.default;
|
||||||
|
this.setOption(path, item.default);
|
||||||
|
|
||||||
|
input.addEventListener('input', () => {
|
||||||
|
input.value = input.value.slice(0, maxLength);
|
||||||
|
});
|
||||||
|
|
||||||
|
input.addEventListener('change', () => {
|
||||||
|
this.setOption(path, input.value);
|
||||||
|
});
|
||||||
|
return div;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw new Error('unknown option type');
|
throw new Error('unknown option type');
|
||||||
}
|
}
|
||||||
|
|||||||
29
tool/zoom.js
29
tool/zoom.js
@ -22,19 +22,23 @@ export class Zoom extends Tool {
|
|||||||
const zoomOut = document.createElement('button');
|
const zoomOut = document.createElement('button');
|
||||||
const zoomIn = document.createElement('button');
|
const zoomIn = document.createElement('button');
|
||||||
const zoomAll = document.createElement('button');
|
const zoomAll = document.createElement('button');
|
||||||
|
const zeroVelocity = document.createElement('button');
|
||||||
|
|
||||||
this.div.appendChild(currentScale);
|
this.div.appendChild(currentScale);
|
||||||
this.div.appendChild(zoomOut);
|
this.div.appendChild(zoomOut);
|
||||||
this.div.appendChild(zoomIn);
|
this.div.appendChild(zoomIn);
|
||||||
this.div.appendChild(zoomAll);
|
this.div.appendChild(zoomAll);
|
||||||
|
this.div.appendChild(zeroVelocity);
|
||||||
|
|
||||||
zoomAll.classList.add(WIDE_CLASSNAME);
|
zoomAll.classList.add(WIDE_CLASSNAME);
|
||||||
|
zeroVelocity.classList.add(WIDE_CLASSNAME);
|
||||||
currentScale.classList.add(WIDE_CLASSNAME);
|
currentScale.classList.add(WIDE_CLASSNAME);
|
||||||
currentScale.classList.add(TOOL_INFO_CLASSNAME);
|
currentScale.classList.add(TOOL_INFO_CLASSNAME);
|
||||||
|
|
||||||
zoomOut.innerHTML = 'Zoom<br>Out';
|
zoomOut.innerHTML = 'Zoom<br>Out';
|
||||||
zoomIn.innerHTML = 'Zoom<br>In';
|
zoomIn.innerHTML = 'Zoom<br>In';
|
||||||
zoomAll.innerHTML = 'Zoom to Fit';
|
zoomAll.innerHTML = 'Zoom to Fit';
|
||||||
|
zeroVelocity.innerHTML = 'Zero Net Velocity';
|
||||||
currentScale.innerHTML = this.displayScaleText;
|
currentScale.innerHTML = this.displayScaleText;
|
||||||
|
|
||||||
this.sim.onZoom(() => {
|
this.sim.onZoom(() => {
|
||||||
@ -84,5 +88,30 @@ export class Zoom extends Tool {
|
|||||||
};
|
};
|
||||||
this.sim.scheduleZoom({x, y}, factor, netVelocity)
|
this.sim.scheduleZoom({x, y}, factor, netVelocity)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
zeroVelocity.addEventListener('click', () => {
|
||||||
|
// Determine average momentum
|
||||||
|
const netMomentum = {x: 0, y: 0};
|
||||||
|
let totalMass = 0;
|
||||||
|
let count = 0;
|
||||||
|
this.sim.objects.forEachObject(obj => {
|
||||||
|
count++;
|
||||||
|
netMomentum.x += obj.mass * obj.velocity.x;
|
||||||
|
netMomentum.y += obj.mass * obj.velocity.y;
|
||||||
|
totalMass += obj.mass;
|
||||||
|
});
|
||||||
|
if (!count) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const netVelocity = {
|
||||||
|
x: netMomentum.x / totalMass,
|
||||||
|
y: netMomentum.y / totalMass,
|
||||||
|
};
|
||||||
|
// Apply offset to all object velocities
|
||||||
|
this.sim.objects.forEachObject(obj => {
|
||||||
|
obj.velocity.x -= netVelocity.x;
|
||||||
|
obj.velocity.y -= netVelocity.y;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user