PerfectVector
Por Irene Kim

Ignora las áreas transparentes de un SVG en Konva

Haz que las áreas transparentes de una imagen SVG ignoren clics en Konva. Reproduce la detección basada en caché, prueba agujeros y fondos y reconstruye los aciertos tras cambiar la fuente.

14 min de lectura
En esta página

Para que las áreas transparentes de una Konva.Image ignoren clics, espera a que se decodifique su imagen fuente, llama a imageNode.cache(), después a imageNode.drawHitFromCache(0) y vuelve a dibujar la capa. El alfa de la escena en caché, es decir, la opacidad de los píxeles, determina entonces qué píxeles de la imagen participan en la detección de aciertos.

Un nodo de imagen normal puede recibir eventos en todo su rectángulo, incluido un agujero vacío del SVG. El tutorial de eventos de imagen de Konva muestra la alternativa basada en alfa. Este artículo prueba un SVG hueco original sobre un fondo separado que también recibe clics, de modo que un agujero que deja de captar clics de imagen tiene un destino real debajo que los recibe.

Esto cambia el área de interacción del lienzo. No crea nodos Konva.Path editables a partir del SVG ni cambia las reglas pointer-events de un SVG en el DOM.

Separa la imagen de su región de acierto

Una región de acierto es el área que Konva usa para elegir el destino de un evento. Su forma puede diferir del diseño visible. En algunas aplicaciones, un destino rectangular amplio es intencional; en otras, los agujeros transparentes deben permitir seleccionar un objeto inferior.

Interacción previstaPunto de partida
Seleccionar toda la imagen desde cualquier punto de su rectánguloComportamiento de acierto predeterminado de Image
Permitir que los píxeles transparentes alcancen un nodo inferiorGuardar la imagen en caché y construir su región de acierto a partir del alfa
Editar o asignar acciones independientes a regiones vectoriales individualesElegir trazados Konva separados y definir su comportamiento
Controlar los destinos del puntero dentro de un SVG DOM en líneaUsar la guía independiente de pointer-events en SVG

La API actual de Shape recibe un entero alphaThreshold de 0 a 255; su valor predeterminado es 0. Pasa aquí un número, no una función de retorno. Esto es distinto del filtro visual Threshold. El ejemplo usa 0 con interiores completamente opacos y agujeros completamente transparentes; no establece un umbral preferido para sombras suaves o bordes suavizados.

1. Guarda dos entradas SVG completas

Crea una carpeta vacía. Guarda este emblema hueco original como 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>

El subtrazado interior crea un agujero según la regla de relleno par-impar. Guarda la misma forma exterior sin ese subtrazado interior como 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>

El segundo archivo es el control de cambio de fuente. Pinta la ubicación que antes estaba vacía. Ningún archivo contiene un rectángulo de fondo blanco ni un mapa de bits incrustado.

2. Carga, guarda en caché y registra los destinos reales

El ejemplo usa Konva 10.9.0. Guarda estos tres archivos junto a ambos SVG. El HTML carga esa compilación de navegador con versión fijada; en un proyecto controlado, puedes servir la misma compilación localmente.

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

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

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

Sirve esta carpeta mediante HTTP en lugar de abrir el HTML como archivo local:

python -m http.server 8000

Abre http://localhost:8000/reader.html y espera a que aparezcan los cuatro escenarios. El SVG de 240 × 180 se coloca en las coordenadas de escenario (80,40) dentro de cada escenario de 420 × 260. Cada fondo es su propio Konva.Rect que escucha eventos, debajo de la imagen. El detector de clics del escenario informa event.target.id(), que identifica el nodo Konva elegido y no solo el elemento DOM canvas.

await source.decode() se ejecuta antes de crear la caché. Crea la caché cuando la fuente real esté lista, no mientras la imagen aún se carga. La API de Node de Konva documenta los métodos de creación y borrado de caché.

3. Haz clic en el área sólida, el agujero, la esquina y el fondo

Prueba las cuatro ubicaciones indicadas debajo de los paneles. Son coordenadas dentro de cada escenario, no coordenadas medidas desde la ventana del navegador.

