JSON Canvas Viewer

Sistema de Renderização

Pipeline de Renderização

graph TD
    START[Widget Build]
    PARSE[Parse JSON]
    SORT[Sort by zIndex]
    CALC[Calculate Dimensions]
    LOOP[Iterate Elements]
    TYPE{Element Type}
    RENDER[Render Element]
    WRAP[Wrap with Gestures]
    POSITION[Position in Stack]
    END[Complete Render]
    
    START --> PARSE
    PARSE --> SORT
    SORT --> CALC
    CALC --> LOOP
    LOOP --> TYPE
    TYPE --> RENDER
    RENDER --> WRAP
    WRAP --> POSITION
    POSITION --> LOOP
    LOOP --> END

Parse e Setup

Inicialização

void _parseAndSetupJson() {
  // 1. Parse JSON string
  parsed = parseJson(widget.jsonString);
  
  // 2. Extrair dimensões de design
  final canvas = parsed!['canvas'];
  designWidth = canvas?['exportWidth'] ?? 1080;
  designHeight = canvas?['exportHeight'] ?? 1920;
  
  // 3. Calcular dimensões do canvas
  final jsonWidth = canvas?['width'];
  final jsonHeight = canvas?['height'];
  
  // 4. Ordenar elementos por zIndex
  elements = List.from(parsed!['elements']);
  elements.sort((a, b) => 
    (a['zIndex'] ?? 0).compareTo(b['zIndex'] ?? 0)
  );
}

Sistema de Escala

Fator de Escala

double _getElementScaleFactor() {
  return math.min(
    canvasWidth / designWidth, 
    canvasHeight / designHeight
  );
}
### Aplicação Todas as dimensões são multiplicadas pelo fator de escala: ```dart final scaleFactor = _getElementScaleFactor(); // Posições final x = (element['x'] as num).toDouble() * scaleFactor; // Dimensões final width = (element['width'] as num).toDouble() * scaleFactor; // Tipografia final fontSize = (element['fontSize'] as num).toDouble() * scaleFactor; ```

Ordem de Renderização (Z-Index)

Sorting

if (elements.length > 1) {
  elements.sort((a, b) {
    final aZ = (a['zIndex'] ?? 0) as num;
    final bZ = (b['zIndex'] ?? 0) as num;
    return aZ.compareTo(bZ);
  });
}

Comportamento

zIndex menor

Renderizado primeiro (atrás)

zIndex maior

Renderizado depois (frente)

zIndex igual

Ordem original do array

zIndex omitido

Tratado como 0


Posicionamento

Sistema de Coordenadas

Centralização

Por String "center"

"x": "center"

Centraliza automaticamente

Por Flags

"centerX": true

Centraliza horizontalmente


Transformações

Rotação

class ApplyRotation extends StatelessWidget {
  Widget build(BuildContext context) {
    if (rotation == null || rotation == 0) return child;
    
    return Transform.rotate(
      angle: rotation! * (math.pi / 180),
      child: child
    );
  }
}

Características:

Opacidade

if (opacity < 1.0) {
  widget = Opacity(opacity: opacity, child: widget);
}

Parsing de Cores

Color _parseColor(String hexColor) {
  hexColor = hexColor.replaceAll('#', '');
  if (hexColor.length == 6) {
    hexColor = 'FF$hexColor';  // Adiciona alpha 100%
  }
  return Color(int.parse('0x$hexColor'));
}

Suporte:


Layout Final

Widget build(BuildContext context) {
  return Container(
    width: canvasWidth,
    height: canvasHeight,
    child: Stack(
      fit: StackFit.expand,
      children: elements.map((el) {
        Widget elementWidget = _renderElement(el);
        return _wrapWithDragGesture(elementWidget, index);
      }).toList(),
    ),
  );
}

Performance

Otimizações

Parse Único

JSON parseado uma vez em setup

Sort Único

Elementos ordenados após parse

Scale Cache

Fator calculado uma vez por build

Conditional Rebuild

Verifica mudanças em didUpdateWidget

Limitações

Elementos FPS Experiência
0-20 60 Excelente
20-50 60 Ótima
50-100 45-60 Boa
100+ 30-45 Degradada

Próximos Passos

Interatividade

Sistema de gestos e manipulação

Ver Gestos →

Elementos

Tipos específicos de elementos

Ver Elementos →

Decisões Técnicas

Justificativas arquiteturais

Ver Decisões →