PerfectVector
Di Irene Kim

Ignora le aree SVG trasparenti nei clic di Konva

Escludi dai clic le aree trasparenti SVG in Konva. Riproduci il rilevamento dalla cache, prova fori e sfondi e ricrea l'area dopo i cambi di sorgente.

13 min di lettura
In questa pagina

Perché le aree trasparenti di una Konva.Image ignorino i clic, attendi la decodifica dell'immagine sorgente, chiama imageNode.cache(), poi imageNode.drawHitFromCache(0) e ridisegna il livello. L'alfa della scena in cache, cioè l'opacità dei pixel, determina quindi quali pixel dell'immagine partecipano al rilevamento dei clic.

Un normale nodo immagine può ricevere eventi sull'intero rettangolo, compreso un foro SVG vuoto. Il tutorial Image Events di Konva mostra l'alternativa basata sull'alfa. Questo articolo prova un SVG originale con un foro sopra uno sfondo cliccabile separato: quando il foro smette di intercettare i clic sull'immagine, esiste un vero oggetto sottostante che li riceve.

Questo cambia l'area di interazione del canvas. Non crea nodi Konva.Path modificabili dall'SVG e non cambia le regole pointer-events dell'SVG nel DOM.

Separa l'immagine dalla sua area di rilevamento

Una hit region è l'area usata da Konva per scegliere il destinatario di un evento. La sua forma può differire dalla grafica visibile. In alcune applicazioni un bersaglio rettangolare ampio è intenzionale; in altre, i fori trasparenti devono consentire all'utente di selezionare un oggetto inferiore.

Interazione desiderataPunto di partenza
Selezionare l'intera immagine da qualsiasi punto del suo rettangoloComportamento di rilevamento predefinito di Image
Lasciare che i pixel trasparenti raggiungano un nodo sottostanteMemorizzare l'immagine in cache e costruire l'area di rilevamento dall'alfa
Modificare singole regioni vettoriali o associarvi azioni indipendentiScegliere tracciati Konva separati e definirne il comportamento
Controllare i destinatari del puntatore dentro un SVG inline nel DOMUsare la guida separata a pointer-events SVG

L'attuale API Shape accetta un intero alphaThreshold da 0 a 255; il valore predefinito è 0. Passa un numero, non una callback. È una funzione distinta dal filtro visivo Threshold. L'esempio usa 0 con interni completamente opachi e fori completamente trasparenti; non stabilisce una soglia preferibile per ombre morbide o bordi antialias.

1. Salva due input SVG completi

Crea una cartella vuota. Salva questo emblema originale con foro come 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>

Il sottotracciato interno crea un foro con la regola di riempimento pari-dispari. Salva la stessa forma esterna senza quel sottotracciato come 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>

Il secondo file è il controllo del cambio di sorgente. Dipinge il punto prima vuoto. Nessuno dei due file contiene un rettangolo di sfondo bianco o una bitmap incorporata.

2. Carica, memorizza in cache e registra i destinatari reali

L'esempio usa Konva 10.9.0. Salva questi tre file accanto ai due SVG. L'HTML carica quella versione fissata della build browser; per un progetto controllato puoi invece servire la stessa build localmente.

Salva 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>

Salva 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; }