UbicaciónCoordenada de escenarioQué prueba
Diseño sólido125,110Un punto opaco bien dentro del emblema
Agujero original195,130Un interior transparente en hollow.svg
Esquina transparente305,55Dentro del rectángulo de imagen, fuera de su silueta pintada
Fuera de la imagen20,20El fondo separado que recibe clics

La tabla siguiente registra el tipo de destino probado. Los registros incluyen el prefijo de cada panel, como alpha-background.

ConfiguraciónSólidoAgujero originalEsquina transparenteFuera de la imagen
Imagen predeterminadaImagenImagenImagenFondo
Región de acierto alfa en cachéImagenFondoFondoFondo
Imagen en caché con relleno blanco opacoImagenImagenImagenFondo
Fuente sustituida y caché reconstruidaImagenImagenFondoFondo
Comparación real de Konva en navegador con aciertos rectangulares predeterminados, aciertos alfa en caché, relleno opaco de imagen y fuente sustituida, incluidos los ID de destinos de clic registrados
Escenarios reales de Konva 10.9.0 con diseños SVG originales y destinos de clic de escritorio registrados. La imagen hueca basada en alfa deja que los clics del agujero y la esquina lleguen a su fondo separado. Un relleno de imagen opaco y una fuente de sustitución pintada cambian esos resultados.

La prueba en navegador usó clics reales del puntero en las 16 ubicaciones y registró la condición de confianza nativa del evento, las coordenadas de escenario y los ID de destino. También comprobó los hashes de los archivos fuente, la decodificación de imágenes, las dimensiones de escenarios e imágenes, los resultados públicos de intersección y las muestras alfa nativas del lienzo renderizado de cada nodo de imagen.

En el agujero original, el alfa del nodo de imagen hueca era 0. Los controles de relleno opaco y fuente sustituida tenían allí alfa 255. El fondo separado de la página no volvía opaca la imagen hueca: pertenecía a otro nodo Konva inferior. Son muestras interiores, alejadas de los límites suavizados.

Es una prueba en un navegador de escritorio con SVG originales sencillos y escenarios sin transformar. No demuestra el comportamiento móvil o táctil, la interacción con teclado, una matriz de varios navegadores, mejoras de rendimiento ni un umbral adecuado para cualquier imagen de bordes suaves. Repite la prueba de clics al tamaño y con las transformaciones reales de tu aplicación.

4. Reconstruye la caché cuando cambie la fuente

El cuarto panel empieza con la fuente hueca y su región de acierto alfa. Después borra la caché, instala la imagen de sustitución ya decodificada, vuelve a crear la caché y reconstruye la región de acierto. La ubicación del agujero original pasa del fondo a la imagen tras esa secuencia.

La caché es una instantánea renderizada. Después de un cambio que afecte a los píxeles renderizados, actualiza conjuntamente la escena en caché y su región de acierto basada en alfa. No supongas que asignar otra imagen ha actualizado una región de acierto ya almacenada en caché. Para una sustitución cargada de forma asíncrona, espera a que se decodifique antes de la secuencia del ejemplo.

El tercer panel aísla una causa distinta: artwork.fill('#ffffff') pinta un rectángulo opaco detrás de la imagen como parte de ese mismo nodo. Construir una región de acierto desde esa escena en caché incluye el área pintada. Elimina un relleno de nodo de imagen no deseado y reconstruye después la caché y la región de acierto. Una región de aspecto blanco en tu archivo fuente también puede ser pintura opaca real; inspecciona la transparencia antes de culpar a la detección de aciertos.

Diagnostica por separado los fallos de lectura y de destino

SíntomaQué comprobar primero
El agujero aún registra la imagenConfirma que la caché se creó después de decodificar, que se reconstruyó la región de acierto y que ningún relleno opaco o fondo de fuente cubre el agujero
El diseño cambió, pero los clics aún siguen una forma anteriorBorra y reconstruye la caché de escena y la región de acierto alfa después del cambio de fuente
Aparece un error de lectura de píxeles o de lienzo contaminadoComprueba el origen de la imagen y las cabeceras de respuesta antes de interpretar resultados de acierto
Toda la imagen deja de recibir eventosComprueba listening, la visibilidad, el orden de capas y si otro nodo está encima
Un agujero alcanza el escenario en lugar de un objeto inferiorConfirma que realmente exista un objeto previsto que escuche eventos debajo de ese punto
Los clics de lienzo funcionan, pero el teclado noDiseña por separado los controles y la semántica de teclado; los píxeles de acierto alfa no los proporcionan

