function make_transition_pic(M, back = false) {
const data = rref(M);
data.steps.reverse();
data.steps.push({
op: "",
em: [
[1, 0],
[0, 1]
],
current: M
});
if (!back) {
data.steps.reverse();
}
let [x0, y0] = [M[0][0], M[1][0]];
let [x1, y1] = [M[0][1], M[1][1]];
let [xmin, xmax] = d3.extent([0, x0, x1, x0 + x1]);
let [ymin, ymax] = d3.extent([0, y0, y1, y0 + y1]);
let xrange = xmax - xmin;
let s = 0.4;
xmin = xmin - s * xrange;
xmax = xmax + s * xrange;
let yrange = ymax - ymin;
ymin = ymin - s * yrange;
ymax = ymax + s * yrange;
const w = 500;
const h = (w * (ymax - ymin)) / (xmax - xmin);
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, w, h])
.attr("width", "100%")
.style("max-width", `${w}px`)
.style("border", "solid black 2px");
const pad = 10;
const x_scale = d3
.scaleLinear()
.domain([xmin, xmax])
.range([pad, w - pad]);
const y_scale = d3
.scaleLinear()
.domain([ymin, ymax])
.range([h - pad, pad]);
const pointToPoint = ([x, y]) => [x_scale(x), y_scale(y)];
if (back) {
[x0, y0] = [1, 0];
[x1, y1] = [0, 1];
}
const configuration = svg.append("g");
const polygon = configuration
.append("polygon")
.attr(
"points",
[
[0, 0],
[x0, y0],
[x0 + x1, y0 + y1],
[x1, y1],
[0, 0]
].map(pointToPoint)
)
.attr("fill", "lightgray")
.attr("stroke", "black")
.attr("stroke-width", 0.5);
const leg0 = configuration
.append("polyline")
.call(arrow, x_scale(0), y_scale(0), x_scale(x0), y_scale(y0))
.attr("stroke", "red")
.attr("stroke-width", 2);
const leg1 = configuration
.append("polyline")
.call(arrow, x_scale(0), y_scale(0), x_scale(x1), y_scale(y1))
.attr("stroke", "blue")
.attr("stroke-width", 2);
svg
.append("g")
.style("font-size", "14px")
.attr("transform", `translate(0, ${y_scale(0)})`)
.call(d3.axisBottom(x_scale).ticks(4));
svg
.append("g")
.style("font-size", "14px")
.attr("transform", `translate(${x_scale(0)}, 0)`)
.call(d3.axisLeft(y_scale).ticks(4));
const leg_steps = data.steps.map(function (o) {
const d = o.current;
const [x0, x1] = d[0];
const [y0, y1] = d[1];
return [
[x0, y0],
[x1, y1]
];
});
function update(state) {
const [x0, y0] = leg_steps[state][0];
const [x1, y1] = leg_steps[state][1];
leg0
.transition()
.duration(850)
.attr(
"points",
arrowPoints(x_scale(0), y_scale(0), x_scale(x0), y_scale(y0))
);
leg1
.transition()
.duration(850)
.attr(
"points",
arrowPoints(x_scale(0), y_scale(0), x_scale(x1), y_scale(y1))
);
polygon
.transition()
.duration(850)
.attr(
"points",
[
[0, 0],
[x0, y0],
[x0 + x1, y0 + y1],
[x1, y1],
[0, 0]
].map(pointToPoint)
);
}
svg.node().update = update;
svg.node().data = data;
return svg.node();
}