Salva 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}`;

Servi la cartella via HTTP invece di aprire l'HTML come file locale:

python -m http.server 8000

Apri http://localhost:8000/reader.html e attendi che compaiano i quattro stage. L'SVG da 240 × 180 è posizionato alle coordinate dello stage (80,40) in ciascuno stage da 420 × 260. Ogni sfondo è un Konva.Rect separato che riceve eventi, sotto l'immagine. Il listener dei clic dello stage riporta event.target.id(), che identifica il nodo Konva scelto anziché il solo elemento DOM canvas.

await source.decode() viene eseguito prima della creazione della cache. Crea la cache quando il sorgente effettivo è pronto, non mentre l'immagine sta ancora caricando. L'API Node documenta i metodi di creazione e cancellazione della cache.

3. Clicca area piena, foro, angolo e sfondo

Prova le quattro posizioni elencate sotto i pannelli. Sono coordinate interne a ciascuno stage, non misurate dalla finestra del browser.

PosizioneCoordinata nello stageCosa verifica
Grafica piena125,110Un punto opaco ben dentro l'emblema
Foro originale195,130Un interno trasparente in hollow.svg
Angolo trasparente305,55Dentro il rettangolo dell'immagine, fuori dalla sagoma dipinta
Fuori dall'immagine20,20Lo sfondo cliccabile separato

La tabella seguente registra il tipo di destinatario verificato. I log includono il prefisso di ogni pannello, come alpha-background.

ConfigurazioneArea pienaForo originaleAngolo trasparenteFuori dall'immagine
Immagine predefinitaImmagineImmagineImmagineSfondo
Area di rilevamento alfa in cacheImmagineSfondoSfondoSfondo
Immagine in cache con riempimento bianco opacoImmagineImmagineImmagineSfondo
Sorgente sostituito e cache ricreataImmagineImmagineSfondoSfondo
Confronto effettivo di Konva nel browser con rilevamento rettangolare predefinito, rilevamento alfa in cache, riempimento opaco e sorgente sostituito, inclusi gli ID registrati dei destinatari dei clic
Stage effettivi Konva 10.9.0 con grafica SVG originale e destinatari dei clic desktop registrati. L'immagine con foro basata sull'alfa lascia che i clic nel foro e nell'angolo raggiungano lo sfondo separato. Un riempimento opaco dell'immagine e un sorgente sostitutivo dipinto cambiano i risultati.

La prova nel browser ha usato clic reali del puntatore in tutte le 16 posizioni e registrato attendibilità dell'evento nativo, coordinate dello stage e ID dei destinatari. Ha controllato anche hash dei file sorgente, decodifica delle immagini, dimensioni di stage e immagini, risultati pubblici delle intersezioni e campioni alfa nativi del canvas renderizzato di ogni nodo immagine.

Nel foro originale, l'alfa del nodo immagine con foro era 0. I controlli con riempimento opaco e sorgente sostituito avevano alfa 255 nello stesso punto. Lo sfondo separato della pagina non rendeva opaca l'immagine con foro: apparteneva a un altro nodo Konva sottostante. Sono campioni interni, lontani dai bordi antialias.

È una singola prova su browser desktop con SVG originali semplici e stage non trasformati. Non dimostra comportamento mobile/touch, interazione da tastiera, una matrice di browser, vantaggi prestazionali o una soglia adatta a ogni immagine con bordi morbidi. Ripeti la prova dei clic alle dimensioni e trasformazioni effettive della tua app.

4. Ricrea la cache quando cambia il sorgente

Il quarto pannello parte dal sorgente con foro e dalla sua area di rilevamento alfa. Poi cancella la cache, imposta l'immagine sostitutiva già decodificata, crea nuovamente la cache e ricostruisce l'area. Dopo questa sequenza, la posizione del foro originale passa dallo sfondo all'immagine.

La cache è un'istantanea renderizzata. Dopo una modifica che influisce sui pixel renderizzati, aggiorna insieme la scena in cache e l'area di rilevamento basata sull'alfa. Non presumere che assegnare un'immagine diversa aggiorni un'area di rilevamento già in cache. Per una sostituzione caricata in modo asincrono, attendi la sua decodifica prima della sequenza dell'esempio.

Il terzo pannello isola una causa diversa: artwork.fill('#ffffff') dipinge un rettangolo opaco dietro l'immagine come parte dello stesso nodo immagine. Costruire un'area di rilevamento da quella scena in cache include l'area dipinta. Rimuovi un riempimento indesiderato del nodo immagine, poi ricrea cache e area di rilevamento. Anche una regione apparentemente bianca nel sorgente può essere pittura opaca reale; esamina la trasparenza prima di attribuire il problema al rilevamento.

Diagnostica separatamente lettura dei pixel e selezione dei destinatari

SintomoPrimo controllo
Il foro registra ancora l'immagineConferma che la cache sia stata creata dopo la decodifica, l'area ricostruita e nessun riempimento opaco o sfondo del sorgente copra il foro
La grafica cambia ma i clic seguono ancora una vecchia formaCancella e ricrea cache della scena e area alfa dopo il cambio di sorgente
Compare un errore di lettura pixel o canvas contaminatoControlla origine dell'immagine e intestazioni della risposta prima di interpretare il rilevamento
L'intera immagine smette di ricevere eventiControlla listening, visibilità, ordine dei livelli e presenza di un altro nodo sopra
Un foro raggiunge lo stage invece di un oggetto inferioreConferma che sotto quel punto esista davvero un oggetto previsto che riceve eventi
I clic sul canvas funzionano ma la tastiera noProgetta separatamente comandi da tastiera e semantica: i pixel di rilevamento alfa non li forniscono

Questo esempio serve entrambi gli SVG dalla stessa origine della pagina. Le immagini provenienti da un'altra origine richiedono un canvas non contaminato per rileggere i pixel. La guida di Konva al canvas contaminato spiega l'uso di crossOrigin insieme a un server che consenta la richiesta CORS. Impostare solo crossOrigin = 'anonymous' non può concedere accesso se il server non lo permette. Questo articolo non ha eseguito un caso di errore tra origini diverse.

Cambiare il CSS pointer-events sul canvas esterno non sceglie quali pixel dentro una Konva.Image colpiscano i nodi interni. Tieni separata la selezione nel canvas dalla selezione dei destinatari nel DOM SVG. Conserva anche il master SVG: una mappa di rilevamento in cache è un dato di interazione basato sui pixel, non un documento vettoriale sostitutivo.

Separa il recupero della grafica dai collegamenti degli eventi

Se all'app servono soltanto posizionamento dell'immagine e rilevamento basato sull'alfa, un raster trasparente adatto può già bastare. Se rimane solo un PNG o JPG e l'app richiede anche geometria modificabile, il flusso da immagine a vettore di PerfectVector può aiutarti a recuperare un SVG candidato. Esamina sagoma e fori, poi scegli la rappresentazione Konva e implementane gli eventi. Questo esempio usava SVG nativi originali e non ha eseguito una conversione PerfectVector.

La vettorializzazione non installa listener, non crea controlli accessibili, non sceglie i destinatari dei clic e non mantiene sincronizzate le cache. Se esiste già un master SVG, correggi direttamente il codice di interazione. Per un file che contiene inaspettatamente un'immagine rettangolare completa, usa il controllo raster incorporato nell'SVG prima di presumere che il contenuto sia formato da tracciati modificabili separati.

Domande frequenti

Perché i pixel trasparenti della mia immagine Konva ricevono clic? Un nodo Image predefinito può usare il proprio rettangolo per il rilevamento. Quando il sorgente è pronto, crea la cache e usa drawHitFromCache con una soglia alfa numerica adatta, poi ridisegna e prova i destinatari effettivi.

Quale argomento accetta drawHitFromCache? L'API attuale accetta una soglia alfa intera facoltativa da 0 a 255, con valore predefinito 0. L'esempio provato passa 0. Non passa una callback e non usa il filtro visivo Threshold.

Perché un riempimento bianco rende di nuovo cliccabile il foro SVG? Un riempimento opaco del nodo Image entra nella sua scena in cache. L'alfa memorizzato include quindi quell'area dipinta. Rimuovi il riempimento indesiderato e ricrea cache della scena e area di rilevamento.

Un'area di rilevamento alfa rende i tracciati SVG modificabili singolarmente? No. La grafica rimane un unico nodo Image. Usa nodi Path separati adeguati e un modello di scena esplicito quando all'app servono controlli di singole regioni vettoriali.

Fonti

  1. Konva: Image Events — Comportamento predefinito delle immagini e generazione di un'area di rilevamento dalla grafica in cache.
  2. Konva: API Shape — Parametro numerico alphaThreshold attuale e relativo intervallo.
  3. Konva: API Node — Creazione e cancellazione della cache, destinatari degli eventi e metodi pubblici dei nodi.
  4. Konva: Guida al canvas contaminato — Restrizioni d'origine, CORS ed errori nella lettura dei pixel.
  5. Konva: SVG su canvas — Rendering dell'immagine intera rispetto a tracciati vettoriali costruiti separatamente.

Quando manca geometria modificabile, prepara un SVG candidato con PerfectVector, esaminane i fori e prova separatamente i destinatari dei clic Konva e gli aggiornamenti della cache previsti.

Altro dal blog

PerfectVector

Riparti da un SVG più pulito
e facile da modificare

Nessuna carta di credito