Start · Sprachen · JavaScript · Referenz · CanvasRenderingContext2D.drawFocusIfNeeded()

CanvasRenderingContext2D.drawFocusIfNeeded()

Methode

Zeichnet einen systemkonformen Fokusrahmen um den aktuellen oder übergebenen Pfad, falls das angegebene Element gerade den Fokus hat.

seit JavaScript Baseline: Chrome 37+, Firefox 32+, Safari 8+, Edge Kategorie: webapi

Signatur

CanvasRenderingContext2D.prototype.drawFocusIfNeeded(element) / drawFocusIfNeeded(path, element)

Beschreibung

drawFocusIfNeeded() hilft dabei, Canvas-Inhalte barrierefrei zu machen. Ein Canvas ist für Screenreader und Tastatur erst einmal nur eine Bitmap. Deshalb legt man üblicherweise fokussierbare Elemente (etwa <button> oder <input>) als Fallback-Inhalt direkt in das <canvas>-Element. Hat eines dieser Elemente den Fokus, zeichnet die Methode einen Fokusring um den zugehörigen Pfad. Dabei gilt der Stil des Browsers bzw. Betriebssystems.

Die Methode prüft selbst, ob das übergebene Element fokussiert ist und ein Nachfahre des Canvas ist. Nur dann zeichnet sie etwas, sonst tut sie nichts. Ohne path-Argument nimmt sie den aktuellen Pfad des Kontexts, der vorher mit beginPath(), rect(), arc() usw. aufgebaut wurde. Alternativ übergibt man ein Path2D-Objekt. Der aktuelle Transformationsstatus (setTransform(), translate() …) wird berücksichtigt.

Typischerweise ruft man die Methode bei jedem Neuzeichnen auf, und zwar für jedes interaktive Element. Die Canvas-Szene wird dazu in focus- und blur-Ereignissen der Fallback-Elemente neu gezeichnet, damit der Fokusring erscheint bzw. wieder verschwindet.

Parameter

Name Typ Default Beschreibung
$path Path2D Optionaler Pfad, um den der Fokusrahmen gezeichnet wird. Fehlt er, wird der aktuelle Pfad des Kontexts verwendet.
$element Pflicht Element Das Element, dessen Fokuszustand geprüft wird. Es muss ein Nachfahre des <canvas>-Elements sein (Fallback-Inhalt), sonst wird nichts gezeichnet.

Rückgabewert

Typ
void
Beschreibung
Gibt undefined zurück.

Beispiele

Fokusring um einen Canvas-Button mit dem aktuellen Pfad

// HTML:
// <canvas id="c" width="300" height="150">
//   <button id="ok">OK</button>
// </canvas>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
const okButton = document.getElementById('ok');

const draw = () => {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.beginPath();
  ctx.rect(50, 40, 120, 50);
  ctx.fillStyle = '#3366cc';
  ctx.fill();
  ctx.fillStyle = '#fff';
  ctx.font = '20px sans-serif';
  ctx.fillText('OK', 95, 72);
  // Zeichnet den Fokusring nur, wenn der Button fokussiert ist
  ctx.drawFocusIfNeeded(okButton);
};

okButton.addEventListener('focus', draw);
okButton.addEventListener('blur', draw);
draw();

Mehrere Schaltflächen mit Path2D

// HTML:
// <canvas id="c" width="400" height="120">
//   <button id="b1">Speichern</button>
//   <button id="b2">Abbrechen</button>
// </canvas>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');

const buttons = [
  { el: document.getElementById('b1'), path: new Path2D(), label: 'Speichern', x: 20 },
  { el: document.getElementById('b2'), path: new Path2D(), label: 'Abbrechen', x: 210 }
];
buttons.forEach(b => b.path.rect(b.x, 30, 170, 50));

const render = () => {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  for (const { el, path, label, x } of buttons) {
    ctx.fillStyle = '#eee';
    ctx.fill(path);
    ctx.fillStyle = '#000';
    ctx.font = '18px sans-serif';
    ctx.fillText(label, x + 40, 61);
    ctx.drawFocusIfNeeded(path, el);
  }
};

buttons.forEach(({ el }) => {
  el.addEventListener('focus', render);
  el.addEventListener('blur', render);
});
render();

Klick auf den Canvas fokussiert das passende Fallback-Element

canvas.addEventListener('click', (event) => {
  const rect = canvas.getBoundingClientRect();
  const x = event.clientX - rect.left;
  const y = event.clientY - rect.top;
  const hit = buttons.find(b => ctx.isPointInPath(b.path, x, y));
  if (hit) {
    hit.el.focus(); // löst focus aus, render() zeichnet den Ring
    hit.el.click();
  }
});

// Wichtig · Fallstricke

  • Das Element muss ein Nachfahre des Canvas sein. Fokussierte Elemente außerhalb des Canvas lösen keinen Fokusring aus.
  • Die Methode zeichnet nur einmal. Nach einem Fokuswechsel muss man die Szene selbst neu zeichnen (focus/blur), sonst bleibt der alte Ring stehen oder der neue fehlt.
  • Ob der Ring erscheint, kann auch von :focus-visible-Heuristiken des Browsers abhängen. Manche Browser zeigen ihn bei Mausfokus nicht an.
  • Stil und Farbe des Rings bestimmt der Browser bzw. das Betriebssystem. Wer einen eigenen Stil will, prüft document.activeElement === el und zeichnet selbst mit stroke().
  • Die früher spezifizierte Methode drawCustomFocusRing() ist veraltet und wurde nie breit unterstützt.
  • Der Fokusring allein macht einen Canvas noch nicht barrierefrei. Fallback-Elemente brauchen sinnvolle Beschriftungen, und Tastaturereignisse müssen behandelt werden.
  • In OffscreenCanvasRenderingContext2D gibt es die Methode nicht.