Files
QR-master/src/lib/rounded-chart-path.ts

51 lines
1.7 KiB
TypeScript

export type ChartPoint = { x: number; y: number };
function distance(a: ChartPoint, b: ChartPoint) {
return Math.hypot(b.x - a.x, b.y - a.y);
}
function pointTowards(from: ChartPoint, to: ChartPoint, amount: number): ChartPoint {
const length = distance(from, to);
if (length === 0) return from;
return {
x: from.x + ((to.x - from.x) / length) * amount,
y: from.y + ((to.y - from.y) / length) * amount,
};
}
function coordinate(value: number) {
return Number(value.toFixed(2));
}
/**
* Turns the factual scan points into one continuous SVG path while rounding
* only the visual corners. Source values and timestamps stay untouched; the
* path merely eases into and out of each factual turning point.
*/
export function roundedChartPath(points: ChartPoint[], cornerRadius: number): string {
if (points.length === 0) return '';
if (points.length === 1) return `M ${coordinate(points[0].x)} ${coordinate(points[0].y)}`;
let path = `M ${coordinate(points[0].x)} ${coordinate(points[0].y)}`;
for (let index = 1; index < points.length - 1; index += 1) {
const previous = points[index - 1];
const current = points[index];
const next = points[index + 1];
const radius = Math.min(
cornerRadius,
distance(previous, current) / 2,
distance(current, next) / 2,
);
const before = pointTowards(current, previous, radius);
const after = pointTowards(current, next, radius);
path += ` L ${coordinate(before.x)} ${coordinate(before.y)}`;
path += ` Q ${coordinate(current.x)} ${coordinate(current.y)} ${coordinate(after.x)} ${coordinate(after.y)}`;
}
const last = points[points.length - 1];
return `${path} L ${coordinate(last.x)} ${coordinate(last.y)}`;
}