Public
Edited
Oct 23, 2022
1 fork
2 stars
Insert cell
Insert cell
test = {
let svg = d3.create('svg')
.attr('viewBox', [-width/2, -width/4, width, width/2])

let paths = svg.append('g').selectAll('path')
// svg.append('circle')
// .attr('cx', 0)
// .attr('cy', 0)
// .attr('r', 50)
// .attr('stroke', 'red')

// let cornerpoints = svg.append('g').selectAll('path')

function update(data) {
paths = paths
.data(data)
.join(enter => enter
.append("path")
.style("fill", "black")
.attr('d', drawPath)
)
.call(d => d.transition()
.attrTween("d", function(d){ return flubber.interpolate(this.getAttribute('d'), drawPath(d))})
)


// points = points
// .data(data[0])
// .join(enter => enter
// .append("circle")
// .style("fill", "green")
// .attr("cx", d => d.x)
// .attr("cy", d => d.y)
// .attr("r", 2)
// )
}

Object.assign(svg.node(), { update })
return svg.node()
}
Insert cell
{
test.update(data)
}
Insert cell
round_points = roundCorners(data[0])
Insert cell
drawRoundedPoly(data[0], 20)
Insert cell
drawRoundedPoly = function(pts, radius) {
let round_points = roundPolygon(pts, radius)

let ctx = d3.path()
// ctx.beginPath()
round_points.forEach((p, i) => {
!i && ctx.moveTo(p.in.x, p.in.y)
ctx.arcTo(p.x, p.y, p.out.x, p.out.y, p.arc.radius)
ctx.lineTo(p.next.in.x, p.next.in.y)
})
ctx.closePath()
return ctx.toString()
}
Insert cell
function roundCorners(_points) {
let corner_radius = 10
let points = Object.assign([], _points)
let vecs = points.map((pt, idx, pts) => {
let pt2 = pts[(idx+1) % points.length]
return {dx: pt2.x - pt.x, dy: pt2.y - pt.y}
})

let lengths = vecs.map(vec => Math.sqrt(Object.values(vec).reduce((s,v) => s + Math.pow(v, 2), 0)))
let normvecs = vecs.map((vec, i) => {return {dx: vec.dx/lengths[i], dy: vec.dy/lengths[i]}})
let angles = vecs.map(vec => Math.atan2(vec.dx, vec.dy))
let ext_angles = angles.map((a, i, angles) => {
let a2 = angles[(i+1) % angles.length]
return a2-a
})

let corner_setbacks = ext_angles.map(a => Math.abs(corner_radius * Math.tan(a/2)))
// return corner_setbacks
let setbackvecs_1 = normvecs.map((vec, i) => {return {dx: vec.dx * corner_setbacks[i],
dy: vec.dy * corner_setbacks[i]}
})
let setbackvecs_2 = normvecs.map((vec, i) => {return {dx: vec.dx * corner_setbacks[(i+points.length-1)%points.length],
dy: vec.dy * corner_setbacks[(i+points.length-1)%points.length]}
})
// return setbackvecs
corner_setbacks.map((v, i) => v + corner_setbacks[(i+1)%corner_setbacks.length] < lengths[i+1]) //setback pair lengths for each edge compared to edge length

let new_points = points.map((pt,i, points) => [{x: pt.x + setbackvecs_2[i].dx,
y: pt.y + setbackvecs_2[i].dy},
{x: points[(i+1)%points.length].x - setbackvecs_1[i].dx,
y: points[(i+1)%points.length].y - setbackvecs_1[i].dy}
])

// return new_points
let ctx = d3.path()
ctx.moveTo(new_points[0][0].x, new_points[0][0].y)
new_points.forEach((point_pair, i, new_points) => {
ctx.lineTo(point_pair[1].x, point_pair[1].y)
ctx.arcTo(points[(i+1)%points.length].x,
points[(i+1)%points.length].y,
new_points[(i+1)%new_points.length][0].x,
new_points[(i+1)%new_points.length][0].y,
corner_radius)
})

return ctx.toString()
}
Insert cell
function drawPath(_points) {
return drawRoundedPoly(_points, 20)
// let points = Object.assign([], _points)
// let ctx = d3.path()
// ctx.moveTo(points[0].x, points[0].y)
// while(points.length) {
// let pt = points.pop()
// ctx.lineTo(pt.x, pt.y)
// }
// return ctx.toString()
}
Insert cell
data = {
// asdf
while(true) {
yield [randomPoly()]
await Promises.delay(2000)
}
}
Insert cell
randomPoly = () => {
let avg_pts = 10
let theta = 0
let angles = []
while (theta < 2*Math.PI) {
angles.push(theta)
theta += d3.randomUniform(0, 2*2*Math.PI/(avg_pts))()
}
let max_radius = width/6
let min_radius = width/24
let pts = angles.map(t => {
let r = d3.randomUniform(min_radius, max_radius)()
return {x: r*Math.sin(t), y: r*Math.cos(t)}
})
return pts
}
Insert cell
roundPolygon(randomPoly(), 20)
Insert cell
roundPolygon = (await import('round-polygon')).default
Insert cell
d3 = require('d3@6')
Insert cell
flubber = require('flubber')
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