Skip to main content

Integrator guide

Esta guía describe cómo integrar el plano en una app Angular. El contrato soportado es un solo camino: el selector upp-konva con una instancia de UppKonvaModel y filas DTO con kind.

Los miembros de UppKonvaArea (y del modelo) marcados en el código con @internal son enganches del host o del motor Konva: no entran en la referencia TypeDoc generada con excludeInternal, no se declaran en el .d.ts publicado (stripInternal), y no deben tratarse como contrato en integraciones de producto. La superficie soportada para apps está descrita en esta guía y en los bindings de upp-konva (p. ej. (onSelect) en lugar de resolver ids del lienzo a mano).


1. Módulo y plantilla

1.1. Importar UppKonvaModule

import { NgModule } from '@angular/core';
import { UppKonvaModule } from '@unpispas/upp-konva';

@NgModule({
imports: [UppKonvaModule],
})
export class FloorPlanHostModule {}

1.2. Componente upp-konva

BindingUso
[model]Instancia UppKonvaModel (obligatoria).
[active]boolean, por defecto true. Con false el lienzo reduce trabajo cuando el plano no hace falta animar o repintar al detalle.
[theme]UPPKONVA_LIGHTTHEME | UPPKONVA_DARKTHEME (preset).
(onChange)Sin payload; se dispara cuando cambia la lista de figuras a nivel estructural (alta/baja/reemplazo de filas). Enlazalo a onModelChanged del modelo si preferís callback en el TS.
(onSelect)Emite las UppKonvaShape vivas seleccionadas en el lienzo.
<upp-konva
[model]="canvas"
[active]="planVisible"
[theme]="'UPPKONVA_DARKTHEME'"
(onChange)="onStructural()"
(onSelect)="onFigures($event)"
/>

El host expone data-id="upp-konva-integration" para pruebas automáticas.

1.3. Cableado recomendado

  1. Creá new UppKonvaModel(initialSource) con un UppKonvaAreaSource ( width, height, shapes con kind por fila).
  2. Asigná canvas.onModelChanged si necesitás lógica además del (onChange) del template (el host encadena ambos).
  3. Para multi-selección, suscribite a canvas.area.onGrouped$ (RxJS), no a callbacks en el DTO.
  4. Volcado de datos: canvas.area.source, canvas.applyAreaFromSource(...), canvas.exportModel(), canvas.importModel(json), canvas.exportToPng().

2. UppKonvaModel (resumen)

MiembroUso
areaUppKonvaArea viva (misma referencia de por vida). Actualizar: area.source = … o applyAreaFromSource. Incluye area.selectShape(shape | null) para seleccionar en el lienzo una figura de area.shapes o limpiar la selección.
modeVIEW | EDIT.
themePreset o null; combinable con [theme].
marginPx, viewZoom, pixelRatioMaxPresentación del encuadre (también configurables vía campos opcionales del DTO de sala).
onModelChangedSolo cuando cambia la lista estructural de figuras (id + kind en orden).
exportModel, importModel, exportToPngSerialización JSON y captura PNG mientras upp-konva está montado.
pushUndoSnapshot, undo, canUndoPila de deshacer en EDIT.
doDestroy()Limpieza al destruir el componente o abandonar el modelo.

Mutar una figura viva in situ (geometría, shapeData, etiquetas) no dispara onModelChanged; usá onUpdated$ de esa figura. Detalle en la referencia TypeDoc bajo Public model API.


3. Qué exporta el barrel desde lib/model/

Todo lo siguiente se importa desde @unpispas/upp-konva:

SímboloRol
UppKonvaModelRaíz del plano cableada a upp-konva.
UppKonvaAreaClase del área viva (model.area); static from(source) equivale al constructor interno del modelo.
UppKonvaGroupMulti-selección (onGrouped$).
UppKonvaShapeClase base abstracta de figuras vivas (geometría, shapeData, streams, remove(), …).

Tipos DTO y de catálogo: UppKonvaAreaSource, UppKonvaShapeSource, UppKonvaShapeKind, UppKonvaOrientation, UppKonvaDrawMode, UppKonvaEditMode, UppKonvaTheme, UppKonvaAxis, UppKonvaLabelFontSize.

Importante: el barrel público no expone artefactos de stage ni subclases/fábricas internas de figuras. La integración se hace con la abstracción del model.


4. DTO: UppKonvaAreaSource y UppKonvaShapeSource

  • Cada fila del array shapes es un UppKonvaShapeSource: id, kind, geometría (x, y, width, height, rotation en cm y grados), opcionales label, sublabel, zIndex, mode, custom, y bolsa data según kind (ver §5).
  • El documento JSON versionado lo cubren exportModel / importModel desde UppKonvaModel.

5. Catálogo UppKonvaShapeKind y campo data

Valores de kind (lista cerrada): VERTEX, TABLE, BAR, DOOR, WINDOW, STAIRS, BILLIARD, SOFA, FOOTBALL, GENERIC.

En figuras vivas, los mismos campos viven en shape.shapeData (objeto plano); al persistir, el modelo proyecta ese estado sobre el DTO público en area.source.

5.1. Campos comunes (todas las filas)

Campo (DTO / vivo)Uso
idIdentificador estable de la fila (UUID recomendado).
kindDiscriminante (en vivo: shape.kind de solo lectura).
x, y, width, height, rotationGeometría en cm y grados.
label, sublabelTexto del badge en el lienzo si no están vacíos; tras editar in situ usá syncLabelsToStage() en la figura viva.
zIndexOrden de pintado (§8).
customBolsa opaca para la app; puede reenviarse en payloads de selección/actualización.

