Signatur
Beschreibung
save() speichert den gesamten Zeichenzustand eines CanvasRenderingContext2D und legt ihn auf einen Stapel (Stack). Mit restore() wird der zuletzt gespeicherte Zustand wieder vom Stapel genommen und aktiviert. So lassen sich Transformationen oder Stiländerungen vorübergehend anwenden, ohne sie danach einzeln zurücksetzen zu müssen.
Zum gespeicherten Zustand gehören unter anderem:
- die aktuelle Transformationsmatrix (
translate(),rotate(),scale(),setTransform()) - der aktuelle Clipping-Bereich (
clip()) - die Strichmuster-Liste (
setLineDash()) undlineDashOffset - Eigenschaften wie
fillStyle,strokeStyle,globalAlpha,globalCompositeOperation,lineWidth,lineCap,lineJoin,miterLimit,shadowOffsetX,shadowOffsetY,shadowBlur,shadowColor,font,textAlign,textBaseline,direction,imageSmoothingEnabled,filterund weitere
Nicht gespeichert werden der aktuelle Pfad (beginPath(), moveTo() usw.) und die bereits gezeichneten Pixel – save() ist also kein Schnappschuss der Grafik, sondern nur der Einstellungen. Für Pixeldaten nutzt man getImageData().
Typischer Einsatz: Bevor man ein einzelnes Objekt gedreht, verschoben oder mit Clipping zeichnet, ruft man save() auf, zeichnet und ruft danach restore() auf. Aufrufe dürfen verschachtelt werden; jedes save() sollte ein passendes restore() haben.
Rückgabewert
undefined).Beispiele
Stil temporär ändern und wiederherstellen
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'steelblue';
ctx.save(); // Zustand mit blauer Füllfarbe sichern
ctx.fillStyle = 'tomato';
ctx.fillRect(10, 10, 100, 100); // rotes Quadrat
ctx.restore(); // wieder blau
ctx.fillRect(130, 10, 100, 100); // blaues Quadrat
console.log(ctx.fillStyle);
Gedrehtes Objekt zeichnen, ohne die Transformation zu verschleppen
const ctx = document.querySelector('canvas').getContext('2d');
const drawRotatedBox = (x, y, size, angle) => {
ctx.save();
ctx.translate(x + size / 2, y + size / 2); // Ursprung in die Mitte
ctx.rotate(angle);
ctx.fillStyle = 'seagreen';
ctx.fillRect(-size / 2, -size / 2, size, size);
ctx.restore(); // Transformation und Farbe zurücksetzen
};
drawRotatedBox(20, 20, 60, Math.PI / 4);
drawRotatedBox(120, 20, 60, Math.PI / 8);
// Folgende Zeichnungen sind wieder unverändert:
ctx.strokeRect(220, 20, 60, 60);
Clipping begrenzen – nur mit save/restore aufhebbar
const ctx = document.querySelector('canvas').getContext('2d');
ctx.save();
ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI * 2);
ctx.clip(); // Ab jetzt nur noch im Kreis zeichnen
ctx.fillStyle = 'gold';
ctx.fillRect(0, 0, 200, 200); // erscheint als Kreis
ctx.restore(); // Clipping-Bereich aufgehoben
ctx.fillStyle = 'purple';
ctx.fillRect(160, 160, 60, 60); // wieder überall sichtbar
Verschachtelte Zustände in einer Animationsschleife
const ctx = document.querySelector('canvas').getContext('2d');
let angle = 0;
const frame = () => {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.save(); // Ebene 1: Mittelpunkt
ctx.translate(150, 150);
ctx.rotate(angle);
ctx.fillRect(-40, -5, 80, 10);
ctx.save(); // Ebene 2: Satellit
ctx.translate(60, 0);
ctx.rotate(angle * 3);
ctx.fillStyle = 'crimson';
ctx.fillRect(-10, -10, 20, 20);
ctx.restore(); // zurück zu Ebene 1
ctx.restore(); // zurück zum Ausgangszustand
angle += 0.02;
requestAnimationFrame(frame);
};
requestAnimationFrame(frame);
// Wichtig · Fallstricke
- Immer paarweise verwenden: Jedes
save()braucht ein passendesrestore(). Fehlt es (z. B. durch einen frühenreturnoder eine Ausnahme), wächst der Stapel in Animationsschleifen immer weiter und Transformationen stapeln sich unerwartet. Bei Bedarftry…finallynutzen. - Der Pfad wird nicht gespeichert: Nach
restore()ist der aktuelle Pfad unverändert – rufen SiebeginPath()explizit auf. - Pixel werden nicht gesichert:
restore()macht keine Zeichenoperationen rückgängig. restore()auf leerem Stapel bewirkt nichts (kein Fehler).- Performance:
save()/restore()kopiert den kompletten Zustand. Wenn nur die Transformation zurückgesetzt werden muss, istsetTransform(1, 0, 0, 1, 0, 0)bzw.resetTransform()oft günstiger. Clipping lässt sich dagegen nur überrestore()(oderreset()) aufheben. - Das Setzen von
canvas.width/heightoderctx.reset()leert den Zustandsstapel vollständig. - Kompatibilität: in allen Browsern unterstützt, ebenso in
OffscreenCanvasRenderingContext2D(Web Worker).