diff --git a/CHANGELOG.md b/CHANGELOG.md index c78a60c..b2b2d4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Web: Füllungen verschwanden (u. a. auf dem Ergebnis-Screen), wenn die Canvas-Breite nicht ganzzahlig war (z. B. `screenWidth * 0.44` = 184,8 px). Die Pixelmaße der Web-Zeichenfläche werden jetzt abgerundet, damit Canvas-Attribut, `getImageData` und Flood-Fill dieselbe Zeilenbreite verwenden - „Von Level 1 neu starten" setzt den Galerie-Speicherstatus zurück (vorher blieb „In Galerie speichern" ggf. gesperrt) - Ergebnis-Feedback wechselte bei jedem Re-Render, weil die rotierende Nachricht im Render gewählt wurde — jetzt einmal pro Bewertung; DE/EN-Texte für 1–2 Sterne laufen nicht mehr auseinander diff --git a/components/DrawingCanvas.web.tsx b/components/DrawingCanvas.web.tsx index 79bad39..1dab937 100644 --- a/components/DrawingCanvas.web.tsx +++ b/components/DrawingCanvas.web.tsx @@ -67,7 +67,7 @@ function drawPath( export default function DrawingCanvas({ width: propWidth, - height = 400, + height: heightProp = 400, strokeColor = '#000000', strokeWidth = 3, tool = 'brush', @@ -76,7 +76,14 @@ export default function DrawingCanvas({ onDrawingChange, }: Props) { const { width: windowWidth } = useWindowDimensions(); - const width = propWidth ?? (windowWidth > 0 ? windowWidth - 48 : DEFAULT_CANVAS_WIDTH); + // Canvas-Pixelmaße müssen ganzzahlig sein: Das canvas-Attribut schneidet Nachkommastellen ab, + // getImageData/floodFillPixels rechnen aber mit der übergebenen Breite — bei gebrochenen Maßen + // (z. B. screenWidth * 0.44 = 184,8) stimmt die Zeilenadressierung nicht mehr und Fills + // verschwinden still. + const width = Math.floor( + propWidth ?? (windowWidth > 0 ? windowWidth - 48 : DEFAULT_CANVAS_WIDTH), + ); + const height = Math.floor(heightProp); const [currentPath, setCurrentPath] = useState<{ x: number; y: number }[]>([]); const isDrawingRef = useRef(false); diff --git a/components/__tests__/DrawingCanvas.web.test.tsx b/components/__tests__/DrawingCanvas.web.test.tsx index 0615fa9..9f59608 100644 --- a/components/__tests__/DrawingCanvas.web.test.tsx +++ b/components/__tests__/DrawingCanvas.web.test.tsx @@ -221,4 +221,24 @@ describe('DrawingCanvas.web — Live-Strich nutzt Snapshot statt Komplett-Redraw expect(ctxCalls.stroke).toBeLessThanOrEqual(1 + 2 * 3); }); }); + + describe('gebrochene Canvas-Maße', () => { + it('verwendet ganzzahlige Maße für Canvas und Pixelzugriff (Fills verschwanden sonst)', () => { + const fill: DrawingPath = { + points: [{ x: 5, y: 5 }], + color: '#FF0000', + strokeWidth: 0, + type: 'fill', + }; + const { container } = render(); + const canvas = container.querySelector('canvas') as HTMLCanvasElement; + + expect(canvas.width).toBe(184); + expect(canvas.height).toBe(100); + expect(fakeCtx.getImageData).toHaveBeenCalledWith(0, 0, 184, 100); + // Der Puffer passt zur übergebenen Breite → Flood-Fill kann korrekt adressieren + const [, , w, h] = fakeCtx.getImageData.mock.calls[0]; + expect(Number.isInteger(w) && Number.isInteger(h)).toBe(true); + }); + }); });