CreaRack-SL

Concepto: colores simbólicos de mxGraph y su resolución en SVG

Resumen

Los stencils de draw.io (que alimentan el catálogo de CreaRack) usan colores simbólicos como frameColor, cabinetColor, stroke, fillColor1 en su formato interno. El navegador no entiende estos identificadores — los trata como color inválido (devuelve a negro) — generando un visual opaco e ilegible: el “velo negro” reportado en v1.46.0.

Solución (v1.48.0): el conversor scripts/stencils/convert_mxgraph_stencils.py mapea cada símbolo a su valor hexadecimal #RRGGBB antes de generar el SVG. El catálogo se regenera (185/185 stencils, 0 símbolos).

El problema: “velo negro”

Qué es un color simbólico en draw.io

En el formato XML/JSON interno de draw.io, los stencils pueden referenciar colores de manera simbólica:

<fillcolor color="cabinetColor" />
<strokecolor color="frameColor" />

Estos símbolos se resuelven en el cliente de draw.io según un tema o paleta configurable. Cuando se exporta a SVG, draw.io sustituye los símbolos por sus valores concretos. Sin embargo, si el conversor copia el símbolo directamente al SVG (sin resolución), el navegador lo recibe así:

<rect fill="cabinetColor" stroke="frameColor" />

Un navegador HTML5 no reconoce cabinetColor como un color válido. Por defecto, echa mano a negro (#000000) como fallback, lo que genera una losa oscura que tapa el detalle del stencil.

Síntomas observados (v1.46.0)

  • Usuarios reportan que algunos stencils de rack, al soltarlos en el mapa, quedan como un rectángulo negro opaco
  • Algunos stencils (ej: patch panels, servidores) se ven bien, otros (racks completos) no
  • El efecto es más visible sobre el fondo oscuro del canvas

Causa raíz

El conversor (convert_mxgraph_stencils.py anterior a v1.48.0):

  1. Leyendo el XML de draw.io
  2. Copiaba los valores de fillcolor, strokecolor, etc. tal cual al SVG (<svg>)
  3. Si el valor era un símbolo como "frameColor", lo insertaba literalmente
  4. El navegador rechazaba el color inválido → fallback a negro

La solución: mapeo simbólico

Mapa SYMBOLIC_COLORS (v1.48.0)

El conversor define una tabla de resolución:

SYMBOLIC_COLORS = {
    "stroke": "currentColor",       # Usa el color de trazo del contexto
    "strokeColor": "currentColor",
    "frameColor": "#9ca3af",        # Marco gris de racks 19" (Tailwind gray-400)
    "cabinetColor": "#374151",      # Interior armario (Tailwind gray-700)
    "fillColor1": "#94a3b8",        # Relleno secundario (Tailwind slate-400)
}

Valores elegidos:

  • #9ca3af (gris claro): marca los bordes de los racks 19” con suficiente contraste sobre el lienzo oscuro (#1a1a1a)
  • #374151 (gris oscuro): interior del armario, diferente del fondo para que no se pierda
  • #94a3b8 (azul-gris): rellenos secundarios (floorplan, detalles)
  • currentColor: para trazos, hereda el color del estado (azul activo, amarillo warning, rojo error)

Flujo de conversión (modificado)

  1. Parsear el XML de draw.io
  2. Cuando encuentra <fillcolor color="cabinetColor" />
    • Obtiene el valor: "cabinetColor"
    • Consulta SYMBOLIC_COLORS.get("cabinetColor") → devuelve "#374151"
    • Asigna al estado: state["fill"] = "#374151"
  3. Genera el SVG con el valor resuelto
  4. Resultado: <rect fill="#374151" /> (válido, navegador lo procesa correctamente)

Pasos en el código

# Antes (v1.46.0)
elif tag == "fillcolor":
    self.state["fill"] = el.get("color") or DEFAULT_FILL

# Después (v1.48.0)
elif tag == "fillcolor":
    color = el.get("color") or DEFAULT_FILL
    self.state["fill"] = SYMBOLIC_COLORS.get(color, color)
    # Si color es "cabinetColor" → mapea a "#374151"
    # Si color es "#ff9900" (hex) → lo deja tal cual (no está en el mapa)

Stencils afectados

El conversor añade el flag materialize: "rack" a los 9 stencils que representan racks completos:

  • Todos ellos usaban colores simbólicos (frameColor para los bordes del rack 19”)
  • Son los que más sufrían del “velo negro” en v1.46.0

Lista (por set y ID):

  1. rack-general::12u-rack-19-standard
  2. rack-general::26u-rack-19-standard
  3. rack-general::36u-rack-19-standard
  4. rack-general::40u-rack-19-standard
  5. rack-general::42u-rack-19-standard (más usado)
  6. rack-general::44u-rack-19-standard
  7. rack-general::47u-rack-19-ibm
  8. rack-general::48u-rack-19-standard
  9. networks::rack (Rack de Network)

Otros stencils (servidores, patch panels, UPS) también se benefician de la resolución, pero no se materializan como racks reales.

Verificación

Catálogo regenerado

En v1.48.0, se ejecutó el conversor sobre todo el catálogo:

$ python scripts/stencils/convert_mxgraph_stencils.py
→ Generadas 185/185 formas
→ Símbolos no resueltos: 0

Testing visual

  • ✅ Los racks completos ahora tienen un visual nítido (marco gris, interior distinguible)
  • ✅ Detalle legible: las ranuras y etiquetas del rack se ven correctamente
  • ✅ Tintado por estado funciona: el color de borde (azul/amarillo/rojo) se aplica correctamente

Testing de compatibilidad

  • ✅ Stencils con colores hexadecimales originales (#ff9900, #1e1e1e) siguen funcionando
  • ✅ El mapa del SVG nuevo es una extensión (no reemplaza), así que colores inéditos se dejan pasar

Notas técnicas

currentColor en Konva

El valor "currentColor" en SVG es una palabra clave que hereda el color del contexto. En Konva, la tematización se hace con themeSvg() antes de rasterizar:

// StencilRenderer.js
const themed = this.themeSvg(svg, stroke)
    .replace('currentColor', borderColor);

Así, el borde del rack hereda el color de estado de monitorización (azul = OK, amarillo = warning, rojo = error).

El archivo static/stencils/floorplan.json (y otros) son generados, no editados a mano. Después de actualizar el conversor, hay que ejecutar:

python scripts/stencils/convert_mxgraph_stencils.py

Los cambios no se commitean al repo hasta que se verifica que el catálogo es válido (185/185).

Futuras mejoras

  1. Tema configurable: permitir que cada usuario o instalación redefinir el mapa SYMBOLIC_COLORS según su paleta corporativa
  2. Detección automática: analizar el catálogo de draw.io en tiempo de carga para detectar símbolos no resueltos y avisar
  3. Validación de catálogo: incluir un step en la CI que rechace catálogos con símbolos inválidos

Véase también

  • [[feature—blueprints—puente-rack-real]]
  • [[concept—blueprints—map-editor]]