5.2. VERTEX

dataTipo / valoresUso
sortnumberOrden dentro de la cadena de muro.
poligonstringIdentificador de cadena; en JSON legacy a veces polygon (el parseo lo normaliza).
closedbooleanSi es true en todos los vértices de la misma cadena, el polígono se cierra y rellena.

5.3. TABLE

dataTipo / valoresUso
shapeSQUARE | CIRCLEMesa rectangular vs elíptica (CIRCLE = elipse en el bbox). En shapeData tras ciertos volcados del motor puede aparecer también ROUND como sinónimo de variante redonda.
chairsnumber0Cantidad de sillas; 0 = solo tablero. Si omitís chairs al construir desde wire, el puente puede asumir un default (p. ej. 4).

Resaltado “atención” en el lienzo (mesa u otra figura cableada): shape.attention = true / lectura shape.attention sobre la UppKonvaShape viva (no suele ir en el DTO UppKonvaShapeSource).

5.4. BAR

dataTipo / valoresUso
shapeLINEAR | TOLEFT | TORIGHT | USHAPEForma de la barra.
stoolLeft, stoolFront, stoolRightnumber0 o omitidoTaburetes por lado. Si omitís la clave, ese lado no lleva taburetes. stoolLeft/stoolRight aplican según la forma (p. ej. TOLEFT, USHAPE).

En vista, onSelected$ puede traer stool: null = clic en el cuerpo de la barra; número = índice global del taburete.

5.5. DOOR, WINDOW, STAIRS

En el DTO público la variante va en data.shape (el motor la mapea a architectureShape internamente):

kinddata.shape (valores reconocidos)Default típico
DOORTOLEFT | TORIGHTTOLEFT
WINDOWSINGLE | DOUBLESINGLE
STAIRSSIMPLE | DOUBLE | SNAILSIMPLE

5.6. SOFA

dataTipo / valoresUso
shapeLINEAR | TOLEFT | TORIGHTChaise recto o retorno en L a izquierda/derecha.

5.7. GENERIC

dataTipo / valoresUso
shapeSQUARE | ROUND | CIRCLEMueble genérico rectangular vs redondo (ROUND/CIRCLE → elipse en el bbox).

5.8. BILLIARD y FOOTBALL

Sin variantes obligatorias en data: podés omitir data o dejarla vacía; la geometría es el bbox (x, y, width, height, rotation).


6. Figuras vivas: UppKonvaShape y shapeData

Las instancias viven en model.area.shapes. La clase base expone geometría (x, y, width, height, rotation), id, kind, label, sublabel, shapeData, onSelected$, onUpdated$, parentArea, remove(), syncPresentationToStage() (tras mutar shapeData sin cambiar geometría global), syncLabelsToStage(), doDestroy().

StreamCuándo
onSelected$Modo VIEW: selección simple en el lienzo (solo 1 elemento).
onUpdated$Modo EDIT: cambios confirmados en el lienzo.

Payload de streams: objeto con bolsa opcional custom y, en barras, campo opcional stool (como en §5.4).

Para acotar tipos en TypeScript, usar discriminación por shape.kind y leer/validar shape.shapeData según catálogo del kind.


7. Multi-selección: onGrouped$ y UppKonvaGroup

Con dos o más figuras seleccionadas, area.onGrouped$ emite un UppKonvaGroup; con cero o uno, emite null. Es el objeto de producto para alinear barras de herramientas con el lienzo ( selection, align, distribute, etc.). Ver la referencia TypeDoc bajo Public model API.

En selección múltiple, la notificación por figura shape.onSelected$ no se emite para evitar duplicar señal con onGrouped$.


8. Orden de pintado (zIndex)

  • zIndex numérico: valores menores se dibujan más abajo. Por defecto 0.
  • A igual zIndex, el paquete aplica un orden interno estable.

9. Ejemplo mínimo

import { Component } from '@angular/core';
import { UppKonvaModel, type UppKonvaAreaSource } from '@unpispas/upp-konva';

@Component({
selector: 'app-floor-plan-shell',
templateUrl: './floor-plan-shell.component.html',
})
export class FloorPlanShellComponent {
readonly canvas = new UppKonvaModel({
width: 800,
height: 600,
name: 'Sala demo',
shapes: [
{
id: 't-1',
kind: 'TABLE',
x: 200,
y: 200,
width: 120,
height: 80,
rotation: 0,
data: { shape: 'SQUARE', chairs: 4 },
label: 'Mesa 1',
custom: { ticketId: 42 },
},
],
} satisfies UppKonvaAreaSource);

onStructural(): void {
void this.canvas.exportModel();
}
}
<upp-konva [model]="canvas" (onChange)="onStructural()" />

JSON sin modelo vivo

import {
adapterAreaToAreaSource,
areaSourceToAdapterArea,
parseFloorPlanDocument,
serializeFloorPlanDocument,
} from '@unpispas/upp-konva';

const parsed = parseFloorPlanDocument(json);
if (!parsed.ok) {
throw new Error(parsed.message);
}
const model = new UppKonvaModel(adapterAreaToAreaSource(parsed.area));
// Con modelo vivo suele bastar `model.exportModel()`.
const wireJson = serializeFloorPlanDocument(areaSourceToAdapterArea(model.area.source));

parseFloorPlanDocument devuelve UppKonvaWireArea; adapterAreaToAreaSource la convierte al DTO público con kind. serializeFloorPlanDocument espera UppKonvaWireArea (areaSourceToAdapterArea(model.area.source)).