Signatur
Beschreibung
Die schreibgeschützte Eigenschaft rangeStart gehört zum CharacterBoundsUpdateEvent der EditContext API. Dieses Ereignis wird an einem EditContext ausgelöst, wenn das Betriebssystem bzw. der Eingabemethoden-Editor (IME) wissen muss, wo bestimmte Zeichen auf dem Bildschirm stehen. Das kommt zum Beispiel vor, wenn ein Kandidatenfenster für chinesische oder japanische Eingabe direkt unter dem gerade eingegebenen Text erscheinen soll.
rangeStart gibt den Index des ersten Zeichens (in UTF-16-Codeeinheiten, bezogen auf editContext.text) an, für das Begrenzungen benötigt werden. Zusammen mit rangeEnd ergibt sich der halboffene Bereich [rangeStart, rangeEnd). Die Anwendung berechnet für jedes Zeichen in diesem Bereich ein DOMRect und meldet es mit editContext.updateCharacterBounds(rangeStart, rects) zurück.
Gebraucht wird die Eigenschaft vor allem in eigenen Editoren, die ihren Text selbst zeichnen, etwa in einem <canvas> oder mit eigenem DOM-Aufbau. Dort weiß der Browser nicht von selbst, wo die Zeichen liegen. Deshalb muss die Anwendung genau den angefragten Bereich ab rangeStart ausmessen.
Rückgabewert
EditContext, für das Begrenzungen angefordert werden. Gezählt wird in UTF-16-Codeeinheiten.Beispiele
Angefragten Bereich protokollieren
const editor = document.querySelector('#editor');
const editContext = new EditContext();
editor.editContext = editContext;
editContext.addEventListener('characterboundsupdate', (event) => {
console.log(`Begrenzungen benötigt für Zeichen ${event.rangeStart} bis ${event.rangeEnd - 1}`);
});
Zeichenbegrenzungen in einem Canvas-Editor zurückmelden
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
ctx.font = '20px monospace';
const editContext = new EditContext();
canvas.editContext = editContext;
const LINE_TOP = 10;
const LINE_HEIGHT = 24;
editContext.addEventListener('characterboundsupdate', (event) => {
const { rangeStart, rangeEnd } = event;
const text = editContext.text;
const canvasRect = canvas.getBoundingClientRect();
const rects = [];
for (let i = rangeStart; i < rangeEnd; i++) {
// x-Position = Breite des Textes vor dem Zeichen
const x = ctx.measureText(text.slice(0, i)).width;
const width = ctx.measureText(text[i] ?? '').width;
rects.push(new DOMRect(canvasRect.left + x, canvasRect.top + LINE_TOP, width, LINE_HEIGHT));
}
// Erster Parameter MUSS rangeStart sein
editContext.updateCharacterBounds(rangeStart, rects);
});
Begrenzungen aus DOM-Textknoten per Range ermitteln
const editor = document.querySelector('#editor');
const editContext = new EditContext();
editor.editContext = editContext;
editContext.addEventListener('characterboundsupdate', ({ rangeStart, rangeEnd }) => {
const textNode = editor.firstChild; // der Editor rendert den Text als einzelnen Textknoten
if (!textNode) return;
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);
console.log(`${rects.length} Rechtecke ab Offset ${rangeStart} gemeldet`);
});
// Wichtig · Fallstricke
Kompatibilität: Die EditContext API ist experimentell und bisher nur in Chromium-Browsern verfügbar (Chrome/Edge ab Version 121). Firefox und Safari unterstützen sie nicht. Vor der Nutzung sollte man die Unterstützung prüfen, etwa mit 'EditContext' in window.
- Der Wert ist schreibgeschützt. Eine Zuweisung wird stillschweigend ignoriert und löst im Strict Mode einen Fehler aus.
- Offsets zählen in UTF-16-Codeeinheiten, nicht in Graphemen. Emojis oder Zeichen außerhalb der BMP belegen zwei Positionen.
- Der Bereich ist halboffen:
rangeEndist exklusiv. Das Array fürupdateCharacterBounds()sollte daher genaurangeEnd - rangeStartEinträge enthalten. - Die Rechtecke müssen in Viewport-Koordinaten angegeben werden, also relativ zum sichtbaren Fensterbereich. Bei Canvas-Editoren muss man daher den Versatz aus
getBoundingClientRect()addieren. - Das Ereignis kann während einer IME-Komposition oft ausgelöst werden. Die Berechnung sollte daher schnell sein, zum Beispiel über zwischengespeicherte Glyphenbreiten.