Signatur
Beschreibung
isPointInFill() gibt es auf allen geometrischen SVG-Elementen, also allen, die von SVGGeometryElement erben: <path>, <rect>, <circle>, <ellipse>, <line>, <polyline> und <polygon>. Die Methode berechnet mathematisch, ob ein Punkt in der Füllfläche der Form liegt. Dabei gilt die aktuelle fill-rule (nonzero oder evenodd).
Typische Anwendungen sind eigene Treffertests, etwa bei Editoren, Diagrammen, interaktiven Karten oder Spielen. Das ist vor allem dann nützlich, wenn Zeigerereignisse nicht reichen: wenn man mehrere sich überlappende Formen prüfen will, beliebige Koordinaten ohne Mausereignis testen möchte oder pointer-events abgeschaltet ist.
Wichtig: Der Punkt wird im lokalen Koordinatensystem des Elements erwartet (user space). Das ist dasselbe System, in dem auch d, x, cx usw. angegeben sind. Mauskoordinaten wie clientX/clientY müssen deshalb zuerst umgerechnet werden, üblicherweise mit getScreenCTM().inverse().
Welchen Wert die Eigenschaft fill hat, spielt keine Rolle: Auch bei fill="none" wird die geometrische Füllfläche geprüft. Für Treffer auf der Kontur gibt es die Schwestermethode isPointInStroke().
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $point | DOMPointInit | DOMPoint | SVGPoint | { x: 0, y: 0 } | Der zu prüfende Punkt als Objekt mit x und y im lokalen Koordinatensystem des Elements. z und w werden ignoriert. |
Beispiele
Einfacher Test an einem Kreis
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
circle.setAttribute('cx', '50');
circle.setAttribute('cy', '50');
circle.setAttribute('r', '40');
svg.append(circle);
document.body.append(svg);
console.log(circle.isPointInFill({ x: 50, y: 50 })); // Mittelpunkt
console.log(circle.isPointInFill(new DOMPoint(85, 50))); // innerhalb des Radius
console.log(circle.isPointInFill({ x: 95, y: 95 })); // außerhalb
Mausklick in lokale Koordinaten umrechnen und prüfen
// HTML: <svg id="map" viewBox="0 0 200 200"><path id="area" transform="scale(2)" d="M10 10 H90 V90 H10 Z"/></svg>
const svg = document.getElementById('map');
const area = document.getElementById('area');
svg.addEventListener('pointerdown', (event) => {
// Bildschirmkoordinaten -> lokales Koordinatensystem des Pfads
const matrix = area.getScreenCTM()?.inverse();
if (!matrix) return;
const local = new DOMPoint(event.clientX, event.clientY).matrixTransform(matrix);
const inside = area.isPointInFill(local);
console.log(inside ? 'Treffer in der Fläche' : 'Daneben');
});
Wirkung von fill-rule bei einem Ring
const ns = 'http://www.w3.org/2000/svg';
const svg = document.createElementNS(ns, 'svg');
const ring = document.createElementNS(ns, 'path');
// Äußeres und inneres Quadrat, beide im Uhrzeigersinn
ring.setAttribute('d', 'M0 0 H100 V100 H0 Z M25 25 H75 V75 H25 Z');
svg.append(ring);
document.body.append(svg);
const center = { x: 50, y: 50 };
ring.setAttribute('fill-rule', 'nonzero');
console.log('nonzero:', ring.isPointInFill(center));
ring.setAttribute('fill-rule', 'evenodd');
console.log('evenodd:', ring.isPointInFill(center));
Alle Formen unter einem Punkt finden
const hitTest = (svg, clientX, clientY) =>
[...svg.querySelectorAll('path, rect, circle, ellipse, polygon')]
.filter((shape) => {
const m = shape.getScreenCTM()?.inverse();
if (!m) return false;
const p = new DOMPoint(clientX, clientY).matrixTransform(m);
return shape.isPointInFill(p) || shape.isPointInStroke(p);
});
document.addEventListener('click', (e) => {
const svg = document.querySelector('svg');
const hits = hitTest(svg, e.clientX, e.clientY);
console.log(`${hits.length} Form(en) getroffen`, hits.map((el) => el.id));
});
// Wichtig · Fallstricke
- Koordinatensystem: Der häufigste Fehler ist,
clientX/clientYoderoffsetX/offsetYdirekt zu übergeben.viewBox,transformund das Scrollen der Seite verschieben die Koordinaten. Rechne sie deshalb immer mitgetScreenCTM().inverse()um. - Kein Einfluss von Stil-Eigenschaften:
fill="none",visibilityundpointer-eventswerden ignoriert. Nur die Geometrie und diefill-rulezählen. Wenn nur sichtbare Flächen als Treffer gelten sollen, musst du das selbst prüfen. - Kontur zählt nicht: Die Strichbreite (
stroke-width) gehört nicht zur Füllfläche. Für Konturen verwendeisPointInStroke(). - Kompatibilität: Ältere Firefox-Versionen (vor 69) und alte Chromium-Versionen akzeptierten nur ein
SVGPoint(übersvg.createSVGPoint()). Moderne Browser nehmen jedes{ x, y }-Objekt bzw.DOMPointan. Beim Aufruf ganz ohne Argument wird(0, 0)geprüft. - Performance: Bei sehr komplexen Pfaden und vielen Formen (z. B. Treffertests bei jedem
pointermove) kann die Berechnung spürbar Zeit kosten. Grenze die Kandidaten vorher übergetBBox()ein oder drossele die Aufrufe. - Für Elemente außerhalb des Dokuments oder mit
display: noneliefertgetScreenCTM()möglicherweisenull. Prüfe das vor der Umrechnung.