agentscape
Version:
Agentscape is a library for creating agent-based simulations. It provides a simple API for defining agents and their behavior, and for defining the environment in which the agents interact. Agentscape is designed to be flexible and extensible, allowing
150 lines (123 loc) • 5.57 kB
text/typescript
// 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 = `
<style>${style}</style>
<div class="row">
<button title="Space" id="play-pause"></button>
<button title="Enter" id="step">Step</button>
<label for="fpsSetter">Framerate</label>
<input type="range" min="1" max="60" id="fpsSetter">
<input type="number" id="fpsDisplay" disabled>
<label for="toggleInspectorPane">Inspector</label>
<input type="checkbox" id="toggleInspectorPane">
<label for="setLogLevel">Log Level</label>
<select id="setLogLevel">
<option value=-1>Off</option>
<option value=0>Debug</option>
<option value=1>Info</option>
<option value=2>Warn</option>
<option value=3>Error</option>
</select>
<div>
`
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