Ignorer les zones SVG transparentes aux clics dans Konva
Fais ignorer les clics aux zones transparentes d’une image SVG dans Konva. Reproduis la détection par cache, teste trous et fonds et reconstruis les zones après un changement de source.
Sur cette page
- Sépare l’image de sa zone de détection
- 1. Enregistre deux entrées SVG complètes
- 2. Charge, mets en cache et consigne les véritables cibles
- 3. Clique sur la zone pleine, le trou, le coin et le fond
- 4. Reconstruis le cache quand la source change
- Diagnostique séparément les erreurs de lecture et de ciblage
- Sépare la récupération de l’illustration et les événements
- Questions fréquentes
- Sources
Pour que les zones transparentes d’une Konva.Image ignorent les clics, attends le décodage de son image source, appelle imageNode.cache(), puis imageNode.drawHitFromCache(0) et redessine le calque. L’alpha de la scène en cache, c’est-à-dire l’opacité des pixels, détermine alors quels pixels de l’image participent à la détection des clics.
Un nœud d’image normal peut recevoir des événements dans tout son rectangle, y compris dans un trou SVG vide. Le tutoriel Image Events de Konva montre l’alternative fondée sur l’alpha. Cet article teste un SVG creux original au-dessus d’un fond cliquable distinct : un trou qui cesse de capter les clics d’image a donc une véritable cible sous-jacente pour les recevoir.
Cela change la zone d’interaction du canevas. Cela ne crée pas de nœuds Konva.Path modifiables à partir du SVG et ne change pas les règles pointer-events du SVG dans le DOM.
Sépare l’image de sa zone de détection
Une zone de détection est la surface utilisée par Konva pour choisir la cible d’un événement. Sa forme peut différer de l’illustration visible. Certaines applications souhaitent volontairement une large cible rectangulaire ; d’autres veulent que les trous transparents permettent de sélectionner un objet inférieur.
| Interaction souhaitée | Point de départ |
|---|---|
| Sélectionner toute l’image depuis n’importe où dans son rectangle | Comportement de détection Image par défaut |
| Laisser les pixels transparents atteindre un nœud sous-jacent | Mettre l’image en cache et construire sa zone de détection à partir de l’alpha |
| Modifier des régions vectorielles individuelles ou leur attribuer des actions indépendantes | Choisir des chemins Konva distincts et définir leur comportement |
| Contrôler les cibles du pointeur dans un SVG DOM en ligne | Utiliser le guide distinct de pointer-events SVG |
L’API Shape actuelle prend un entier alphaThreshold de 0 à 255 ; sa valeur par défaut est 0. Passe un nombre ici, pas une fonction de rappel. C’est distinct du filtre visuel Threshold. L’exemple utilise 0 avec des intérieurs entièrement opaques et des trous entièrement transparents ; il n’établit pas de seuil préféré pour les ombres douces ou les bords anticrénelés.
1. Enregistre deux entrées SVG complètes
Crée un dossier vide. Enregistre cet emblème creux original sous 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>Le sous-chemin intérieur crée un trou avec la règle de remplissage pair-impair. Enregistre la même forme extérieure sans ce sous-chemin intérieur sous 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>Le second fichier est le témoin de changement de source. Il peint l’emplacement auparavant vide. Aucun fichier ne contient de rectangle blanc de fond ni de bitmap incorporé.
2. Charge, mets en cache et consigne les véritables cibles
L’exemple utilise Konva 10.9.0. Enregistre ces trois fichiers à côté des deux SVG. Le HTML charge cette version de navigateur figée ; pour un projet contrôlé, tu peux plutôt servir la même version localement.
Enregistre 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>Enregistre 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; }Enregistre 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}`;Sers ce dossier en HTTP au lieu d’ouvrir le HTML comme fichier local :
python -m http.server 8000Ouvre http://localhost:8000/reader.html et attends l’apparition des quatre scènes. Le SVG de 240 × 180 est placé aux coordonnées de scène (80,40) dans chaque scène de 420 × 260. Chaque fond est son propre Konva.Rect à l’écoute des événements, sous l’image. L’écouteur de clic de la scène rapporte event.target.id(), qui identifie le nœud Konva choisi plutôt que le seul élément DOM canvas.
await source.decode() s’exécute avant la création du cache. Mets en cache lorsque la véritable source est prête, pas pendant que l’image charge encore. L’API Node de Konva documente les méthodes de création et de vidage du cache.
3. Clique sur la zone pleine, le trou, le coin et le fond
Teste les quatre emplacements indiqués sous les panneaux. Ce sont des coordonnées dans chaque scène, pas des coordonnées mesurées depuis la fenêtre du navigateur.
| Emplacement | Coordonnée de scène | Ce qui est testé |
|---|---|---|
| Illustration pleine | 125,110 | Un point opaque bien à l’intérieur de l’emblème |
| Trou d’origine | 195,130 | Un intérieur transparent dans hollow.svg |
| Coin transparent | 305,55 | À l’intérieur du rectangle d’image, hors de sa silhouette peinte |
| Hors de l’image | 20,20 | Le fond cliquable distinct |
Le tableau suivant consigne le type de cible testé. Les journaux incluent le préfixe de chaque panneau, comme alpha-background.
| Configuration | Zone pleine | Trou d’origine | Coin transparent | Hors de l’image |
|---|---|---|---|---|
| Image par défaut | Image | Image | Image | Fond |
| Zone de détection alpha en cache | Image | Fond | Fond | Fond |
| Image en cache avec fond blanc opaque | Image | Image | Image | Fond |
| Source remplacée et cache reconstruit | Image | Image | Fond | Fond |

Le test navigateur a utilisé de véritables clics de pointeur aux 16 emplacements et consigné l’état natif de confiance de l’événement, les coordonnées de scène et les identifiants de cible. Il a aussi vérifié les empreintes des fichiers source, le décodage des images, les dimensions des scènes et images, les résultats publics d’intersection et les échantillons alpha natifs du canevas rendu de chaque nœud d’image.
Au trou d’origine, l’alpha du nœud d’image creuse était de 0. Les témoins de fond opaque et de source remplacée avaient un alpha de 255 à cet endroit. Le fond de page distinct ne rendait pas l’image creuse elle-même opaque : il appartenait à un autre nœud Konva situé dessous. Ce sont des échantillons intérieurs, éloignés des limites anticrénelées.
Il s’agit d’un test dans un seul navigateur de bureau, avec des SVG originaux simples et des scènes non transformées. Il ne prouve ni comportement mobile ou tactile, ni interaction clavier, ni matrice multinavigateur, ni gains de performances, ni seuil adapté à toutes les images à bords doux. Répète le test de clic à la véritable taille affichée et avec les transformations de ton application.
4. Reconstruis le cache quand la source change
Le quatrième panneau commence avec la source creuse et sa zone de détection alpha. Il vide ensuite le cache, installe l’image de remplacement déjà décodée, remet en cache et reconstruit la zone de détection. L’emplacement du trou d’origine passe du fond à l’image après cette séquence.
Le cache est un instantané rendu. Après un changement qui affecte les pixels rendus, actualise ensemble la scène en cache et sa zone de détection fondée sur l’alpha. Ne suppose pas que l’attribution d’une autre image a mis à jour une zone de détection déjà en cache. Pour un remplacement chargé de manière asynchrone, attends son décodage avant la séquence de l’exemple.
Le troisième panneau isole une autre cause : artwork.fill('#ffffff') peint un rectangle opaque derrière l’image comme partie de ce même nœud d’image. Construire une zone de détection à partir de cette scène en cache inclut la zone peinte. Supprime un fond de nœud d’image indésirable, puis reconstruis le cache et la zone de détection. Une région d’apparence blanche dans le fichier source peut aussi être une véritable peinture opaque ; inspecte la transparence avant d’accuser la détection.
Diagnostique séparément les erreurs de lecture et de ciblage
| Symptôme | Premier contrôle |
|---|---|
| Le trou consigne encore l’image | Confirme que la mise en cache suit le décodage, que la zone de détection a été reconstruite et qu’aucun fond opaque du nœud ou de la source ne couvre le trou |
| L’illustration a changé, mais les clics suivent encore une ancienne forme | Vide et reconstruis le cache de scène et la zone de détection alpha après le changement de source |
| Une erreur de lecture de pixels ou de canevas contaminé apparaît | Vérifie l’origine de l’image et les en-têtes de réponse avant d’interpréter un résultat de détection |
| Toute l’image cesse de recevoir des événements | Vérifie listening, la visibilité, l’ordre des calques et la présence d’un autre nœud au-dessus |
| Un trou atteint la scène au lieu d’un objet inférieur | Confirme qu’un objet prévu à l’écoute existe réellement sous ce point |
| Les clics de canevas fonctionnent, mais pas le clavier | Conçois les commandes et la sémantique clavier séparément ; les pixels de détection alpha ne les fournissent pas |
Cet exemple sert les deux SVG depuis la même origine que la page. Les images d’autres origines demandent un canevas non contaminé pour lire les pixels. Le guide de canevas contaminé de Konva explique l’utilisation de crossOrigin avec un serveur qui autorise la requête CORS. Définir seulement crossOrigin = 'anonymous' ne donne aucun accès si le serveur ne l’autorise pas. Cet article n’a pas exécuté de cas d’échec entre origines.
Changer pointer-events en CSS sur le canevas extérieur ne choisit pas quels pixels d’une Konva.Image atteignent ses nœuds internes. Sépare le ciblage du canevas du ciblage de pointeur SVG DOM. Garde aussi le maître SVG : une carte de détection en cache est une donnée d’interaction fondée sur des pixels, pas un document vectoriel de remplacement.
Sépare la récupération de l’illustration et les événements
Si ton application a seulement besoin de placer une image et d’utiliser une détection alpha, une image matricielle transparente adaptée peut déjà suffire. S’il ne reste qu’un PNG ou JPG et que l’application a aussi besoin de chemins modifiables, le processus image vers vecteur de PerfectVector peut aider à récupérer un SVG candidat. Inspecte la silhouette et les trous, puis choisis la représentation Konva et implémente ses événements. Cet exemple utilisait des SVG natifs originaux et n’a effectué aucune conversion PerfectVector.
La vectorisation n’installe pas d’écouteurs, ne construit pas de commandes accessibles, ne choisit pas les cibles de clic et ne synchronise pas les caches. Si un maître SVG existe déjà, corrige directement le code d’interaction. Pour un fichier contenant de manière inattendue une image rectangulaire complète, utilise le contrôle de contenu matriciel incorporé au SVG avant de supposer qu’il contient des chemins modifiables distincts.
Questions fréquentes
Pourquoi les pixels transparents de mon image Konva reçoivent-ils des clics ? Un nœud Image par défaut peut utiliser sa zone rectangulaire pour la détection. Lorsque la source est prête, mets-la en cache et utilise drawHitFromCache avec un seuil alpha numérique adapté, puis redessine et teste les véritables cibles.
Quel argument prend drawHitFromCache ? L’API actuelle accepte un seuil alpha entier facultatif de 0 à 255, par défaut 0. L’exemple testé passe 0. Il ne passe pas de fonction de rappel et n’utilise pas le filtre visuel Threshold.
Pourquoi un fond blanc rend-il mon trou SVG à nouveau cliquable ? Un fond opaque sur le nœud Image devient partie de sa scène en cache. L’alpha en cache inclut alors cette zone peinte. Supprime le fond indésirable et reconstruis le cache de scène et la zone de détection.
Une zone de détection alpha rend-elle les chemins SVG modifiables indépendamment ? Non. L’illustration reste un seul nœud Image. Utilise des nœuds Path distincts adaptés et un modèle de scène explicite si ton application demande des commandes par région vectorielle.
Sources
- Konva : Événements d’image — comportement de détection par défaut et génération d’une zone à partir de l’illustration en cache.
- Konva : API Shape — paramètre numérique alphaThreshold actuel et plage de valeurs.
- Konva : API Node — création et vidage du cache, cibles d’événement et méthodes publiques des nœuds.
- Konva : Guide du canevas contaminé — restrictions d’origine, CORS et échecs de lecture de pixels.
- Konva : SVG sur canvas — rendu de l’image entière ou chemins vectoriels construits séparément.
Lorsqu’il manque une géométrie modifiable, prépare un SVG candidat avec PerfectVector, inspecte ses trous, puis teste séparément les cibles de clic Konva prévues et les mises à jour du cache.
Plus depuis le blog

Marqueurs SVG dans Matplotlib : vérifier le chemin
Utilise un chemin SVG simple comme marqueur de nuage de points Matplotlib. Reproduis les contrôles de centrage, d’orientation, de trou et de taille dans les véritables exports SVG et PDF.

Ajouter un filigrane SVG à un PDF existant avec Python
Fusionne un filigrane SVG avec un PDF existant grâce à svglib, ReportLab et pypdf. Vérifie opacité, recadrage, rotation, texte conservé et ordre de superposition.
