Start · Sprachen · JavaScript · Referenz · EditContext: characterboundsupdate

EditContext: characterboundsupdate

Ereignis

Wird ausgelöst, wenn das Betriebssystem bzw. die Eingabemethode (IME) die Bildschirmposition bestimmter Zeichen im Text eines <code>EditContext</code> benötigt.

seit JavaScript Chromium 121+ (Chrome, Edge, Opera); nicht in Fire Kategorie: webapi

Signatur

editContext.addEventListener("characterboundsupdate", handler)

Beschreibung

Das Ereignis characterboundsupdate gehört zur EditContext-API. Mit ihr bauen Sie eigene Texteditoren, etwa auf Basis eines <canvas> oder eines selbst gerenderten DOM, die trotzdem vollständig mit Eingabemethoden (IME) für Chinesisch, Japanisch, Koreanisch oder Emoji-Auswahl zusammenarbeiten. Die IME muss wissen, wo auf dem Bildschirm die Zeichen der aktuellen Komposition stehen. Nur dann kann sie ihr Kandidatenfenster direkt am Text anzeigen.

Weil der Browser Ihre selbst gezeichneten Zeichen nicht ausmessen kann, fragt er über dieses Ereignis nach. Das Ereignisobjekt ist ein CharacterBoundsUpdateEvent mit den Eigenschaften rangeStart und rangeEnd. Sie geben den Bereich der Zeichen-Offsets im Text des EditContext an, für den Grenzen gebraucht werden. Ihr Handler berechnet für jedes Zeichen in diesem Bereich ein DOMRect in Viewport-Koordinaten und übergibt die Liste mit editContext.updateCharacterBounds(rangeStart, rects).

Das Ereignis tritt meist während einer Komposition auf, also zwischen compositionstart und compositionend, und oft nach einem textupdate. Sie können den Handler auf zwei Arten registrieren: mit addEventListener("characterboundsupdate", …) oder über die Eigenschaft editContext.oncharactersboundsupdate. Richtig geschrieben heißt sie oncharacterboundsupdate.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname "characterboundsupdate".
$handler Pflicht (event: CharacterBoundsUpdateEvent) => void Callback, der ein CharacterBoundsUpdateEvent erhält. Wichtige Eigenschaften: event.rangeStart (Offset des ersten Zeichens) und event.rangeEnd (Offset nach dem letzten Zeichen, exklusiv).
$options boolean|AddEventListenerOptions false Übliche Listener-Optionen wie once oder signal (AbortSignal zum Entfernen).

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Die Antwort an die IME geben Sie im Handler über editContext.updateCharacterBounds().

Beispiele

Zeichengrenzen für einen Canvas-Editor melden

const canvas = document.querySelector('#editor');
const ctx2d = canvas.getContext('2d');
ctx2d.font = '20px monospace';

const editContext = new EditContext();
canvas.editContext = editContext;

const LINE_Y = 30;   // Grundlinie der Textzeile im Canvas
const PADDING_X = 10;
const LINE_HEIGHT = 24;

editContext.addEventListener('characterboundsupdate', (event) => {
  const { rangeStart, rangeEnd } = event;
  const canvasRect = canvas.getBoundingClientRect();
  const text = editContext.text;
  const rects = [];

  for (let i = rangeStart; i < rangeEnd; i++) {
    // x-Position = Breite des Textes vor dem Zeichen
    const x = PADDING_X + ctx2d.measureText(text.slice(0, i)).width;
    const width = ctx2d.measureText(text[i] ?? ' ').width;
    rects.push(new DOMRect(
      canvasRect.left + x,
      canvasRect.top + LINE_Y - LINE_HEIGHT + 4,
      width,
      LINE_HEIGHT
    ));
  }

  editContext.updateCharacterBounds(rangeStart, rects);
  console.log(`Grenzen für ${rangeStart}–${rangeEnd} gemeldet`);
});
Grenzen für 0–2 gemeldet

DOM-basierter Editor: Grenzen per Range ermitteln

const editorEl = document.querySelector('#editor'); // enthält einen einzigen Textknoten
const editContext = new EditContext({ text: editorEl.textContent });
editorEl.editContext = editContext;

editContext.addEventListener('textupdate', (e) => {
  editorEl.textContent = editContext.text;
});

editContext.addEventListener('characterboundsupdate', ({ rangeStart, rangeEnd }) => {
  const textNode = editorEl.firstChild;
  const range = document.createRange();
  const rects = [];

  for (let i = rangeStart; i < rangeEnd; i++) {
    range.setStart(textNode, i);
    range.setEnd(textNode, i + 1);
    rects.push(range.getBoundingClientRect());
  }

  editContext.updateCharacterBounds(rangeStart, rects);
});

Handler über die on-Property setzen und entfernen

const editContext = new EditContext();
document.querySelector('#editor').editContext = editContext;

const logBounds = (event) => {
  console.log('IME fragt Zeichen', event.rangeStart, 'bis', event.rangeEnd);
  editContext.updateCharacterBounds(event.rangeStart, []);
};

// Variante 1: on-Property
editContext.oncharacterboundsupdate = logBounds;

// Später entfernen
editContext.oncharacterboundsupdate = null;

// Variante 2: addEventListener mit AbortController
const controller = new AbortController();
editContext.addEventListener('characterboundsupdate', logBounds, { signal: controller.signal });
controller.abort(); // Listener wird entfernt
IME fragt Zeichen 3 bis 5

// Wichtig · Fallstricke

  • Browser-Kompatibilität: Die EditContext-API ist experimentell und gibt es derzeit nur in Chromium-Browsern (Chrome/Edge ab 121). Prüfen Sie vorab mit if ('EditContext' in window) und bieten Sie sonst einen Ausweichweg an, etwa contenteditable oder ein verstecktes <textarea>.
  • Koordinaten: Die DOMRect-Werte müssen im Viewport-Koordinatensystem stehen, genau wie bei getBoundingClientRect(). Canvas-interne Koordinaten müssen Sie also mit der Position des Canvas verrechnen. Wenn das Canvas per CSS skaliert wird, rechnen Sie zusätzlich die Skalierung (devicePixelRatio bzw. das Verhältnis von CSS-Größe zu Canvas-Größe) ein.
  • Offsets: rangeStart und rangeEnd sind UTF-16-Code-Unit-Offsets in editContext.text. Bei Emojis und Surrogatpaaren passen sie nicht zu sichtbaren Zeichen (Graphemen). rangeEnd ist exklusiv.
  • Rufen Sie updateCharacterBounds() synchron im Handler auf. Sonst zeigt die IME ihr Kandidatenfenster an der falschen Stelle an. Melden Sie außerdem Änderungen am Layout, etwa durch Scrollen oder Größenänderung, zusätzlich mit updateControlBounds() und updateSelectionBounds().
  • Das Ereignis sagt nichts darüber, ob sich der Text geändert hat. Textänderungen verarbeiten Sie im Ereignis textupdate.