Polish social milestone chart curves
This commit is contained in:
50
src/lib/rounded-chart-path.ts
Normal file
50
src/lib/rounded-chart-path.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
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)}`;
|
||||
}
|
||||
Reference in New Issue
Block a user