play/pause button

This commit is contained in:
Lentil Hoffman 2025-12-25 23:41:29 -06:00
parent d96aefd3f2
commit 6fd3bcae15
Signed by: lentil
GPG Key ID: 0F5B99F3F4D0C087
7 changed files with 137 additions and 17 deletions

View File

@ -12,3 +12,5 @@ export const MOTION_TIME_SCALE = 0.001;
export const OFFSCREEN_OBJECT_LINE_SCALE = 5; export const OFFSCREEN_OBJECT_LINE_SCALE = 5;
export const OFFSCREEN_OBJECT_LINE_WIDTH = 1.5; export const OFFSCREEN_OBJECT_LINE_WIDTH = 1.5;
export const OFFSCREEN_OBJECT_ARROWHEAD_LENGTH = 15; export const OFFSCREEN_OBJECT_ARROWHEAD_LENGTH = 15;
export const ZOOM_IN_FACTOR = 2;
export const ZOOM_OUT_FACTOR = 0.5;

View File

@ -15,7 +15,7 @@ body {
} }
div[id=simulator] { div[id=simulator] {
position: absolute; position: float;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;

View File

@ -1,4 +1,8 @@
import { POINTER_HISTORY_SIZE } from './config.js'; import {
POINTER_HISTORY_SIZE,
ZOOM_IN_FACTOR,
ZOOM_OUT_FACTOR,
} from './config.js';
export class Pointer { export class Pointer {
sim = undefined; sim = undefined;
@ -11,30 +15,36 @@ export class Pointer {
// Monitor mouse movements // Monitor mouse movements
const el = window; const el = window;
el.addEventListener('mousemove', e => { el.addEventListener('mousemove', e => {
// e.preventDefault();
this.handlePointerMove(this.sim.screenToSim(e.clientX, e.clientY)); this.handlePointerMove(this.sim.screenToSim(e.clientX, e.clientY));
}); });
// Monitor touch events // Monitor touch events
el.addEventListener('touchmove', e => { el.addEventListener('touchmove', e => {
// e.preventDefault();
const {pageX, pageY} = e.touches[0]; const {pageX, pageY} = e.touches[0];
this.handlePointerMove(this.sim.screenToSim(pageX, pageY)); this.handlePointerMove(this.sim.screenToSim(pageX, pageY));
}); });
el.addEventListener('pointerdown', e => { el.addEventListener('pointerdown', e => {
// e.preventDefault();
this.handlePointerDown(this.sim.screenToSim(e.clientX, e.clientY)); this.handlePointerDown(this.sim.screenToSim(e.clientX, e.clientY));
}); });
el.addEventListener('pointerup', e => { el.addEventListener('pointerup', e => {
// e.preventDefault();
this.handlePointerUp(this.sim.screenToSim(e.clientX, e.clientY)); this.handlePointerUp(this.sim.screenToSim(e.clientX, e.clientY));
}); });
el.addEventListener('click', e => { el.addEventListener('click', e => {
// e.preventDefault();
}); });
// Monitor wheel events // Monitor wheel events
el.addEventListener('wheel', e => { el.addEventListener('wheel', e => {
// e.preventDefault();
// Wheel scroll down => positive deltaY => ZOOM IN // Wheel scroll down => positive deltaY => ZOOM IN
const factor = e.deltaY > 0 ? 2 : 0.5; const factor = e.deltaY > 0 ? ZOOM_IN_FACTOR : ZOOM_OUT_FACTOR;
this.sim.scheduleZoom(this.sim.screenToSim(e.clientX, e.clientY), factor); this.sim.scheduleZoom(this.sim.screenToSim(e.clientX, e.clientY), factor);
}); });

View File

@ -2,12 +2,15 @@ import { Display } from './display.js';
import { Overlay } from './overlay.js'; import { Overlay } from './overlay.js';
import { Pointer } from './pointer.js'; import { Pointer } from './pointer.js';
import { Objects } from './objects.js'; import { Objects } from './objects.js';
import { Toolbar } from './toolbar.js';
import { PlayPause } from './tools/play-pause.js';
export class Sim { export class Sim {
info = {}; info = {};
frame = 0; frameCount = 0;
time = undefined; time = undefined;
nextZoom = undefined; nextZoom = undefined;
playing = true;
display = undefined; display = undefined;
overlay = undefined; overlay = undefined;
@ -23,6 +26,10 @@ export class Sim {
this.overlay = new Overlay(this); this.overlay = new Overlay(this);
this.pointer = new Pointer(this); this.pointer = new Pointer(this);
this.objects = new Objects(this); this.objects = new Objects(this);
this.toolbar = new Toolbar(this);
// Set up toolbar
this.toolbar.addTool(new PlayPause(this.toolbar));
// Initiate main loop // Initiate main loop
this.time = document.timeline.currentTime; this.time = document.timeline.currentTime;
@ -43,12 +50,23 @@ export class Sim {
this.display.viewOrigin.y = y - this.display.height / 2; this.display.viewOrigin.y = y - this.display.height / 2;
} }
// Transform display coordinates to simulator coordinates using scale and viewOrigin
screenToSim(x, y) { screenToSim(x, y) {
return this.display.screenToSim(x, y); return this.display.screenToSim(x, y);
} }
play() {
this.playing = true;
}
pause() {
this.playing = false;
}
// Main loop // Main loop
loop(currentTime) { loop(currentTime) {
if (this.playing) {
this.frameCount += 1;
const elapsedTime = currentTime - this.time; const elapsedTime = currentTime - this.time;
this.time = currentTime; this.time = currentTime;
if (this.nextZoom) { if (this.nextZoom) {
@ -62,7 +80,8 @@ export class Sim {
this.display.drawObjects(); this.display.drawObjects();
this.overlay.renderInfo(); this.overlay.renderInfo();
}
requestAnimationFrame(t => this.loop(t)); requestAnimationFrame(t => this.loop(t));
} }
} }

20
tool.js Normal file
View File

@ -0,0 +1,20 @@
// Idea here is, tool can declare its parameters;
// can call back to toolbar for whatever...
// through toolbar can access sim
export class Tool {
toolbar = undefined;
sim = undefined;
constructor(toolbar) {
this.toolbar = toolbar;
this.sim = this.toolbar.sim;
const div = document.createElement('div');
this.div = div;
div.style.position = 'inline-block';
div.style.border = '1px #0fb solid';
div.style.margin = 10;
}
frame() {}
}

30
toolbar.js Normal file
View File

@ -0,0 +1,30 @@
export class Toolbar {
sim = undefined;
tools = [];
constructor(sim) {
this.sim = sim;
// Create ourselves a div, as child of sim's div
const div = document.createElement('div');
this.div = div;
this.sim.div.appendChild(div);
div.style.position = 'absolute';
div.style.top = 0;
div.style.left = 0;
div.style.zIndex = 2;
}
// tool: instance of Tool
addTool(tool) {
this.div.appendChild(tool.div);
this.tools.push(tool);
}
frame() {
for (let tool in this.tools) {
// TODO: tool.frame()
}
}
}

39
tools/play-pause.js Normal file
View File

@ -0,0 +1,39 @@
import { Tool } from '../tool.js';
export class PlayPause extends Tool {
constructor(toolbar) {
super(toolbar);
const playHTML = 'Play';
const pauseHTML = 'Pause';
// For now, use a regular button
const button = document.createElement('button');
this.div.appendChild(button);
if (this.playing) {
button.innerHTML = pauseHTML;
} else {
button.innerHTML = playHTML;
}
button.addEventListener('click', (e) => {
e.stopPropagation();
if (this.playing) {
button.innerHTML = playHTML;
this.playing = false;
} else {
button.innerHTML = pauseHTML;
this.playing = true;
}
});
console.log('PlayPause tool constructed ~!~');
}
get playing() {
return this.sim.playing;
}
set playing(playing) {
return this.sim.playing = playing;
}
}