diff --git a/src/CreateGraphPath.ts b/src/CreateGraphPath.ts index 0c7f1c0..c8c2f82 100644 --- a/src/CreateGraphPath.ts +++ b/src/CreateGraphPath.ts @@ -155,60 +155,33 @@ function createGraphPathBase({ const points: SkPoint[] = []; - const startX = - getXInRange(drawingWidth, graphData[0]!.date, range.x) + horizontalPadding; const endX = getXInRange(drawingWidth, graphData[graphData.length - 1]!.date, range.x) + horizontalPadding; - const getGraphDataIndex = (pixel: number) => - endX === startX - ? 0 - : Math.round( - ((pixel - startX) / (endX - startX)) * (graphData.length - 1) - ); - - const getNextPixelValue = (pixel: number) => { - if (pixel === endX || pixel + PIXEL_RATIO < endX) - return pixel + PIXEL_RATIO; - return endX; - }; - - for ( - let pixel = startX; - startX <= pixel && pixel <= endX; - pixel = getNextPixelValue(pixel) - ) { - const index = getGraphDataIndex(pixel); - - // Draw first point only on the very first pixel - if (index === 0 && pixel !== startX) continue; - // Draw last point only on the very last pixel - - if (index === graphData.length - 1 && pixel !== endX) continue; - - if (index !== 0 && index !== graphData.length - 1) { - // Only draw point, when the point is exact - const exactPointX = - getXInRange(drawingWidth, graphData[index]!.date, range.x) + - horizontalPadding; + let lastDrawnX: number | undefined; - const isExactPointInsidePixelRatio = Array(PIXEL_RATIO) - .fill(0) - .some((_value, additionalPixel) => { - return pixel + additionalPixel === exactPointX; - }); + for (let index = 0; index < graphData.length; index++) { + const graphPoint = graphData[index]!; + const x = + getXInRange(drawingWidth, graphPoint.date, range.x) + horizontalPadding; + const isBoundaryPoint = index === 0 || index === graphData.length - 1; - if (!isExactPointInsidePixelRatio) continue; + if ( + !isBoundaryPoint && + lastDrawnX != null && + x - lastDrawnX < PIXEL_RATIO + ) { + continue; } - const value = graphData[index]!.value; const y = drawingHeight - - getYInRange(drawingHeight, value, range.y) + + getYInRange(drawingHeight, graphPoint.value, range.y) + verticalPadding; - points.push({ x: pixel, y: y }); + points.push({ x, y }); + lastDrawnX = x; } for (let i = 0; i < points.length; i++) { diff --git a/src/__tests__/CreateGraphPath.test.ts b/src/__tests__/CreateGraphPath.test.ts index dc015dd..0d308ce 100644 --- a/src/__tests__/CreateGraphPath.test.ts +++ b/src/__tests__/CreateGraphPath.test.ts @@ -43,3 +43,25 @@ it('creates a finite path when every graph point maps to the same pixel', () => expect(mockPath.moveTo).toHaveBeenCalledTimes(1); expect(mockPath.moveTo.mock.calls[0]?.every(Number.isFinite)).toBe(true); }); + +it('preserves intermediate points with irregular timestamp spacing', () => { + const points = [ + { date: new Date(0), value: 0 }, + { date: new Date(3), value: 100 }, + { date: new Date(10), value: 0 }, + ]; + + createGraphPath({ + pointsInRange: points, + range: { + x: { min: points[0]!.date, max: points[2]!.date }, + y: { min: 0, max: 100 }, + }, + horizontalPadding: 0, + verticalPadding: 0, + canvasHeight: 100, + canvasWidth: 10, + }); + + expect(mockPath.cubicTo).toHaveBeenCalledTimes(3); +});