{
const context = DOM.context2d(width, height);
const R = [];
context.lineCap = "round";
context.lineJoin = "round";
for (let t = 0; true; ++t) {
const scale = viewof zoom.value * width / viewbox.width;
const a = t * 2 / q * Math.PI;
context.save();
context.clearRect(0, 0, width, height);
let p = [0, 0];
for (let i = 0; i < M; ++i) {
p = add(p, mul(DFT[i], expim(a * K[i])));
}
context.translate(width / 2, height / 2);
context.scale(scale, scale);
context.translate(-p[0], -p[1]);
context.beginPath();
for (let i = 0, p = [0, 0]; i < M; ++i) {
const r = abs(DFT[i]);
context.moveTo(p[0] + r, p[1]);
context.arc(...p, r, 0, 2 * Math.PI);
p = add(p, mul(DFT[i], expim(a * K[i])));
}
context.lineWidth = 0.25 / scale;
context.strokeStyle = "#999";
context.stroke();
context.beginPath();
context.moveTo(0, 0);
for (let i = 0, p = [0, 0]; i < M; ++i) {
context.lineTo(...p = add(p, mul(DFT[i], expim(a * K[i]))));
}
context.lineWidth = 0.75 / scale;
context.strokeStyle = "#333";
context.stroke();
context.beginPath();
for (let i = 0, p = [0, 0]; i < M; ++i) {
arrow(context, p, p = add(p, mul(DFT[i], expim(a * K[i]))), {size: 8 / scale});
}
context.fillStyle = "#333";
context.fill();
if (R.length < q) R.push(p);
context.beginPath();
context.moveTo(...R[0]);
for (let i = 1, n = R.length; i < n; ++i) {
context.lineTo(...R[i]);
}
if (R.length >= q) context.closePath();
context.lineWidth = 1.5 / scale;
context.strokeStyle = "#f00";
context.stroke();
context.restore();
yield context.canvas;
}
}