// The control bar at the bottom of the canvas pane.
// it contains the play/pause button, the step button, and the speed control
import Log from '../../Log'
enum PlayPauseState {
Play = 'Play',
Pause = 'Pause'
}
class AnimationToolbar extends HTMLElement {
private playPauseBtnRef: HTMLButtonElement
private stepBtnRef: HTMLButtonElement
private fpsSetterRef: HTMLInputElement
private fpsDisplayRef: HTMLInputElement
private playPauseState: PlayPauseState
public connectedCallback() {
const style = `
.row {
border-top: 1px solid black;
display: flex;
justify-content: flex-start;
align-items: center;
}
button {
width: 50px;
height: 25px;
margin: 3px;
}
label {
margin-left: 5px;
margin-right: 3px;
}
#fpsDisplay {
width: 35px;
}
`
const template = document.createElement('template')
template.innerHTML = `
`
const shadowRoot = this.attachShadow({mode: 'open'})
shadowRoot.appendChild(template.content.cloneNode(true))
this.fpsDisplayRef = shadowRoot.getElementById('fpsDisplay') as HTMLInputElement
this.fpsSetterRef = shadowRoot.getElementById('fpsSetter') as HTMLInputElement
this.playPauseBtnRef = shadowRoot.getElementById('play-pause') as HTMLButtonElement
this.stepBtnRef = shadowRoot.getElementById('step') as HTMLButtonElement
// the inspector pane toggle emits a custom event to toggle the inspector pane
// the event detail is wherever the checkbox is checked or not
const toggleInspectorPane = shadowRoot.getElementById('toggleInspectorPane') as HTMLInputElement
toggleInspectorPane.addEventListener('change', (e) => {
window.dispatchEvent(new CustomEvent('toggleInspectorPane', {detail: (e.target as HTMLInputElement).checked}))
})
const toggleLogs = shadowRoot.getElementById('setLogLevel') as HTMLSelectElement
toggleLogs.addEventListener('change', (e) => {
Log.setLevel(parseInt((e.target as HTMLInputElement).value))
})
this.playPauseBtnRef.addEventListener('click', this.handlePlayPauseClick.bind(this))
this.stepBtnRef.addEventListener('click', this.handleStepClick.bind(this))
// set playPauseState to Play if autoPlay is true
if (this.getAttribute('autoPlay') === 'true') {
this.playPauseState = PlayPauseState.Play
this.playPauseBtnRef.innerHTML = PlayPauseState.Pause
} else {
this.playPauseState = PlayPauseState.Pause
this.playPauseBtnRef.innerHTML = PlayPauseState.Play
}
// init the frame rate setter
const fps = this.getAttribute('fps') || '60'
this.fpsDisplayRef.value = fps
this.fpsSetterRef.value = fps
this.fpsSetterRef.addEventListener('change', this.handleFpsChange.bind(this))
// keep the play/pause button in sync with the simulation state
window.addEventListener('play', () => {
this.playPauseState = PlayPauseState.Play
this.playPauseBtnRef.innerText = PlayPauseState.Pause
})
window.addEventListener('pause', () => {
this.playPauseState = PlayPauseState.Pause
this.playPauseBtnRef.innerText = PlayPauseState.Play
})
}
private handlePlayPauseClick() {
if (this.playPauseState === PlayPauseState.Play) {
// if the simulation is playing, pause it
this.playPauseBtnRef.innerText = PlayPauseState.Play
this.playPauseState = PlayPauseState.Pause
// emit a custom 'play' event
window.dispatchEvent(new CustomEvent('pause'))
} else {
// if the simulation is paused, play it
this.playPauseBtnRef.innerText = PlayPauseState.Pause
this.playPauseState = PlayPauseState.Play
// emit a custom 'pause' event
window.dispatchEvent(new CustomEvent('play'))
}
}
private handleStepClick() {
// emit a custom 'step' event if the simulation is paused
window.dispatchEvent(new CustomEvent('step'))
}
private handleFpsChange() {
// emit a custom 'fps' event
this.fpsDisplayRef.value = this.fpsSetterRef.value
window.dispatchEvent(new CustomEvent('fps', {detail: this.fpsSetterRef.value}))
}
}
customElements.define('animation-toolbar', AnimationToolbar)
export default AnimationToolbar