PerfectVector
Von Irene Kim

Transparente SVG-Flächen bei Konva-Treffern ignorieren

Lass transparente SVG-Bildflächen in Konva Klicks ignorieren. Teste cachebasierte Treffererkennung, Löcher und Hintergründe und erneuere Treffer nach einem Quellenwechsel.

11 Min. Lesezeit
Auf dieser Seite

Damit transparente Bereiche einer Konva.Image Klicks ignorieren, warte auf das Dekodieren ihres Quellbilds, rufe imageNode.cache() und dann imageNode.drawHitFromCache(0) auf und zeichne die Ebene erneut. Das Alpha der gecachten Szene, also die Pixeldeckkraft, bestimmt dann, welche Bildpixel an der Treffererkennung teilnehmen.

Ein gewöhnlicher Bildknoten kann im gesamten Rechteck Ereignisse erhalten, auch in einem leeren SVG-Loch. Konvas Tutorial zu Bildereignissen zeigt die alphabasierte Alternative. Dieser Artikel testet eine eigene hohle SVG über einem separat anklickbaren Hintergrund. Wenn ein Loch keine Bildklicks mehr abfängt, liegt dadurch ein tatsächliches Ziel darunter, das sie erhalten kann.

Dies verändert den Interaktionsbereich des Canvas. Es erstellt weder bearbeitbare Konva.Path-Knoten aus der SVG noch ändert es DOM-SVG-pointer-events-Regeln.

Trenne Bild und Trefferbereich

Ein Trefferbereich ist die Fläche, anhand derer Konva ein Ereignisziel auswählt. Ihre Form kann von der sichtbaren Grafik abweichen. Manche Anwendungen möchten bewusst ein großes rechteckiges Ziel; andere sollen durch transparente Löcher die Auswahl eines tiefer liegenden Objekts ermöglichen.

Gewünschte InteraktionAusgangspunkt
Das gesamte Bild von überall in seinem Rechteck auswählenStandardmäßiges Image-Trefferverhalten
Durch transparente Bildpixel einen darunterliegenden Knoten erreichenBild cachen und seinen Trefferbereich aus Alpha aufbauen
Einzelne Vektorflächen bearbeiten oder ihnen unabhängige Aktionen zuweisenSeparate Konva-Pfade wählen und ihr Verhalten definieren
Zeigerziele innerhalb von Inline-DOM-SVG steuernDie separate Anleitung zu SVG pointer-events verwenden

Die aktuelle Shape-API erwartet einen ganzzahligen alphaThreshold von 0 bis 255; der Standard ist 0. Übergib hier eine Zahl, keinen Callback. Das ist vom visuellen Threshold-Filter zu unterscheiden. Das Beispiel verwendet 0 mit vollständig deckenden Innenflächen und vollständig transparenten Löchern. Es legt keinen bevorzugten Grenzwert für weiche Schatten oder geglättete Kanten fest.

1. Speichere zwei vollständige SVG-Eingaben

Erstelle einen leeren Ordner. Speichere dieses eigene hohle Emblem als hollow.svg:

<svg xmlns="http://www.w3.org/2000/svg" width="240" height="180" viewBox="0 0 240 180">
  <path fill="#315d6f" fill-rule="evenodd"
        d="M20 30 L180 20 L215 60 L195 150 L35 160 L10 110 Z
           M80 65 L145 55 L160 110 L95 125 Z"/>
</svg>

Der innere Teilpfad erzeugt unter der Gerade-Ungerade-Füllregel ein Loch. Speichere dieselbe Außenform ohne diesen inneren Teilpfad als filled.svg:

<svg xmlns="http://www.w3.org/2000/svg" width="240" height="180" viewBox="0 0 240 180">
  <path fill="#315d6f" d="M20 30 L180 20 L215 60 L195 150 L35 160 L10 110 Z"/>
</svg>

Die zweite Datei dient als Kontrollversion für den Quellenwechsel. Sie bemalt die zuvor leere Stelle. Keine Datei enthält ein weißes Hintergrundrechteck oder eingebettetes Bitmap.

