class FlowCurve extends Plot.Mark {
static defaults = {
stroke: "black",
strokeWidth: 1,
opacity: 1
};
constructor(data, options = {}) {
const { x1, y1, x2, y2, sweep = 1 } = options;
super(
data,
{
x1: { value: x1, scale: "x" },
y1: { value: y1, scale: "y" },
x2: { value: x2, scale: "x" },
y2: { value: y2, scale: "y" }
},
options,
FlowCurve.defaults
);
this.sweep = sweep < 0 ? -1 : sweep > 0 ? 1 : 0;
}
render(indices, scales, channels, dimensions, cxt) {
const {
x1: x1s,
y1: y1s,
x2: x2s,
y2: y2s,
stroke: clrs,
strokeWidth: sws,
opacity: ops
} = channels;
return htl.svg`<g>${[...indices].map((i) => {
const clr = clrs?.value ?? (clrs ? clrs[i] : this.stroke);
const op = ops?.value ?? (ops ? ops[i] : this.opacity);
const sw = sws?.value ?? (sws ? sws[i] : this.strokeWidth);
const [x1, y1, cx, cy, x2, y2] = FlowCurve.cPts(
x1s[i],
y1s[i],
x2s[i],
y2s[i],
this.sweep
);
const d = `M ${x1},${y1} C ${cx},${cy} ${x2},${y2} ${x2},${y2}`;
return htl.svg`<path d="${d}" fill="none" stroke="${clr}" stroke-width="${sw}" stroke-opacity="${op}" />`;
})}</g>`;
}
static cPts = (x1, y1, x2, y2, d = 1) => {
const [cx, cy] = [x2 - d * 0.25 * (y1 - y2), y2 + d * 0.25 * (x1 - x2)];
return [x1, y1, cx, cy, x2, y2];
};
}