Este ejemplo sirve ambos SVG desde el mismo origen que la página. Las imágenes entre orígenes requieren un lienzo con origen limpio para leer píxeles. La guía de lienzo contaminado de Konva explica el uso de crossOrigin junto con un servidor que permita la solicitud CORS. Establecer solo crossOrigin = 'anonymous' no puede conceder acceso si el servidor no lo permite. Este artículo no ejecutó un caso de fallo entre orígenes.

Cambiar pointer-events de CSS en el lienzo exterior no elige qué píxeles de una Konva.Image aciertan en sus nodos internos. Separa los destinos de lienzo de los destinos del puntero en SVG DOM. Conserva también el maestro SVG: un mapa de aciertos en caché es información de interacción basada en píxeles, no un documento vectorial de sustitución.

Separa la recuperación del diseño de los eventos

Si tu aplicación solo necesita colocar imágenes y usar aciertos basados en alfa, quizá baste una imagen ráster transparente adecuada. Si solo queda un PNG o JPG y la aplicación también necesita geometría de trazados editable, el flujo de imagen a vector de PerfectVector puede ayudar a recuperar un SVG candidato. Inspecciona la silueta y los agujeros, elige después la representación Konva e implementa sus eventos. Este ejemplo usó SVG nativos originales y no realizó una conversión de PerfectVector.

La vectorización no instala detectores, ni construye controles accesibles, ni elige destinos de clic, ni mantiene sincronizadas las cachés. Si ya existe un maestro SVG, corrige directamente el código de interacción. Para un archivo que contenga inesperadamente una imagen rectangular completa, usa la comprobación de ráster incrustado en SVG antes de suponer que su contenido son trazados editables separados.

Preguntas frecuentes

¿Por qué los píxeles transparentes de mi imagen Konva reciben clics? Un nodo Image predeterminado puede usar su área rectangular para los aciertos. Cuando la fuente esté lista, guárdala en caché y usa drawHitFromCache con un umbral alfa numérico adecuado; después vuelve a dibujar y prueba los destinos reales.

¿Qué argumento recibe drawHitFromCache? La API actual acepta un umbral alfa entero opcional de 0 a 255, con valor predeterminado 0. El ejemplo probado pasa 0. No pasa una función de retorno ni usa el filtro visual Threshold.

¿Por qué un relleno blanco hace que el agujero SVG vuelva a recibir clics? Un relleno opaco del nodo Image pasa a formar parte de su escena en caché. El alfa en caché incluye entonces esa área pintada. Elimina el relleno no deseado y reconstruye la caché de escena y la región de acierto.

¿Una región de acierto alfa hace editables los trazados SVG por separado? No. El diseño sigue siendo un nodo Image. Usa nodos Path separados adecuados y un modelo de escena explícito si tu aplicación necesita controles de regiones vectoriales individuales.

Fuentes

  1. Konva: Eventos de imagen — comportamiento de acierto predeterminado de imágenes y generación de una región de acierto a partir del diseño en caché.
  2. Konva: API de Shape — parámetro numérico actual alphaThreshold y su rango.
  3. Konva: API de Node — creación y borrado de caché, destinos de eventos y métodos públicos de nodos.
  4. Konva: Guía de lienzo contaminado — restricciones de origen, CORS y fallos de lectura de píxeles.
  5. Konva: SVG en canvas — renderizado de imagen completa frente a trazados vectoriales construidos por separado.

Cuando falte geometría editable, prepara un SVG candidato con PerfectVector, inspecciona sus agujeros y prueba después por separado los destinos de clic Konva previstos y las actualizaciones de caché.

Más del blog

PerfectVector

Empieza con un SVG más limpio
y fácil de editar

Sin tarjeta de crédito