2. Lade, cache und protokolliere die tatsächlichen Ziele

Das Beispiel verwendet Konva 10.9.0. Speichere diese drei Dateien neben beiden SVGs. Das HTML lädt diesen festgelegten Browserbuild. In einem kontrollierten Projekt kannst du stattdessen denselben Build lokal bereitstellen.

Speichere reader.html:

<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>Konva transparent image hit comparison</title>
<link rel="stylesheet" href="reader.css">
<main>
<h1>Transparent artwork: which node gets the click?</h1>
<p class="banner"><strong id="version">Loading Konva…</strong>. Original same-origin SVGs, actual Konva.Image nodes, and a separately clickable background. These are canvas hit pixels, not editable SVG path nodes. Desktop click test only; no mobile or accessibility audit.</p>
<div class="grid">
<section class="panel"><h2>1. Default rectangular hit</h2><div class="stage" id="default"></div><p>The hollow image still catches its transparent center and corner.</p><pre class="log" id="default-log"></pre></section>
<section class="panel"><h2>2. Cached alpha hit region</h2><div class="stage" id="alpha"></div><p>cache() then drawHitFromCache(0): the center and corner reach the background.</p><pre class="log" id="alpha-log"></pre></section>
<section class="panel"><h2>3. Opaque image fill</h2><div class="stage" id="fill"></div><p>A white fill behind this image is part of its cached scene. Its formerly empty pixels receive image hits.</p><pre class="log" id="fill-log"></pre></section>
<section class="panel"><h2>4. Replaced source, rebuilt cache</h2><div class="stage" id="updated"></div><p>The original hole is painted in filled.svg. Clear, replace, cache, and rebuild the hit region.</p><pre class="log" id="updated-log"></pre></section>
</div>
<p>Click these stage coordinates in each panel: solid (125,110), hole (195,130), transparent corner (305,55), and outside the image (20,20). The corner is inside the image viewport but outside its painted shape. Logs report actual click targets.</p>
 
</main>
<script src="https://unpkg.com/konva@10.9.0/konva.min.js"></script>
<script type="module" src="reader.js"></script>
</html>

Speichere reader.css:

