Published
Edited
Jun 4, 2019
3 forks
Insert cell
md`
# AgentScript: Hello Model & D3 View
This is an introduction to using the core AgentScript library (no View) and using D3 for the view.
A great big Thank You to Mike, Jeremy, Philippe for not only [fixing it all](https://talk.observablehq.com/t/bug-report-svg-based-patch-grid-transform-fails/898) but introducing me to good D3 style.

First we'll import the HelloWorld.js sample model.
`
Insert cell
HelloModel = (await import("https://backspaces.github.io/agentscript/models/HelloModel.js")).default
Insert cell
md`
You can see the code [here.](https://backspaces.github.io/agentscript/models/HelloModel.js)
`
Insert cell
Insert cell
model = {
const model = new HelloModel()
model.setup()
return model
}
Insert cell
Insert cell
{
const width = model.world.width * patchSize
const height = model.world.height * patchSize
const svg = d3.select(DOM.svg(width, height))
.attr('style', 'border: 1px solid; padding: 10');

const g = svg.append('g');

g.call(transform)
.call(appendPatches)
.call(appendCircle)
.call(appendLines)
.call(appendTurtles);

// the above called only once, the loop repeats
while (true) {
model.step();
draw(g);
yield svg.node();
}
}
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
appendCircle = g => g
.append('circle')
.attr('x', 0)
.attr('y', 0)
.attr('r', 0.25)
.attr('fill', 'red')
Insert cell
appendLines = g => g
.selectAll('line')
.data(model.links)
.enter()
.append('line')
.attr('x1', d => d.end0.x)
.attr('y1', d => d.end0.y)
.attr('x2', d => d.end1.x)
.attr('y2', d => d.end1.y)
.attr('vector-effect', 'non-scaling-stroke')
.attr('style', 'stroke: red; 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('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('line')
// .data(model.links) // lines/turtles static, don't need rebinding.
.attr('x1', d => d.end0.x)
.attr('y1', d => d.end0.y)
.attr('x2', d => d.end1.x)
.attr('y2', d => d.end1.y)
g
.selectAll('use')
// .data(model.turtles)
.attr(
'transform',
d => `translate(${d.x},${d.y}) rotate(${d.theta * 180 / Math.PI})`
)
}
Insert cell
Insert cell
d3 = require("d3@5")
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 = 15
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