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
- Origem (0,0): Canto superior esquerdo
- Eixo X: Cresce para direita
- Eixo Y: Cresce para baixo
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:
- Rotação em graus (0-360)
- Ponto de rotação: centro do elemento
- Aplicada após todos os estilos
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:
#RRGGBB
: RGB com alpha implícito#AARRGGBB
: ARGB com alpha explícito
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 |