diff --git a/src/renderers/draw-features.ts b/src/renderers/draw-features.ts index 1704af508..301c02460 100644 --- a/src/renderers/draw-features.ts +++ b/src/renderers/draw-features.ts @@ -95,7 +95,7 @@ function featurePathRenderer(feature: PackedGraphFeature): string { } const simplifiedPoints = simplify(points, 0.3); - const clippedPoints = clipPoly(simplifiedPoints, graphWidth, graphHeight); + const clippedPoints = clipPoly(simplifiedPoints, graphWidth, graphHeight, 1); const lineGen = line().curve(curveBasisClosed); const path = `${round(lineGen(clippedPoints) || "")}Z`; diff --git a/src/utils/commonUtils.ts b/src/utils/commonUtils.ts index 2da6d8d9b..d227e7cb2 100644 --- a/src/utils/commonUtils.ts +++ b/src/utils/commonUtils.ts @@ -9,12 +9,15 @@ import { rand } from "./probabilityUtils"; * @param points - Array of points [[x1, y1], [x2, y2], ...] * @param graphWidth - Width of the graph * @param graphHeight - Height of the graph + * @param secure - When truthy, duplicate boundary-crossing points to prevent B-spline + * curves from arcing away from map edges (restores original "secure clipping" behavior) * @returns Clipped polygon points */ export const clipPoly = ( points: [number, number][], graphWidth: number, graphHeight: number, + secure?: number, ) => { if (points.length < 2) return points; if (points.some((point) => point === undefined)) { @@ -22,7 +25,25 @@ export const clipPoly = ( return points; } - return clipPolygon(points, [0, 0, graphWidth, graphHeight]); + const clipped = clipPolygon(points, [0, 0, graphWidth, graphHeight]); + + if (!secure || !clipped.length) return clipped; + + // Duplicate each boundary point twice so the B-spline passes through it + // rather than arcing away from the map edge (replicates polygonclip secure=1) + const secured: [number, number][] = []; + for (const point of clipped) { + secured.push(point); + if ( + point[0] === 0 || + point[0] === graphWidth || + point[1] === 0 || + point[1] === graphHeight + ) { + secured.push(point, point); + } + } + return secured; }; /** @@ -375,7 +396,7 @@ declare global { interface Window { ERROR: boolean; - clipPoly: typeof clipPoly; + clipPoly: (points: [number, number][], secure?: number) => [number, number][]; getSegmentId: typeof getSegmentId; debounce: typeof debounce; throttle: typeof throttle; diff --git a/src/utils/index.ts b/src/utils/index.ts index d0999679d..94d1d36aa 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -227,8 +227,8 @@ import { wiki, } from "./commonUtils"; -window.clipPoly = (points: [number, number][]) => - clipPoly(points, graphWidth, graphHeight); +window.clipPoly = (points: [number, number][], secure?: number) => + clipPoly(points, graphWidth, graphHeight, secure); window.getSegmentId = getSegmentId; window.debounce = debounce; window.throttle = throttle;