agentscript
Version:
AgentScript Model in Model/View architecture
154 lines (130 loc) • 4.79 kB
HTML
<html>
<head>
<title>tsp</title>
</head>
<body>
<script type="module">
import * as util from 'https://code.agentscript.org/src/utils.js'
import Model from 'https://code.agentscript.org/models/TspModel.js'
import TwoDraw from 'https://code.agentscript.org/src/TwoDraw.js'
import Animator from 'https://code.agentscript.org/src/Animator.js'
import Mouse from 'https://code.agentscript.org/src/Mouse.js'
import Keyboard from 'https://code.agentscript.org/src/Keyboard.js'
import GUI from 'https://code.agentscript.org/src/GUI.js'
import Plot from 'https://code.agentscript.org/src/Plot.js'
//NOTE: model width doesn't show until a step taken
// ditto turtle size
// ==== Define draw options ====
const breedSize = { nodes: 2, travelers: 0 }
const drawOptions = {
patchesColor: 'black',
turtlesShape: 'circle',
turtlesSize: t => breedSize[t.breed.name],
turtlesColor: 'yellow',
linksColor: 'red',
}
// =========== Init Model, View, Animator ===================
const model = new Model()
await model.startup()
model.setup()
const view = new TwoDraw(model, {
div: 'modelDiv',
width: 500,
drawOptions,
})
const anim = new Animator(
() => {
if (model.done) anim.stop()
model.step()
view.draw()
updatePlot()
},
-1, // run until model stops: best tour constant for 500 steps
30 // 30 fps
).startStats()
anim.setIdle(() => view.draw())
// ==== Define keyboard commands ====
const keyCommands = [
{ key: 's', cmd: () => anim.toggle() },
{ key: 'o', cmd: () => anim.once() },
{ key: 'd', cmd: () => view.downloadCanvas() },
]
const keyboard = new Keyboard(keyCommands).start()
// =========== UI Elements ===================
let template = {
fps: {
slider: [40, [5, 60, 5]],
cmd: val => anim.setFps(val),
},
stop: {
switch: !anim.isRunning, // bool
cmd: val => { if (val) { anim.stop() } else { anim.start() } },
},
once: {
button: () => anim.once()
},
modelWidth: {
slider: [500, [100, 1000, 25]],
cmd: val => view.width = val,
},
turtlesShape: {
chooser: ['circle', ['bug', 'dart', 'person', 'circle', 'arrow']],
cmd: val => view.drawOptions.turtlesShape = val,
},
turtlesSize: {
slider: [3, [1, 10, 1]],
cmd: val => view.drawOptions.turtlesSize = val,
},
downloadCanvas: {
button: () => view.downloadCanvas()
},
bestTourLength: {
monitor: [model, 'bestTourLength'],
},
modelTicks: {
monitor: [model, 'ticks'],
},
downloadCanvas: {
button: () => view.downloadCanvas()
},
}
const gui = new GUI(template, 280)
// ============ Mouse Handling ==================
let selectedTurtle
const mouse = new Mouse(model, view, mouse => {
const { x, y, action } = mouse
switch (action) {
case 'mousedown':
selectedTurtle = model.nodes.minOneOf(t => t.distanceXY(x, y))
break
case 'mousedrag':
if (selectedTurtle) selectedTurtle.setxy(x, y)
break
case 'mouseup':
selectedTurtle = null
break
}
view.draw() // Draw whenever mouse has an event
}).start()
// ============ Plot new tours ==================
const pens = {
tourLength: 'red' // red lines
}
const options = {
title: 'Data',
width: 800,
height: 200,
}
const plot = new Plot('plotDiv', pens, options)
function updatePlot() {
if (model.bestTourLength === pens.tourLength) return
pens.tourLength = model.bestTourLength
plot.linePlot(pens)
}
// ============ Done w/ controllers! ==================
util.toWindow({ util, model, view, anim, gui, plot })
</script>
<div id="modelDiv"></div>
<div id="plotDiv"></div>
</body>
</html>