// 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