Public
Edited
Dec 22, 2023
Insert cell
Insert cell
chart_canvas = {
const context = DOM.context2d(width, height);
const canvas = context.canvas;

let simulation = d3
.forceSimulation(dataset)

.force(
"x",
d3
.forceX()
.x((d) => {
return xScale(d.xValues);
})
.strength(0.2)
)
.force("y", d3.forceY(height / 2).strength(0.1))
.force(
"collide",
d3
.forceCollide()
.radius((d) => rScale(d.count) * 1.08)
.strength(0.1)
.iterations(4)
)
// .force("center", forceBoundary(20, 20, width - 20, height - 20).border(3))

.on("tick", render);
function render() {
// console.log(dataset[0].x);
context.clearRect(0, 0, width, height);
dataset.forEach((d) => {
const halfBlueArcSpan = Math.PI * d.demoncratPercentage;
const halfRedArcSpan = Math.PI * (1 - d.demoncratPercentage);
// Draw the blue arc
context.beginPath();
context.arc(
d.x,
d.y,
rScale(d.count),
Math.PI + halfBlueArcSpan, // start from the top (12 o'clock)
Math.PI - halfBlueArcSpan, // move counterclockwise
true // this makes it go counterclockwise
);
context.fillStyle = "#99C0E5";
context.fill();

// Draw the red arc
context.beginPath();
context.arc(
d.x,
d.y,
rScale(d.count),
0 - halfRedArcSpan,
0 + halfRedArcSpan
);
context.fillStyle = "#FDA5A8";
context.fill();

// text
context.beginPath();
context.font = `${Math.max(rScale(d.count) / 2, 8)}px serif`;
context.textAlign = "center";
context.fillStyle = "black";
context.fillText(d.name, d.x, d.y);
context.font = `${Math.max(rScale(d.count) / 4, 8)}px serif`;
context.fillText(
`${format(d.count * d.demoncratPercentage)} - ${format(
d.count * (1 - d.demoncratPercentage)
)}`,
d.x,
d.y + 15
);
});
}

d3.select(canvas).call(drag(simulation));
return canvas;
}
Insert cell
format = d3.format(".0f")
Insert cell
a = d3.format(".3s")
Insert cell
a(.1)
Insert cell
function drag(simulation) {
function dragSubject(event) {
let quadtree = d3
.quadtree()
.x((d) => d.x)
.y((d) => d.y)
.addAll(dataset);

return quadtree.find(event.x, event.y, Infinity);
}

//STEP 1. raise the dragged circle and start the simulation engine
//STEP 1 Instead: We don't have to raise the circle because they will not overlap due to the forces so I can just do one thing:
//STEP 1.1 make sure the dragged circle is centered to my mouse
function dragStart(event) {
simulation.alphaTarget(0.3).restart();
}

//STEP 2. change the dragged circles position to pinned fx,fy
function dragging(event) {
console.log(event);
event.subject.fx = event.x;
event.subject.fy = event.y;
}
//STEP 3. turn the simulation engine off and s
function dragEnd(event) {
event.subject.fx = null;
event.subject.fy = null;
simulation.alphaTarget(0);
}

return d3
.drag()
.subject(dragSubject)
.on("start", dragStart)
.on("drag", dragging)
.on("end", dragEnd);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// function boundingBoxForce() {
// let nodes = [];
// let min
// function force(alpha) {
// nodes.forEach((node) => {
// // make sure the range of node.x is between [minx, max]
// // when x is bigger than width. make it the smaller value of the two[x, width], aka, width
// node.x = Math.min(node.x, maxX);
// // when x is smaller than width, approach negative, make it the left edge of width
// node.x = Math.max(node.x, minX);

// node.y = Math.min(node.x, maxX);
// node.y = Math.max(node.x, minY);
// });
// }
// force.initialize = (_) => {
// nodes = _;
// };

// force.minX = () => {
// arguments.length ?
// }
// return force;
// }
Insert cell
// dataset = data1.topics.map((d) => {
// let demoncratPercentage = fractionOfA(d.parties[0].count, d.parties[1].count);
// return {
// // ...d,
// name: d.name,
// count: d.count,
// demoncratPercentage,
// xValues: 0.5 - Math.max(0.1, Math.min(0.9, demoncratPercentage))
// };
// })
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