Public
Edited
Feb 3, 2023
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
d3_angle = (a) => (a[0] < 0) ? (Math.PI * 2 - angle(a, [0, 1])) : (angle(a, [0, 1]))
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
const width = 400;
const height = 400;
const margin = {top: 30, right: 30, bottom: 30, left: 30};
const x = d3.scaleLinear()
.domain([-1, 1])
.range([margin.left, width - margin.right]);

const y = d3.scaleLinear()
.domain([-1, 1])
.range([height - margin.bottom, margin.top]);

const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);

svg.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x));

svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y));

let a = [-0.4, 0.4];
let b = [1, 0];

const arcPath = svg.append("path")
.attr("transform", `translate(${x(0)}, ${y(0)})`)
.attr("fill", "transparent")
.attr("stroke", "gray");
let l1 = svg.append('line')
.attr("x1", x(0))
.attr("y1", y(0))
.attr("x2", x(a[0]))
.attr("y2", y(a[1]))
.attr("stroke", color1);
let c1 = svg.append('circle')
.attr("cx", x(a[0]))
.attr("cy", y(a[1]))
.attr("r", 4)
.attr("fill", color1);

let l2 = svg.append('line')
.attr("x1", x(0))
.attr("y1", y(0))
.attr("x2", x(b[0]))
.attr("y2", y(b[1]))
.attr("stroke", color2);
let c2 = svg.append('circle')
.attr("cx", x(b[0]))
.attr("cy", y(b[1]))
.attr("fill", color2)
.attr("r", 4);

const arc = d3.arc()
.innerRadius(0)
.outerRadius(20)
.startAngle(0)
.endAngle(angle(a, b));

const angleFormat = d3.format(".0f");
const angleText = svg.append("text")
.attr("text-anchor", "middle")
.attr("alignment-baseline", "middle")
.attr("font-size", "12px")
.attr("transform", `translate(${x(0)}, ${y(0)})`);
const render = function() {
const clockwise = angle2(b, a) > 0;
const innerAngle = angle(a, b);
const startAngle = clockwise ? d3_angle(a) : d3_angle(b);

arcPath.attr("d", (arc.startAngle(0).endAngle(innerAngle))())
.attr("transform", `translate(${x(0)}, ${y(0)}) rotate(${startAngle * 180 / Math.PI})`);

let bis = normalize(bisect(a, b));
angleText
.text(angleFormat((innerAngle) * 180 / Math.PI) + "°")
.attr("transform", `translate(${x(bis[0] / 6)}, ${y(bis[1] / 6)})`);
}
const drag1 = d3.drag()
.on("drag", (event, d) => {
a = [x.invert(event.x), y.invert(event.y)];
a = normalize_vecs.length > 0 ? normalize(a) : a;
c1.attr("cx", x(a[0])).attr("cy", y(a[1]));
l1.attr("x2", x(a[0])).attr("y2", y(a[1]));
mutable vec_a = a;
render();
});

const drag2 = d3.drag()
.on("drag", (event, d) => {
b = [x.invert(event.x), y.invert(event.y)];
b = normalize_vecs.length > 0 ? normalize(b) : b;
c2.attr("cx", x(b[0])).attr("cy", y(b[1]));
l2.attr("x2", x(b[0])).attr("y2", y(b[1]));
mutable vec_b = b;
render();
});

c1.call(drag1);
c2.call(drag2);

render();

yield { svg: svg.node() };
}
Insert cell
color1 = "#8e44ad"
Insert cell
color2 = "#c0392b"
Insert cell
mutable vec_a = [0, 1]
Insert cell
mutable vec_b = [1, 0]
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