Published
Edited
Sep 5, 2020
1 star
Insert cell
Insert cell
AS = import("https://agentscript.org/dist/agentscript.esm.js")
Insert cell
FlockModel =
(await import("https://agentscript.org/models/FlockModel.js")).default
Insert cell
Insert cell
model = {
const world = AS.World.defaultWorld(33, 16)
const model = new FlockModel(world)
model.setup()
return model
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
run = {
const svg = d3.select(svgElement)
.attr('style', 'border: 1px solid; padding: 10')

const g = svg.append('g')
g.call(transform)
.call(appendPatches)
.call(appendTurtles)

const vegaView = new Vega.View(Vega.parse(VegaLite.compile(vegaSpec).spec))
.initialize(vegaDiv).run()
// the above called only once, the loop repeats
let x = 0
let y = 0
while (y < 0.98) {
model.step()
draw(g)
y = model.flockVectorSize()
vegaDraw(vegaView, x++, y)
yield svgElement
}
}
Insert cell
Insert cell
transform = g => g.attr(
'transform',
`
scale(${patchSize}, ${-patchSize})
translate(${-model.world.minXcor}, ${-model.world.maxYcor})
`
)
Insert cell
appendPatches = g => g
.selectAll('rect')
.data(model.patches)
.enter()
.append('rect')
.attr('x', d => d.x - 0.5) // note the .5 outset, patch coords
.attr('y', d => d.y - 0.5) // are in the patch center! Cool.
.attr('width', 1)
.attr('height', 1)
.attr('vector-effect', 'non-scaling-stroke')
.attr(
'style',
d => `fill: ${randomLightGray()}; stroke: gray; stroke-width: 0.5;`
)
Insert cell
appendTurtles = g => {
g
.append('defs')
.append('g')
.attr('id', 'dart')
.append('polygon')
.attr('points', '0.5,0, -0.5,0.4, -0.25,0, -0.5,-0.4')
// .attr('transform', 'scale(2)')
.attr('transform', `scale(${turtleSize})`)
.attr('vector-effect', 'non-scaling-stroke')
.attr('style', 'stroke: black; stroke-width: 1px')

g
.selectAll('.dart')
.data(model.turtles)
.enter()
.append('use')
.attr('xlink:href', '#dart')
.attr('style', d => `fill: ${randomColor()}`)
}
Insert cell
Insert cell
draw = g => {
g
.selectAll('use')
// .data(model.turtles)
.attr(
'transform',
d => `translate(${d.x},${d.y}) rotate(${d.theta * 180 / Math.PI})`
)
}
Insert cell
Insert cell
vegaSpec = ({
$schema: "https://vega.github.io/schema/vega-lite/v2.json",
data: {
name: "table"
},
width: width - 50,
mark: "line",
encoding: {
x: {
field: "x",
type: "quantitative",
scale: {
zero: false
}
},
y: {
field: "y",
type: "quantitative"
},
}
})
Insert cell
Insert cell
vegaDraw = (vegaView, x, y) => {
const changeSet = Vega.changeset()
.insert({x, y})
vegaView.change('table', changeSet).run()
}
Insert cell
Insert cell
function randomLightGray() {
const g = randomInt2(200, 255)
return `rgb(${g},${g},${g})`
}
Insert cell
function randomColor() {
const rgb = () => Math.round((randomInt2(0, 3) * 255) / 2)
return `rgb(${rgb()},${rgb()},${rgb()})`
}

Insert cell
randomInt2 = (min, max) => min + Math.floor(Math.random() * (max - min))

Insert cell
patchSize = 13
// patchSize = width / model.world.numX
Insert cell
turtleSize = 1.25
Insert cell
d3 = require("d3@5")
Insert cell
Vega = require('vega@3')
Insert cell
VegaLite = require('vega-lite@2/build/vega-lite.min.js')
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more