Published
Edited
Dec 4, 2020
2 forks
2 stars
Insert cell
Insert cell
animation = {
const svg = d3.create("svg")
.attr("height", p.h)
.attr("width", p.w)
.attr("style", "fill: none; stroke: steelblue; border: 1px solid silver;")

let tree = new Node(7) // ← arg is depth

const frame = () => {
tree.update()
// console.log(tree)


// make array of points
// let flatTree = tree.flattern()

// svg.selectAll('line')
// .data(flatTree, d => d)
// .join('line')
// .attr('x1', d => d.points[0][0])
// .attr('y1', d => d.points[0][1])
// .attr('x2', d => d.points[1][0])
// .attr('y2', d => d.points[1][1])
// // .attr('stroke', `rgb(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255})`)
// .attr('stroke', `steelblue`)
// // .attr('stroke-width', d => d.depth)

tree.draw(svg)

// .attr('d', d => pointsToSplinePath([//d.points[0],
// findSegmentPoint(d.points[0], d.points[2], 0.5),
// //d.points[2],
// findSegmentPoint(d.points[2], d.points[3], 0.5),
// //d.points[3],
// findSegmentPoint(d.points[3], d.points[1], 0.5),
// //d.points[1],
// findSegmentPoint(d.points[1], d.points[0], 0.5),


// ],
// true))
// .attr('d', d => pointsToSplinePath([findSegmentPoint(d.points[0], d.points[2], 0.5),
// findSegmentPoint(d.points[2], d.points[3], 0.5),
// findSegmentPoint(d.points[3], d.points[1], 0.5),
// findSegmentPoint(d.points[1], d.points[0], 0.5)],
// true))
// .attr('stroke', `steelblue`)
// .attr('stroke-width', 2)

// // right and bottom lines
// svg.selectAll('line.root-v')
// .data([0])
// .join('line')
// .classed('root-v', true)
// .attr('x1', tree.points[2][0])
// .attr('y1', tree.points[2][1])
// .attr('x2', tree.points[3][0])
// .attr('y2', tree.points[3][1])
// .attr('stroke', `steelblue`)
// // .attr('stroke-width', tree.depth)
// svg.selectAll('line.root-h')
// .data([0])
// .join('line')
// .classed('root-h', true)
// .attr('x1', tree.points[1][0])
// .attr('y1', tree.points[1][1])
// .attr('x2', tree.points[3][0])
// .attr('y2', tree.points[3][1])
// .attr('stroke', `steelblue`)
// // .attr('stroke-width', tree.depth)

requestAnimationFrame(frame)
}
frame()
// invalidation.then(() => cancelAnimationFrame(animation))
return svg.node()
}
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Node = function Node(depth, parent=null, siblingIndex = 0) {
this.seed = '' + Math.random()
this.depth = depth
this.parent = parent
this.siblingIndex = siblingIndex
this.children = []
if (depth > 0) {
this.children = [new Node(depth - 1, this, 0), new Node(depth - 1, this, 1)]
this.orientation = depth % 2 ? 'h' : 'v'
}

this.update = () => {
const simplex = new noise(this.seed)
let time = + new Date / 50000
this.proportion = [simplex.noise3D(time, 1000, 10000) / 2 + 0.5,
simplex.noise3D(time, 2000, 10000) / 2 + 0.5]

this.points = []
if (parent) {
if (siblingIndex == 0) { // upper or left
this.points[0] = parent.points[0]
this.points[1] = parent.points[2]
this.points[2] = findSegmentPoint(parent.points[0], parent.points[1], parent.proportion[0])
this.points[3] = findSegmentPoint(parent.points[2], parent.points[3], parent.proportion[1])
}
else { // lower or right
this.points[0] = findSegmentPoint(parent.points[0], parent.points[1], parent.proportion[0])
this.points[1] = findSegmentPoint(parent.points[2], parent.points[3], parent.proportion[1])
this.points[2] = parent.points[1]
this.points[3] = parent.points[3]
}
}
else { // root node
this.points = [
[p.m.l, p.m.t],
[p.m.l, p.h - p.m.b],
[p.w - p.m.r, p.m.t],
[p.w - p.m.r, p.h - p.m.b],
]
}

if (this.children) this.children.forEach(d => d.update())
}

this.draw = (svg) => {
// svg.selectAll('line')
// .data(this.children, d => d.seed)
// .join(
// enter => enter.append("line")
// .attr('stroke', `white`)
// .attr('stroke-width', this.depth),
// update => update
// .attr('x1', d => d.points[0][0])
// .attr('y1', d => d.points[0][1])
// .attr('x2', d => d.points[1][0])
// .attr('y2', d => d.points[1][1]),
// exit => {},
// )

if (this.children.length > 0) {
this.children.forEach(d => d.draw(svg))
}
else {
// console.log('yo')
svg.selectAll('path')
.data([this], d => d.seed)
.join(
enter => enter.append("path")
// .attr('fill', `white`)
,
update => update
// .call(drawBezierCurves, this),
.attr('d', d => {
let middle02 = findSegmentPoint(d.points[0], d.points[2], 0.5)
let middle23 = findSegmentPoint(d.points[2], d.points[3], 0.5)
let middle31 = findSegmentPoint(d.points[3], d.points[1], 0.5)
let middle10 = findSegmentPoint(d.points[1], d.points[0], 0.5)
let path = d3.path()
path.moveTo(...middle02)
path.bezierCurveTo(...d.points[2], ...d.points[2], ...middle23)
path.bezierCurveTo(...d.points[3], ...d.points[3], ...middle31)
path.bezierCurveTo(...d.points[1], ...d.points[1], ...middle10)
path.bezierCurveTo(...d.points[0], ...d.points[0], ...middle02)
return path.toString()
})
.attr('transform', d => {
let meanX = d3.mean(d.points, p => p[0])
let meanY = d3.mean(d.points, p => p[1])
return `translate(${meanX} ${meanY}) scale(0.9) translate(${-meanX} ${-meanY})`
}),
exit => {},
)
}

}

this.flattern = () => {
let flatTree = [this]
if (this.v) this.v.forEach(d => {
flatTree.push(...d.flattern())
})
if (this.h) this.h.forEach(d => {
flatTree.push(...d.flattern())
})
return flatTree
}
}

Insert cell
Insert cell
findSegmentPoint = (p1, p2, proportion) => {
let p = [p1[0] + (p2[0] - p1[0]) * proportion,
p1[1] + (p2[1] - p1[1]) * proportion, ]
return p
}
Insert cell
p = {
return {
m: {t: 100, r: 50, b: 100, l: 50},
w: 594,
h: 841,
}
}
Insert cell
// timeCurve = (time) => {
// let t = time / 1000
// let whole = Math.floor(t)
// let decimal = t % 1
// return 1000 * (whole + 1 - ((1 - decimal) ** 6))
// }
Insert cell
// time = {
// while (true) {
// yield + new Date() / 1000
// // await Promises.tick(10)
// }
// }
Insert cell
import {pointsToSplinePath, noise} from "@illus0r/snippets"
Insert cell
Insert cell
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