Arquitetura Técnica
Visão Geral
O JSON Canvas Viewer segue uma arquitetura modular com separação clara de responsabilidades, implementando o padrão de apresentação baseado em widgets do Flutter com gerenciamento de estado local usando StatefulWidget.
Estrutura do Projeto
jsoncanvasviewer/
├── lib/
│ ├── main.dart # Ponto de entrada
│ └── src/
│ ├── modules/
│ │ └── home/
│ │ └── ui/
│ │ ├── home_page.dart # Coordenador principal
│ │ └── widgets/
│ │ ├── canvas_viewer_widget.dart
│ │ └── json_editor_widget.dart
│ └── shared/
│ ├── colors/
│ │ ├── app_colors.dart
│ │ └── editor_theme.dart
│ └── jsonWidget/
│ └── json_canvas_widget.dart # Motor de renderização
├── pubspec.yaml
└── analysis_options.yaml
Diagrama de Componentes
graph TB
subgraph "Camada de Apresentação"
MA[MyApp]
HP[HomePage]
JE[JsonEditorWidget]
CV[CanvasViewerWidget]
end
subgraph "Camada de Renderização"
JCV[JsonCanvasViewer]
AR[ApplyRotation]
end
subgraph "Camada de Dados"
JSON[JSON Data]
EL[Elements List]
end
subgraph "Camada de Tema"
ET[EditorTheme]
AC[AppColors]
end
MA --> HP
HP --> JE
HP --> CV
JE --> JSON
CV --> JCV
JCV --> JSON
JCV --> EL
JCV --> AR
JE --> ET
CV --> ET
JCV --> AC
Camadas da Arquitetura
Camada de Apresentação
Responsável pela interface do usuário e interação.
Componentes:
MyApp
: Configuração global da aplicaçãoHomePage
: Coordenador principal, gerencia estado compartilhadoJsonEditorWidget
: Editor de código JSONCanvasViewerWidget
: Visualizador do canvas
Camada de Renderização
Processa JSON e renderiza elementos visuais.
Componentes:
JsonCanvasViewer
: Motor de renderização principalApplyRotation
: Widget para aplicar transformações de rotação
Camada de Dados
Gerencia estrutura de dados e parsing.
Componentes:
- JSON parseado como
Map<String, dynamic>
- Lista de elementos ordenados por z-index
Camada de Tema
Define estilos visuais e cores.
Componentes:
EditorTheme
: Tema do editor de códigoAppColors
: Paleta de cores da aplicação
Fluxo de Comunicação
Fluxo de Edição (Editor → Canvas)
sequenceDiagram
participant U as Usuário
participant JE as JsonEditor
participant HP as HomePage
participant CV as CanvasViewer
participant JCV as JsonCanvasViewer
U->>JE: Digita no editor
JE->>JE: Inicia debounce (300ms)
Note over JE: Timer expira
JE->>JE: _validateJson()
JE->>HP: onJsonChanged(jsonString)
JE->>HP: onValidationChanged(isValid)
HP->>HP: setState(_jsonData, _isValid)
HP->>CV: Passa jsonData e isValid
CV->>CV: didUpdateWidget detecta mudança
CV->>JCV: Cria/atualiza JsonCanvasViewer
JCV->>JCV: _parseAndSetupJson()
JCV->>JCV: build() renderiza elementos
JCV->>U: Exibe canvas atualizado
Fluxo de Interação (Canvas → Editor)
sequenceDiagram
participant U as Usuário
participant JCV as JsonCanvasViewer
participant CV as CanvasViewer
participant HP as HomePage
participant JE as JsonEditor
U->>JCV: onPanStart (inicia drag)
JCV->>JCV: setState(_draggedElementIndex)
U->>JCV: onPanUpdate (arrasta)
JCV->>JCV: Atualiza elemento local
JCV->>CV: onElementMoved(index, newX, newY)
CV->>CV: _updateJsonOnElementMove()
CV->>CV: Modifica Map decoded
CV->>HP: onJsonUpdated(updatedJson)
HP->>HP: _isUpdatingFromCanvas = true
HP->>HP: setState(_jsonData)
HP->>HP: _isUpdatingFromCanvas = false
HP->>JE: externalJsonData atualizado
JE->>JE: didUpdateWidget detecta mudança
JE->>JE: _isUpdatingFromExternal = true
JE->>JE: _codeController.text = externalJson
JE->>JE: _isUpdatingFromExternal = false
JE->>U: Editor exibe JSON atualizado
U->>JCV: onPanEnd (termina drag)
JCV->>JCV: setState(limpa flags)
Gerenciamento de Estado
HomePage State
class _HomePageState extends State<HomePage> {
String _jsonData = '';
bool _isValid = false;
bool _isUpdatingFromCanvas = false;
// Atualização do editor
void _onJsonChanged(String jsonData) {
if (_isUpdatingFromCanvas) return; // Previne loop
Future.microtask(() {
if (mounted) setState(() => _jsonData = jsonData);
});
}
// Atualização do canvas
void onCanvasUpdate(String updatedJson) {
_isUpdatingFromCanvas = true;
setState(() => _jsonData = updatedJson);
_isUpdatingFromCanvas = false;
}
}
Prevenção de Loop Infinito
O sistema usa múltiplas flags para prevenir loops de atualização:
- HomePage:
_isUpdatingFromCanvas
- Ativada quando Canvas atualiza JSON
- Previne HomePage de notificar Canvas novamente
- JsonEditorWidget:
_isUpdatingFromExternal
- Ativada quando recebe dados externos
- Previne Editor de notificar HomePage novamente
- JsonEditorWidget:
_lastExternalData
- Cache do último dado externo
- Previne atualizações redundantes
Responsabilidades por Módulo
Módulo | Responsabilidades | Dependências |
---|---|---|
main.dart | Inicialização, tema global | MaterialApp, HomePage |
HomePage | Coordenação, estado compartilhado | JsonEditor, CanvasViewer |
JsonEditorWidget | Edição JSON, validação | CodeController, Debounce |
CanvasViewerWidget | Exibição canvas, detecção mudanças | JsonCanvasViewer |
JsonCanvasViewer | Parsing JSON, renderização elementos | Dart core, Flutter widgets |
EditorTheme | Estilos do editor | CodeThemeData |
AppColors | Cores da aplicação | Color constants |
Sistema de Escala
O sistema implementa coordenadas de design fixo que escalam proporcionalmente:
// Dimensões de design (referência)
designWidth = 1080
designHeight = 1920
// Fator de escala
scaleFactor = min(canvasWidth / designWidth, canvasHeight / designHeight)
// Aplicação
finalX = originalX * scaleFactor
finalFontSize = originalFontSize * scaleFactor
Benefícios:
- Designers trabalham em resolução fixa
- Canvas se adapta a qualquer tamanho
- Coordenadas intuitivas e previsíveis
Padrões Utilizados
Observer Pattern
- Callbacks para comunicação entre widgets
onJsonChanged
,onValidationChanged
,onElementMoved
State Management
- Local state com
StatefulWidget
- Props drilling para estado compartilhado
Composition over Inheritance
- Widgets compostos de outros widgets
- Reutilização através de composição
Debouncing
- Timer de 300ms para otimizar performance
- Reduz chamadas desnecessárias ao parser
Performance
Otimizações Implementadas
- Debouncing: Timer de 300ms nas atualizações do editor
- Microtasks:
Future.microtask
para callbacks assíncronos - Conditional Rebuild: Verificações em
didUpdateWidget
- Z-Index Sorting: Ordenação única durante parse
- Scale Factor Cache: Cálculo único por build
Limitações de Performance
- Não virtualizado: todos elementos renderizados sempre
- Rebuild completo do Stack a cada mudança
- Recomendado: máximo 50-100 elementos
Próximos Passos
- Explore Componentes para detalhes de implementação
- Veja Renderização para entender o pipeline
- Confira Decisões Técnicas para justificativas