body { margin: 32px; font: 16px/1.55 Arial, sans-serif; color: #183a42; background: #edf2ef; }
main { max-width: 1080px; margin: auto; }
h1 { font-size: 32px; margin-bottom: 12px; }
h2 { margin: 0 0 12px; font-size: 22px; }
p { margin: 10px 0; }
.banner { background: #dce8e4; padding: 18px; border-left: 5px solid #315d6f; }
.grid { display: grid; grid-template-columns: repeat(2, minmax(460px, 1fr)); gap: 20px; margin: 24px 0; }
.panel { background: white; padding: 20px; border: 1px solid #d1dbd5; border-radius: 12px; }
.stage { width: 420px; height: 260px; }
pre { white-space: pre-wrap; overflow-wrap: anywhere; background: #f8faf7; padding: 12px; }
table { border-collapse: collapse; width: 100%; margin-top: 20px; }
th, td { border-bottom: 1px solid #c9d5ce; padding: 10px; text-align: left; }
.log { min-height: 88px; margin-bottom: 0; font-size: 13px; }

Speichere reader.js:

const source = new Image();
source.src = './hollow.svg';
await source.decode();
const replacement = new Image();
replacement.src = './filled.svg';
await replacement.decode();
 
const clicks = [];
const scenes = [];
function makeScene(id, mode) {
  const stage = new Konva.Stage({ container: id, width: 420, height: 260 });
  const layer = new Konva.Layer();
  stage.add(layer);
  const background = new Konva.Rect({
    id: `${id}-background`, width: 420, height: 260, fill: '#eadfcd'
  });
  const artwork = new Konva.Image({
    id: `${id}-image`, image: source, x: 80, y: 40, width: 240, height: 180
  });
  if (mode === 'fill') artwork.fill('#ffffff');
  layer.add(background, artwork);
  if (mode !== 'default') {
    artwork.cache();
    artwork.drawHitFromCache(0);
  }
  layer.draw();
  const beforeUpdate = stage.getIntersection({ x: 195, y: 130 }).id();
  if (mode === 'update') {
    artwork.clearCache();
    artwork.image(replacement);
    artwork.cache();
    artwork.drawHitFromCache(0);
    layer.draw();
  }
  stage.on('click', (event) => {
    const point = stage.getPointerPosition();
    const record = {
      scene: id, x: point.x, y: point.y,
      target: event.target.id(), trusted: event.evt.isTrusted
    };
    clicks.push(record);
    document.getElementById(`${id}-log`).textContent +=
      `(${Math.round(point.x)}, ${Math.round(point.y)}) → ${record.target}\n`;
    document.dispatchEvent(new CustomEvent('fixture-click-recorded'));
  });
  const scene = { id, stage, artwork, beforeUpdate };
  scenes.push(scene);
  return scene;
}
makeScene('default', 'default');
makeScene('alpha', 'alpha');
makeScene('fill', 'fill');
makeScene('updated', 'update');
document.getElementById('version').textContent = `Konva ${Konva.version}`;

Stelle diesen Ordner über HTTP bereit, statt das HTML als lokale Datei zu öffnen:

python -m http.server 8000

Öffne http://localhost:8000/reader.html und warte auf die vier Bühnen. Die 240 × 180 große SVG liegt in jeder 420 × 260 großen Bühne an den Bühnenkoordinaten (80,40). Jeder Hintergrund ist ein eigener, auf Ereignisse reagierender Konva.Rect unter dem Bild. Der Klicklistener der Bühne meldet event.target.id(). Dies identifiziert den gewählten Konva-Knoten und nicht nur das Canvas-DOM-Element.

await source.decode() läuft vor dem Erstellen des Caches. Cache erst, wenn die tatsächliche Quelle bereit ist, und nicht während das Bild noch lädt. Konvas Node-API dokumentiert die Methoden zum Cachen und Leeren des Caches.

3. Klicke Vollfläche, Loch, Ecke und Hintergrund an

Teste die vier unter den Feldern genannten Stellen. Das sind Koordinaten innerhalb der jeweiligen Bühne, keine vom Browserfenster aus gemessenen Koordinaten.

StelleBühnenkoordinateWas sie testet
Deckende Grafik125,110Einen deckenden Punkt deutlich innerhalb des Emblems
Ursprüngliches Loch195,130Einen transparenten Innenbereich in hollow.svg
Transparente Ecke305,55Innerhalb des Bildrechtecks, außerhalb der bemalten Silhouette
Außerhalb des Bilds20,20Den separat anklickbaren Hintergrund

Die folgende Tabelle hält den getesteten Zieltyp fest. Die Protokolle enthalten das Präfix des jeweiligen Felds, etwa alpha-background.

KonfigurationVollflächeUrsprüngliches LochTransparente EckeAußerhalb des Bilds
StandardbildBildBildBildHintergrund
Gecachter Alpha-TrefferbereichBildHintergrundHintergrundHintergrund
Gecachtes Bild mit deckend weißer FüllungBildBildBildHintergrund
Ersetzte Quelle und neu aufgebauter CacheBildBildHintergrundHintergrund
Tatsächlicher Konva-Browservergleich mit rechteckigen Standardtreffern, gecachten Alphatreffern, deckender Bildfüllung und ersetzter Quelle einschließlich protokollierter Klickziel-IDs
Tatsächliche Konva-10.9.0-Bühnen mit eigener SVG-Grafik und protokollierten Desktop-Klickzielen. Das alphabasierte hohle Bild lässt Klicks in Loch und Ecke den separaten Hintergrund erreichen. Eine deckende Bildfüllung und eine bemalte Ersatzquelle verändern diese Ergebnisse.

Der Browsertest verwendete echte Zeigerklicks an allen 16 Stellen und protokollierte den nativen Vertrauensstatus des Ereignisses, Bühnenkoordinaten und Ziel-IDs. Er prüfte außerdem Quelldateihashes, Bilddekodierung, Bühnen- und Bildmaße, öffentliche Schnittpunktabfragen und native Alphastichproben aus dem gerenderten Canvas jedes Bildknotens.

Am ursprünglichen Loch betrug das Alpha des hohlen Bildknotens 0. Die Kontrollversionen mit deckender Füllung und ersetzter Quelle hatten dort Alpha 255. Der separate Seitenhintergrund machte das hohle Bild selbst nicht deckend: Er gehörte zu einem anderen Konva-Knoten darunter. Das sind innere Stichproben abseits geglätteter Grenzen.

Dies ist ein einzelner Desktop-Browsertest mit einfachen eigenen SVGs und untransformierten Bühnen. Er belegt weder Mobil-/Touchverhalten noch Tastaturinteraktion, einen browserübergreifenden Vergleich, Leistungsgewinne oder einen Grenzwert für jedes weichkantige Bild. Wiederhole den Klicktest in der tatsächlichen Darstellungsgröße und mit den Transformationen deiner Anwendung.

4. Erneuere den Cache bei einem Quellenwechsel

Das vierte Feld beginnt mit der hohlen Quelle und ihrem Alpha-Trefferbereich. Dann leert es den Cache, setzt das bereits dekodierte Ersatzbild ein, cachet erneut und baut den Trefferbereich neu auf. Die Stelle des ursprünglichen Lochs wechselt nach dieser Abfolge vom Hintergrund zum Bild.

Der Cache ist eine gerenderte Momentaufnahme. Aktualisiere nach einer Änderung, die gerenderte Pixel betrifft, die gecachte Szene und ihren alphabasierten Trefferbereich gemeinsam. Gehe nicht davon aus, dass das Zuweisen eines anderen Bilds einen bestehenden gecachten Trefferbereich aktualisiert hat. Warte bei einem asynchron geladenen Ersatz vor der Beispielabfolge auf dessen Dekodierung.

Das dritte Feld isoliert eine andere Ursache: artwork.fill('#ffffff') malt ein deckendes Rechteck hinter das Bild als Teil desselben Bildknotens. Ein aus dieser gecachten Szene erzeugter Trefferbereich schließt die bemalte Fläche ein. Entferne eine unerwünschte Bildknotenfüllung und baue Cache und Trefferbereich anschließend neu auf. Ein weiß wirkender Bereich in deiner Quelldatei kann ebenfalls tatsächlich deckende Farbe sein. Prüfe Transparenz, bevor du die Treffererkennung verantwortlich machst.

Untersuche Auslese- und Zielfehler getrennt

SymptomZuerst prüfen
Das Loch protokolliert weiterhin das BildBestätige, dass nach dem Dekodieren gecacht, der Trefferbereich neu aufgebaut und das Loch nicht durch deckende Füllung oder Quellhintergrund verdeckt wurde
Die Grafik änderte sich, aber Klicks folgen noch einer alten FormLeere und erneuere Szenencache und Alpha-Trefferbereich nach dem Quellenwechsel
Ein Pixelauslese- oder Tainted-Canvas-Fehler erscheintPrüfe Bildursprung und Antwortheader, bevor du Trefferergebnisse deutest
Das gesamte Bild erhält keine Ereignisse mehrPrüfe listening, Sichtbarkeit, Ebenenreihenfolge und einen möglichen Knoten darüber
Ein Loch erreicht die Bühne statt eines tiefer liegenden ObjektsBestätige, dass unter diesem Punkt tatsächlich ein vorgesehenes reagierendes Objekt existiert
Canvasklicks funktionieren, Tastaturbedienung aber nichtGestalte Tastatursteuerung und Semantik separat; Alpha-Trefferpixel liefern sie nicht

Dieses Beispiel stellt beide SVGs vom selben Ursprung wie die Seite bereit. Bilder anderer Ursprünge benötigen zum Pixelauslesen einen ursprungsreinen Canvas. Konvas Anleitung zu Tainted Canvas erklärt crossOrigin zusammen mit einem Server, der die CORS-Anfrage erlaubt. crossOrigin = 'anonymous' allein gewährt keinen Zugriff, wenn der Server ihn nicht erlaubt. Dieser Artikel führte keinen ursprungsübergreifenden Fehlerfall aus.

CSS-pointer-events am äußeren Canvas zu ändern bestimmt nicht, welche Pixel innerhalb einer Konva.Image ihre internen Knoten treffen. Halte Canvas-Zielauswahl getrennt von DOM-SVG-Zeigerzielen. Behalte auch den SVG-Master: Eine gecachte Trefferkarte ist pixelbasierte Interaktionsinformation, kein Ersatz für ein Vektordokument.

Trenne Grafikwiedergewinnung und Ereigniseinrichtung

Wenn deine Anwendung nur Bildplatzierung und alphabasierte Treffer benötigt, kann ein geeignetes transparentes Rasterbild bereits genügen. Wenn nur eine PNG oder JPG übrig ist und die Anwendung zusätzlich bearbeitbare Pfadgeometrie benötigt, kann PerfectVectors Bild-zu-Vektor-Ablauf einen SVG-Kandidaten gewinnen. Prüfe Silhouette und Löcher, wähle anschließend die Konva-Darstellung und implementiere ihre Ereignisse. Dieses Beispiel verwendete eigene native SVGs und führte keine PerfectVector-Konvertierung durch.

Vektorisierung installiert keine Listener, baut keine barrierefreien Bedienelemente, wählt keine Klickziele und synchronisiert keine Caches. Wenn bereits ein SVG-Master existiert, korrigiere den Interaktionscode direkt. Enthält eine Datei unerwartet ein vollständiges rechteckiges Bild, nutze die Prüfung eingebetteter Rasterbilder in SVGs, bevor du separate bearbeitbare Pfade als Inhalt annimmst.

Häufige Fragen

Warum erhalten transparente Pixel meines Konva-Bilds Klicks? Ein standardmäßiger Image-Knoten kann seine rechteckige Fläche für Treffer verwenden. Cache ihn nach dem Laden der Quelle, verwende drawHitFromCache mit einem passenden numerischen Alphagrenzwert und zeichne anschließend neu und teste die tatsächlichen Ziele.

Welches Argument erhält drawHitFromCache? Die aktuelle API akzeptiert einen optionalen ganzzahligen Alphagrenzwert von 0 bis 255 mit Standardwert 0. Das getestete Beispiel übergibt 0. Es übergibt keinen Callback und verwendet den visuellen Threshold-Filter nicht.

Warum macht eine weiße Füllung mein SVG-Loch wieder anklickbar? Eine deckende Füllung am Image-Knoten wird Teil seiner gecachten Szene. Das gecachte Alpha enthält dann diese bemalte Fläche. Entferne eine unerwünschte Füllung und erneuere Szenencache und Trefferbereich.

Macht ein Alpha-Trefferbereich SVG-Pfade unabhängig bearbeitbar? Nein. Die Grafik bleibt ein Image-Knoten. Verwende geeignete separate Path-Knoten und ein ausdrückliches Szenenmodell, wenn deine Anwendung einzelne Vektorflächen steuern muss.

Quellen

  1. Konva: Bildereignisse — standardmäßiges Bildtrefferverhalten und Erzeugen eines Trefferbereichs aus gecachten Grafiken.
  2. Konva: Shape-API — aktueller numerischer Parameter alphaThreshold und sein Wertebereich.
  3. Konva: Node-API — Cacheerstellung und -leerung, Ereignisziele und öffentliche Knotenmethoden.
  4. Konva: Anleitung zu Tainted Canvas — Ursprungsbeschränkungen, CORS und Pixelauslesefehler.
  5. Konva: SVG auf Canvas — Ganzbilddarstellung im Vergleich zu separat konstruierten Vektorpfaden.

Wenn bearbeitbare Geometrie fehlt, bereite mit PerfectVector einen SVG-Kandidaten vor, prüfe seine Löcher und teste anschließend die vorgesehenen Konva-Klickziele und Cacheaktualisierungen separat.

Mehr aus dem Blog

PerfectVector

Starte mit einer sauberen SVG,
die leichter zu bearbeiten ist

Keine Kreditkarte nötig