Signatur
Beschreibung
getCharNumAtPosition() führt einen Treffertest auf Zeichenebene für SVG-Textelemente wie <text>, <tspan> und <textPath> durch. Du übergibst einen Punkt und erhältst den Index des Zeichens zurück, dessen Glyph-Zelle diesen Punkt enthält. Liegt an der Stelle kein Glyph, ist der Rückgabewert -1.
Typische Einsatzfälle sind interaktive SVG-Grafiken: das Zeichen unter dem Mauszeiger hervorheben, eine eigene Textauswahl oder einen Cursor in SVG-Texteditoren umsetzen, Tooltips für einzelne Buchstaben anzeigen oder auf einen Klick auf ein bestimmtes Wort in einem gebogenen Text (<textPath>) reagieren.
Wichtig: Der Punkt wird im Benutzerkoordinatensystem des Elements erwartet, nicht in Bildschirm- oder Viewport-Koordinaten. Mauskoordinaten aus clientX/clientY musst du daher erst mit getScreenCTM().inverse() umrechnen. Der zurückgegebene Index bezieht sich auf die Zeichen des Elements (UTF-16-Codeeinheiten) und lässt sich direkt mit Methoden wie getExtentOfChar() oder getStartPositionOfChar() weiterverwenden.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $point Pflicht | DOMPoint | DOMPointInit | SVGPoint | Der zu prüfende Punkt mit den Eigenschaften x und y im Benutzerkoordinatensystem des Textelements. Laut SVG 2 genügt ein DOMPointInit-Objekt; für maximale Kompatibilität eignet sich svg.createSVGPoint() oder new DOMPoint(x, y). |
Rückgabewert
long) des Zeichens an der angegebenen Position; -1, wenn an dieser Stelle kein Zeichen gerendert ist.Beispiele
Einfacher Treffertest an einer festen Koordinate
// <svg id="bild" width="300" height="100"><text id="titel" x="10" y="50" font-size="32">Hallo SVG</text></svg>
const text = document.getElementById('titel');
const index = text.getCharNumAtPosition(new DOMPoint(20, 45));
console.log(index, text.textContent[index]);
// Punkt außerhalb des Textes
console.log(text.getCharNumAtPosition(new DOMPoint(290, 90)));
Zeichen unter dem Mauszeiger ermitteln
const svg = document.getElementById('bild');
const text = document.getElementById('titel');
const toUserSpace = (evt, element) => {
// Bildschirmkoordinaten in Benutzerkoordinaten umrechnen
const pt = new DOMPoint(evt.clientX, evt.clientY);
return pt.matrixTransform(element.getScreenCTM().inverse());
};
svg.addEventListener('mousemove', (evt) => {
const point = toUserSpace(evt, text);
const index = text.getCharNumAtPosition(point);
if (index !== -1) {
console.log(`Zeichen ${index}: "${text.textContent[index]}"`);
}
});
Angeklicktes Zeichen mit einem Rechteck hervorheben
const SVG_NS = 'http://www.w3.org/2000/svg';
const svg = document.getElementById('bild');
const text = document.getElementById('titel');
const marker = document.createElementNS(SVG_NS, 'rect');
marker.setAttribute('fill', 'rgba(255, 200, 0, 0.5)');
svg.insertBefore(marker, text);
text.addEventListener('click', (evt) => {
const point = new DOMPoint(evt.clientX, evt.clientY)
.matrixTransform(text.getScreenCTM().inverse());
const index = text.getCharNumAtPosition(point);
if (index === -1) return;
const { x, y, width, height } = text.getExtentOfChar(index);
Object.entries({ x, y, width, height })
.forEach(([key, value]) => marker.setAttribute(key, value));
});
// Wichtig · Fallstricke
- Koordinatensystem: Häufigster Fehler ist die direkte Übergabe von
clientX/clientY. Ohne Umrechnung übergetScreenCTM().inverse()passen die Ergebnisse nur zufällig – spätestens beiviewBox, Skalierung, Scrollen odertransformgibt es falsche Treffer oder-1. - Zeichenindex ≠ sichtbares Zeichen: Der Index zählt UTF-16-Codeeinheiten. Emojis oder andere Zeichen außerhalb der BMP belegen zwei Indizes; Ligaturen können mehrere Zeichen auf ein Glyph abbilden.
- Bei überlappenden Glyphen (z. B. durch
dx/rotate) liefert die Methode laut Spezifikation das Zeichen, das zuletzt gerendert wurde, also optisch oben liegt. - Das Element muss gerendert sein. Bei
display: noneoder vor dem Einfügen ins DOM ist kein sinnvolles Ergebnis zu erwarten. - Kompatibilität: Wird von allen modernen Browsern unterstützt. Ältere Browser erwarten teils zwingend ein
SVGPoint(übersvg.createSVGPoint()) statt eines einfachen Objekts oderDOMPoint.