Start · Sprachen · JavaScript · Referenz · SVGGeometryElement.isPointInFill()

SVGGeometryElement.isPointInFill()

Methode

Prüft, ob ein Punkt im lokalen Koordinatensystem eines SVG-Formelements innerhalb von dessen Füllfläche liegt, und gibt <code>true</code> oder <code>false</code> zurück.

seit JavaScript Baseline: alle modernen Browser (Chrome 48+, Firef Kategorie: webapi

Signatur

SVGGeometryElement.prototype.isPointInFill(point)

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
true true false

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');
});
Treffer in der Fläche (bzw. „Daneben“, je nach Klickposition)

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));
nonzero: true evenodd: false

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));
});
2 Form(en) getroffen ['kreis', 'hintergrund'] (Beispiel)

// Wichtig · Fallstricke

  • Koordinatensystem: Der häufigste Fehler ist, clientX/clientY oder offsetX/offsetY direkt zu übergeben. viewBox, transform und das Scrollen der Seite verschieben die Koordinaten. Rechne sie deshalb immer mit getScreenCTM().inverse() um.
  • Kein Einfluss von Stil-Eigenschaften: fill="none", visibility und pointer-events werden ignoriert. Nur die Geometrie und die fill-rule zä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 verwende isPointInStroke().
  • Kompatibilität: Ältere Firefox-Versionen (vor 69) und alte Chromium-Versionen akzeptierten nur ein SVGPoint (über svg.createSVGPoint()). Moderne Browser nehmen jedes { x, y }-Objekt bzw. DOMPoint an. 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 über getBBox() ein oder drossele die Aufrufe.
  • Für Elemente außerhalb des Dokuments oder mit display: none liefert getScreenCTM() möglicherweise null. Prüfe das vor der Umrechnung.