Compare commits
2 Commits
f34266091d
...
56414a7ca1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56414a7ca1 | ||
|
|
dc4d92c9cd |
@ -19,4 +19,9 @@ TODO
|
|||||||
- [ ] Zoom Easing
|
- [ ] Zoom Easing
|
||||||
- [ ] 2-touch Pan & Zoom
|
- [ ] 2-touch Pan & Zoom
|
||||||
- [ ] Multi-touch Mass Create
|
- [ ] Multi-touch Mass Create
|
||||||
- [ ] Tool to Clear Traces
|
- [x] Tool to Clear Traces
|
||||||
|
- [ ] Undo feature:
|
||||||
|
- [ ] Undo "Clear Traces" Action
|
||||||
|
- [ ] Undo "Reset
|
||||||
|
- [ ] Save to LocalStorage
|
||||||
|
- [ ] Lossy Rescaling To Widen Zoom (Handling overflow/underflow)
|
||||||
|
|||||||
@ -9,13 +9,13 @@ export const DISPLAY_ACCELERATION_VECTORS = true;
|
|||||||
export const DISPLAY_PATH_TRACES = false;
|
export const DISPLAY_PATH_TRACES = false;
|
||||||
|
|
||||||
// VELOCITY
|
// VELOCITY
|
||||||
export const VELOCITY_VECTOR_SCALE = 5E0;
|
export const VELOCITY_VECTOR_SCALE = 8E0;
|
||||||
export const VELOCITY_VECTOR_COLOR = 'rgba(150, 150, 150, 0.8)'; // optionally set to 'object color'
|
export const VELOCITY_VECTOR_COLOR = 'rgba(150, 150, 150, 0.8)'; // optionally set to 'object color'
|
||||||
export const VELOCITY_VECTOR_WIDTH = 1.5;
|
export const VELOCITY_VECTOR_WIDTH = 1.5;
|
||||||
export const VELOCITY_VECTOR_ARROWHEAD = true;
|
export const VELOCITY_VECTOR_ARROWHEAD = true;
|
||||||
|
|
||||||
// ACCELERATION
|
// ACCELERATION
|
||||||
export const ACCELERATION_VECTOR_SCALE = 5E0;
|
export const ACCELERATION_VECTOR_SCALE = 8E0;
|
||||||
export const ACCELERATION_VECTOR_COLOR = 'rgba(0, 128, 0, 0.8)'; // optionally set to 'object color'
|
export const ACCELERATION_VECTOR_COLOR = 'rgba(0, 128, 0, 0.8)'; // optionally set to 'object color'
|
||||||
export const ACCELERATION_VECTOR_WIDTH = 1.5;
|
export const ACCELERATION_VECTOR_WIDTH = 1.5;
|
||||||
export const ACCELERATION_VECTOR_ARROWHEAD = true;
|
export const ACCELERATION_VECTOR_ARROWHEAD = true;
|
||||||
|
|||||||
148
display.js
148
display.js
@ -1,22 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
ACCELERATION_VECTOR_ARROWHEAD,
|
|
||||||
ACCELERATION_VECTOR_COLOR,
|
|
||||||
ACCELERATION_VECTOR_SCALE,
|
|
||||||
ACCELERATION_VECTOR_WIDTH,
|
|
||||||
ARROWHEAD_LENGTH,
|
ARROWHEAD_LENGTH,
|
||||||
ARROWHEAD_WIDTH,
|
ARROWHEAD_WIDTH,
|
||||||
DISPLAY_CANVAS_SIZE,
|
DISPLAY_CANVAS_SIZE,
|
||||||
OFFSCREEN_OBJECT_ARROWHEAD_LENGTH,
|
|
||||||
OFFSCREEN_OBJECT_LINE_SCALE,
|
|
||||||
OFFSCREEN_OBJECT_LINE_WIDTH,
|
|
||||||
PATH_TRACES_COLOR,
|
|
||||||
PATH_TRACES_OPACITY,
|
|
||||||
PATH_TRACES_DASHED_OPACITY,
|
|
||||||
PATH_TRACES_WIDTH,
|
|
||||||
VELOCITY_VECTOR_ARROWHEAD,
|
|
||||||
VELOCITY_VECTOR_COLOR,
|
|
||||||
VELOCITY_VECTOR_SCALE,
|
|
||||||
VELOCITY_VECTOR_WIDTH,
|
|
||||||
} from './config.js';
|
} from './config.js';
|
||||||
|
|
||||||
export class Display {
|
export class Display {
|
||||||
@ -86,139 +71,8 @@ export class Display {
|
|||||||
ctx.fillRect(this.viewOrigin.x, this.viewOrigin.y, this.width, this.height);
|
ctx.fillRect(this.viewOrigin.x, this.viewOrigin.y, this.width, this.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawObject(obj) {
|
|
||||||
const ctx = this.ctx;
|
|
||||||
const {r, g, b} = obj.color;
|
|
||||||
const {x, y} = obj.position;
|
|
||||||
const {x: vx, y: vy} = obj.velocity;
|
|
||||||
const acceleration = obj.acceleration;
|
|
||||||
const radius = obj.radius;
|
|
||||||
const {height: H, width: W} = this;
|
|
||||||
const ox = this.viewOrigin.x;
|
|
||||||
const oy = this.viewOrigin.y;
|
|
||||||
const cx = ox + W / 2;
|
|
||||||
const cy = oy + H / 2;
|
|
||||||
|
|
||||||
// Draw path traces
|
|
||||||
if (this.sim.getOption('display.traces') && obj.history?.length) {
|
|
||||||
const dashedTraces = this.sim.getOption('display.dashedTraces');
|
|
||||||
const opacity = dashedTraces ? PATH_TRACES_DASHED_OPACITY : PATH_TRACES_OPACITY;
|
|
||||||
ctx.strokeStyle = PATH_TRACES_COLOR === 'object color' ?
|
|
||||||
`rgba(${r}, ${g}, ${b}, ${opacity})` : PATH_TRACES_COLOR;
|
|
||||||
ctx.lineWidth = PATH_TRACES_WIDTH / this.scale;
|
|
||||||
ctx.beginPath();
|
|
||||||
let dash = false;
|
|
||||||
for (let i = 0; i < obj.history.length ; i++) {
|
|
||||||
// if (i % 2 > 0) continue;
|
|
||||||
const {position: {x, y}} = obj.history[i];
|
|
||||||
if (dashedTraces) {
|
|
||||||
if (dash) {
|
|
||||||
ctx.lineTo(x, y);
|
|
||||||
} else {
|
|
||||||
ctx.moveTo(x, y);
|
|
||||||
}
|
|
||||||
dash = !dash;
|
|
||||||
} else {
|
|
||||||
ctx.lineTo(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!obj.alive) return;
|
|
||||||
|
|
||||||
// If the object is outside the display area, draw an arrow at the edge of the display
|
|
||||||
if (Math.abs(x - cx) - radius >= W / 2 ||
|
|
||||||
Math.abs(y - cy) - radius >= H / 2) {
|
|
||||||
// Find where a line from center of display to object intersects display edge
|
|
||||||
let px, py;
|
|
||||||
if (y <= cy) {
|
|
||||||
// Line intersects y = 0:
|
|
||||||
const y0px = cx + (H / 2) / (cy - y) * (x - cx);
|
|
||||||
if (Math.abs(y0px - cx) <= W / 2) {
|
|
||||||
px = y0px;
|
|
||||||
py = this.viewOrigin.y;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Line intersects y = H
|
|
||||||
const yHpx = cx + (H / 2) / (y - cy) * (x - cx);
|
|
||||||
if (Math.abs(yHpx - cx) <= W / 2) {
|
|
||||||
px = yHpx;
|
|
||||||
py = this.viewOrigin.y + H;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (px === undefined) {
|
|
||||||
if (x <= cx) {
|
|
||||||
// Line intersects x = 0:
|
|
||||||
px = this.viewOrigin.x;
|
|
||||||
py = cy + (W / 2) / (cx - x) * (y - cy);
|
|
||||||
} else {
|
|
||||||
// Line intersects x = W:
|
|
||||||
px = this.viewOrigin.x + W;
|
|
||||||
py = cy + (W / 2) / (x - cx) * (y - cy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const arrowDirection = Math.atan2(py - cy, px - cx);
|
|
||||||
// Length of arrow based on distance (logarithmic scale)
|
|
||||||
const distance = Math.sqrt((x - px) ** 2, (y - py) ** 2) * this.scale;
|
|
||||||
const arrowLength = Math.log(distance) * OFFSCREEN_OBJECT_LINE_SCALE / this.scale;
|
|
||||||
const startAx = px - arrowLength * Math.cos(arrowDirection);
|
|
||||||
const startAy = py - arrowLength * Math.sin(arrowDirection);
|
|
||||||
this.drawArrow(startAx, startAy, px, py, {
|
|
||||||
style: `rgb(${r}, ${g}, ${b})`,
|
|
||||||
width: OFFSCREEN_OBJECT_LINE_WIDTH,
|
|
||||||
arrowheadLength: OFFSCREEN_OBJECT_ARROWHEAD_LENGTH,
|
|
||||||
fill: false,
|
|
||||||
ifShort: 'head',
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 arrow for the velocity
|
|
||||||
if (this.sim.getOption('display.velocity')) {
|
|
||||||
const speed = Math.sqrt(vx ** 2 + vy ** 2);
|
|
||||||
const endVx = x + VELOCITY_VECTOR_SCALE * vx / speed * Math.log(speed);
|
|
||||||
const endVy = y + VELOCITY_VECTOR_SCALE * vy / speed * Math.log(speed);
|
|
||||||
const style = VELOCITY_VECTOR_COLOR === 'object color' ?
|
|
||||||
`rgb(${r}, ${g}, ${b})` : VELOCITY_VECTOR_COLOR;
|
|
||||||
this.drawArrow(x, y, endVx, endVy, {
|
|
||||||
style,
|
|
||||||
width: VELOCITY_VECTOR_WIDTH,
|
|
||||||
arrowhead: VELOCITY_VECTOR_ARROWHEAD,
|
|
||||||
fill: false,
|
|
||||||
ifShort: 'head'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw arrow for acceleration
|
|
||||||
if (this.sim.getOption('display.acceleration')) {
|
|
||||||
const accelerationMagnitude = Math.sqrt(acceleration.x ** 2 + acceleration.y ** 2);
|
|
||||||
const endAx = x + ACCELERATION_VECTOR_SCALE * acceleration.x /
|
|
||||||
accelerationMagnitude * Math.log(accelerationMagnitude);
|
|
||||||
const endAy = y + ACCELERATION_VECTOR_SCALE * acceleration.y /
|
|
||||||
accelerationMagnitude * Math.log(accelerationMagnitude);
|
|
||||||
const style = ACCELERATION_VECTOR_COLOR === 'object color' ?
|
|
||||||
`rgb(${r}, ${g}, ${b})` : ACCELERATION_VECTOR_COLOR;
|
|
||||||
this.drawArrow(x, y, endAx, endAy, {
|
|
||||||
style,
|
|
||||||
width: ACCELERATION_VECTOR_WIDTH,
|
|
||||||
arrowhead: ACCELERATION_VECTOR_ARROWHEAD,
|
|
||||||
fill: false,
|
|
||||||
ifShort: 'tail'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
drawObjects() {
|
drawObjects() {
|
||||||
this.sim.objects.forEachObject(obj => this.drawObject(obj), null);
|
this.sim.objects.forEachObject(obj => obj.drawObject(this.sim), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawArrow(startX, startY, endX, endY, {style, width, arrowhead, arrowheadLength, fill, ifShort}) {
|
drawArrow(startX, startY, endX, endY, {style, width, arrowhead, arrowheadLength, fill, ifShort}) {
|
||||||
|
|||||||
161
object.js
161
object.js
@ -1,3 +1,21 @@
|
|||||||
|
import {
|
||||||
|
ACCELERATION_VECTOR_ARROWHEAD,
|
||||||
|
ACCELERATION_VECTOR_COLOR,
|
||||||
|
ACCELERATION_VECTOR_SCALE,
|
||||||
|
ACCELERATION_VECTOR_WIDTH,
|
||||||
|
OFFSCREEN_OBJECT_ARROWHEAD_LENGTH,
|
||||||
|
OFFSCREEN_OBJECT_LINE_SCALE,
|
||||||
|
OFFSCREEN_OBJECT_LINE_WIDTH,
|
||||||
|
PATH_TRACES_COLOR,
|
||||||
|
PATH_TRACES_DASHED_OPACITY,
|
||||||
|
PATH_TRACES_OPACITY,
|
||||||
|
PATH_TRACES_WIDTH,
|
||||||
|
VELOCITY_VECTOR_ARROWHEAD,
|
||||||
|
VELOCITY_VECTOR_COLOR,
|
||||||
|
VELOCITY_VECTOR_SCALE,
|
||||||
|
VELOCITY_VECTOR_WIDTH,
|
||||||
|
} from './config.js';
|
||||||
|
|
||||||
export class MassObject {
|
export class MassObject {
|
||||||
mass = 0;
|
mass = 0;
|
||||||
density = 1;
|
density = 1;
|
||||||
@ -25,7 +43,7 @@ export class MassObject {
|
|||||||
|
|
||||||
get radius() {
|
get radius() {
|
||||||
// radius should be proportional to cube root of mass
|
// radius should be proportional to cube root of mass
|
||||||
return Math.pow(this.mass / this.density, 1/3);
|
return Math.pow(this.mass / this.density, 1 / 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAcceleration() {
|
getAcceleration() {
|
||||||
@ -40,5 +58,146 @@ export class MassObject {
|
|||||||
y: ay / this.mass,
|
y: ay / this.mass,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drawObject(sim) {
|
||||||
|
const {
|
||||||
|
color: {r, g, b},
|
||||||
|
position: {x, y},
|
||||||
|
velocity: {x: vx, y: vy},
|
||||||
|
acceleration,
|
||||||
|
radius,
|
||||||
|
} = this;
|
||||||
|
|
||||||
|
const {
|
||||||
|
display: {
|
||||||
|
ctx,
|
||||||
|
height: H,
|
||||||
|
width: W,
|
||||||
|
viewOrigin: {x: ox, y: oy},
|
||||||
|
}
|
||||||
|
} = sim;
|
||||||
|
|
||||||
|
const cx = ox + W / 2;
|
||||||
|
const cy = oy + H / 2;
|
||||||
|
|
||||||
|
// Draw path traces
|
||||||
|
if (sim.getOption('display.traces') && this.history?.length) {
|
||||||
|
const dashedTraces = sim.getOption('display.dashedTraces');
|
||||||
|
const opacity = dashedTraces ? PATH_TRACES_DASHED_OPACITY : PATH_TRACES_OPACITY;
|
||||||
|
ctx.strokeStyle = PATH_TRACES_COLOR === 'object color' ?
|
||||||
|
`rgba(${r}, ${g}, ${b}, ${opacity})` : PATH_TRACES_COLOR;
|
||||||
|
ctx.lineWidth = PATH_TRACES_WIDTH / this.scale;
|
||||||
|
ctx.beginPath();
|
||||||
|
let dash = false;
|
||||||
|
for (let i = 0; i < this.history.length; i++) {
|
||||||
|
// if (i % 2 > 0) continue;
|
||||||
|
const {position: {x, y}} = this.history[i];
|
||||||
|
if (dashedTraces) {
|
||||||
|
if (dash) {
|
||||||
|
ctx.lineTo(x, y);
|
||||||
|
} else {
|
||||||
|
ctx.moveTo(x, y);
|
||||||
|
}
|
||||||
|
dash = !dash;
|
||||||
|
} else {
|
||||||
|
ctx.lineTo(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.alive) return;
|
||||||
|
|
||||||
|
// If the object is outside the display area, draw an arrow at the edge of the display
|
||||||
|
if (Math.abs(x - cx) - radius >= W / 2 ||
|
||||||
|
Math.abs(y - cy) - radius >= H / 2) {
|
||||||
|
// Find where a line from center of display to object intersects display edge
|
||||||
|
let px, py;
|
||||||
|
if (y <= cy) {
|
||||||
|
// Line intersects y = 0:
|
||||||
|
const y0px = cx + (H / 2) / (cy - y) * (x - cx);
|
||||||
|
if (Math.abs(y0px - cx) <= W / 2) {
|
||||||
|
px = y0px;
|
||||||
|
py = oy;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Line intersects y = H
|
||||||
|
const yHpx = cx + (H / 2) / (y - cy) * (x - cx);
|
||||||
|
if (Math.abs(yHpx - cx) <= W / 2) {
|
||||||
|
px = yHpx;
|
||||||
|
py = oy + H;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (px === undefined) {
|
||||||
|
if (x <= cx) {
|
||||||
|
// Line intersects x = 0:
|
||||||
|
px = ox;
|
||||||
|
py = cy + (W / 2) / (cx - x) * (y - cy);
|
||||||
|
} else {
|
||||||
|
// Line intersects x = W:
|
||||||
|
px = ox + W;
|
||||||
|
py = cy + (W / 2) / (x - cx) * (y - cy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const arrowDirection = Math.atan2(py - cy, px - cx);
|
||||||
|
// Length of arrow based on distance (logarithmic scale)
|
||||||
|
const distance = Math.sqrt((x - px) ** 2, (y - py) ** 2) * this.scale;
|
||||||
|
const arrowLength = Math.log(distance) * OFFSCREEN_OBJECT_LINE_SCALE / this.scale;
|
||||||
|
const startAx = px - arrowLength * Math.cos(arrowDirection);
|
||||||
|
const startAy = py - arrowLength * Math.sin(arrowDirection);
|
||||||
|
sim.display.drawArrow(startAx, startAy, px, py, {
|
||||||
|
style: `rgb(${r}, ${g}, ${b})`,
|
||||||
|
width: OFFSCREEN_OBJECT_LINE_WIDTH,
|
||||||
|
arrowheadLength: OFFSCREEN_OBJECT_ARROWHEAD_LENGTH,
|
||||||
|
fill: false,
|
||||||
|
ifShort: 'head',
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 arrow for the velocity
|
||||||
|
if (sim.getOption('display.velocity')) {
|
||||||
|
const speed = Math.sqrt(vx ** 2 + vy ** 2);
|
||||||
|
const endVx = x + VELOCITY_VECTOR_SCALE * vx / speed * Math.log(speed);
|
||||||
|
const endVy = y + VELOCITY_VECTOR_SCALE * vy / speed * Math.log(speed);
|
||||||
|
const style = VELOCITY_VECTOR_COLOR === 'object color' ?
|
||||||
|
`rgb(${r}, ${g}, ${b})` : VELOCITY_VECTOR_COLOR;
|
||||||
|
sim.display.drawArrow(x, y, endVx, endVy, {
|
||||||
|
style,
|
||||||
|
width: VELOCITY_VECTOR_WIDTH,
|
||||||
|
arrowhead: VELOCITY_VECTOR_ARROWHEAD,
|
||||||
|
fill: false,
|
||||||
|
ifShort: 'head'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw arrow for acceleration
|
||||||
|
if (sim.getOption('display.acceleration')) {
|
||||||
|
const accelerationMagnitude = Math.sqrt(acceleration.x ** 2 + acceleration.y ** 2);
|
||||||
|
const endAx = x + ACCELERATION_VECTOR_SCALE * acceleration.x /
|
||||||
|
accelerationMagnitude * Math.log(accelerationMagnitude);
|
||||||
|
const endAy = y + ACCELERATION_VECTOR_SCALE * acceleration.y /
|
||||||
|
accelerationMagnitude * Math.log(accelerationMagnitude);
|
||||||
|
const style = ACCELERATION_VECTOR_COLOR === 'object color' ?
|
||||||
|
`rgb(${r}, ${g}, ${b})` : ACCELERATION_VECTOR_COLOR;
|
||||||
|
sim.display.drawArrow(x, y, endAx, endAy, {
|
||||||
|
style,
|
||||||
|
width: ACCELERATION_VECTOR_WIDTH,
|
||||||
|
arrowhead: ACCELERATION_VECTOR_ARROWHEAD,
|
||||||
|
fill: false,
|
||||||
|
ifShort: 'tail'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,11 @@ import {Tool} from '../tool.js';
|
|||||||
export class PlayPause extends Tool {
|
export class PlayPause extends Tool {
|
||||||
playHTML = 'Play';
|
playHTML = 'Play';
|
||||||
pauseHTML = 'Pause';
|
pauseHTML = 'Pause';
|
||||||
|
clearTracesText = 'Clear Traces';
|
||||||
currentTimeEl = undefined;
|
currentTimeEl = undefined;
|
||||||
|
pauseButton = undefined;
|
||||||
|
playButton = undefined;
|
||||||
|
clearTracesEl = undefined;
|
||||||
|
|
||||||
get timeText() {
|
get timeText() {
|
||||||
let time = this.sim.time;
|
let time = this.sim.time;
|
||||||
@ -36,52 +40,59 @@ export class PlayPause extends Tool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateButtons() {
|
||||||
|
this.pauseButton.style.opacity = this.sim.playing ? '100%' : '50%';
|
||||||
|
this.playButton.style.opacity = this.sim.playing ? '50%' : '100%';
|
||||||
|
}
|
||||||
|
|
||||||
constructor(toolbar) {
|
constructor(toolbar) {
|
||||||
super(toolbar);
|
super(toolbar);
|
||||||
|
|
||||||
const currentTime = document.createElement('button');
|
const currentTime = document.createElement('button');
|
||||||
const pauseButton = document.createElement('button');
|
const pauseButton = document.createElement('button');
|
||||||
const playButton = document.createElement('button');
|
const playButton = document.createElement('button');
|
||||||
|
const clearTraces = document.createElement('button');
|
||||||
|
this.pauseButton = pauseButton;
|
||||||
|
this.playButton = playButton;
|
||||||
|
this.clearTracesEl = clearTraces;
|
||||||
this.currentTimeEl = currentTime;
|
this.currentTimeEl = currentTime;
|
||||||
|
|
||||||
this.div.appendChild(currentTime);
|
this.div.appendChild(currentTime);
|
||||||
this.div.appendChild(pauseButton);
|
this.div.appendChild(pauseButton);
|
||||||
this.div.appendChild(playButton);
|
this.div.appendChild(playButton);
|
||||||
|
this.div.appendChild(clearTraces);
|
||||||
|
|
||||||
currentTime.classList.add(TOOL_INFO_CLASSNAME);
|
currentTime.classList.add(TOOL_INFO_CLASSNAME);
|
||||||
currentTime.classList.add(WIDE_CLASSNAME);
|
currentTime.classList.add(WIDE_CLASSNAME);
|
||||||
|
clearTraces.classList.add(WIDE_CLASSNAME);
|
||||||
|
|
||||||
pauseButton.innerHTML = this.pauseHTML;
|
pauseButton.innerHTML = this.pauseHTML;
|
||||||
playButton.innerHTML = this.playHTML;
|
playButton.innerHTML = this.playHTML;
|
||||||
currentTime.innerHTML = this.timeText;
|
currentTime.innerHTML = this.timeText;
|
||||||
|
clearTraces.innerHTML = this.clearTracesText;
|
||||||
|
|
||||||
pauseButton.style.opacity = this.sim.playing ? '100%' : '50%';
|
this.updateButtons();
|
||||||
playButton.style.opacity = this.sim.playing ? '50%' : '100%';
|
|
||||||
|
|
||||||
pauseButton.addEventListener('click', (e) => {
|
pauseButton.addEventListener('click', () => {
|
||||||
e.stopPropagation();
|
|
||||||
this.sim.pointer.panning = undefined;
|
this.sim.pointer.panning = undefined;
|
||||||
if (this.playing) {
|
if (this.sim.playing) {
|
||||||
this.playing = false;
|
this.sim.playing = false;
|
||||||
pauseButton.style.opacity = '50%';
|
this.updateButtons();
|
||||||
playButton.style.opacity = '100%';
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
playButton.addEventListener('click', () => {
|
playButton.addEventListener('click', () => {
|
||||||
if (!this.playing) {
|
if (!this.sim.playing) {
|
||||||
this.playing = true;
|
this.sim.playing = true;
|
||||||
pauseButton.style.opacity = '100%';
|
this.updateButtons();
|
||||||
playButton.style.opacity = '50%';
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
get playing() {
|
clearTraces.addEventListener('click', () => {
|
||||||
return this.sim.playing;
|
// Obliterate object histories
|
||||||
}
|
this.sim.objects.forEachObject(obj => {
|
||||||
|
obj.history = [];
|
||||||
set playing(playing) {
|
}, null);
|
||||||
this.sim.playing = playing;
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user