Solução de problemas
Verificações e correções copiáveis para falhas comuns na integração de gráficos.
Estes modos de falha são gerados a partir do mesmo conhecimento versionado usado por diagnose_chart. Comece pelo sintoma que mais se aproxima da aplicação, aplique a verificação de diagnóstico e mantenha apenas as correções que preservem o ciclo de vida documentado e o contrato de propriedade de typed-array.
Se nenhuma entrada corresponder, inspecione o símbolo relevante na referência de API aninhada ou peça ao servidor MCP local para executar um diagnóstico focado. Reduza a reprodução para renderMode: "main" e animated: false apenas como passo de diagnóstico, não como configuração automática de produção.
Índice de sintomas
A área de desenho (canvas) está vazia ou tem tamanho zero
Aplica-se a: line, stock.
Sintoma. O gráfico inicializa sem erro visível, mas não aparece qualquer plot ou o canvas tem altura medida de zero pixels.
Causa provável. O elemento anfitrião do canvas não tinha uma altura concreta quando o renderer foi inicializado.
Verifique
- Inspecione o anfitrião e o canvas com getBoundingClientRect(); tanto a largura como a altura devem ser maiores que zero.
- Verifique se um antepassado em flex ou grid fez colapsar a linha do gráfico.
Solução
- Atribua ao elemento anfitrião uma altura concreta ou min-height antes de executar initialize().
- Faça com que o canvas preencha esse anfitrião em vez de depender das dimensões intrínsecas do canvas.
Forneça ao gráfico um elemento anfitrião mensurável
.chart-host {
position: relative;
width: 100%;
height: clamp(20rem, 55vh, 34rem);
}
.chart-host > canvas {
display: block;
width: 100%;
height: 100%;
}Os dados são definidos antes de o gráfico estar pronto
Aplica-se a: line, stock.
Sintoma: o primeiro conjunto de dados não aparece, enquanto uma atualização posterior ou remount funciona.
Causa provável. Uma integração vanilla chamou um método de dados antes de initialize() concluir, ou inicializou o mesmo canvas mais do que uma vez.
Verifique
- Verifique que initialize() é aguardado exactamente uma vez por cada instância de chart.
- Se um framework controlar a vista, prefira o adaptador oficial para que a ordem de mount e unmount seja tratada por si.
- A prontidão do adaptador dispara uma vez após a inicialização e o primeiro lote bem‑sucedido de props de dados, aparência e janela de visualização; não é uma notificação de frame pintado.
Corrigir
- Aguarde initialize() antes de chamar setData() ou setMultiSeriesData().
- Destrua o gráfico antigo antes de reutilizar o seu canvas para outra instância.
- Para uma instalação de prop de adaptador rejeitada, forneça props corrigidas para tentar novamente sem remontar. Os dados instalados com êxito não são transferidos novamente. Uma falha terminal do renderer exige um remount.
Use o ciclo de vida vanilla por ordem
const chart = new LineChart(canvas, { renderMode: "auto" });
await chart.initialize();
chart.setData(data);
// Call this when the view is permanently removed.
export function disposeChart() {
chart.destroy();
}A renderização por worker recai para o thread principal
Aplica-se a: line, stock.
Sintoma. Um gráfico funciona, mas recorre à renderização no thread principal, ou a construção do worker falha apenas em produção.
Causa provável. O worker, OffscreenCanvas, transferControlToOffscreen, ou a Política de Segurança de Conteúdo (CSP) aplicada impediram o arranque do renderer em worker.
Verifique
- Use setStatsCallback() temporariamente e inspeccione as estatísticas.renderMode.
- Verifique a consola do navegador e a diretiva Content Security Policy worker-src.
Corrigir
- Mantenha renderMode definido como auto, salvo se for necessário forçar um modo para diagnóstico.
- Permita a URL do worker gerada pela aplicação em worker-src e mantenha operacional a alternativa no thread principal.
Confirme o renderer resolvido
chart.setStatsCallback((stats) => {
console.info("Sixtyfold renderer:", stats.renderMode);
chart.setStatsCallback(null);
});Arrays tipados ficam destacáveis após setData
Aplica-se a: line, stock.
Sintoma. Um array tipado de origem tem byteLength 0 ou já não pode ser lido depois de os dados terem sido atribuídos a um gráfico com suporte de worker.
Causa provável. Os dados em massa do gráfico são transferidos para o renderer em modo worker; as ArrayBuffers transferidas saem do chamador.
Verificar
- Inspecione as byteLength imediatamente antes e depois da chamada de dados em massa.
- Confirme se outro subsistema realmente precisa de reter uma cópia legível.
Corrigir
- Considere a chamada de dados em massa como uma transferência de propriedade.
- Clone apenas as colunas que outro subsistema precise reter; evite duplicar por omissão conjuntos de dados com milhões de valores.
Manter uma cópia intencional na aplicação
const retainedX = sourceX.slice();
const retainedY = sourceY.slice();
chart.setData({
x: sourceX,
y: sourceY,
length: sourceX.length,
});
// retainedX and retainedY remain readable.O eixo temporal está comprimido, vazio ou muito no futuro
Aplica‑se a: line, stock.
Sintoma. Os marcadores mostram datas implausíveis, o intervalo visível colapsa ou a deslocação (panning) comporta‑se de forma imprevisível.
Causa provável. A coluna X usou segundos ou strings em vez de epoch milliseconds finitos e ordenados, ou as observações não estavam ordenadas.
Verifique
- Inspecione os carimbos de data/hora primeiro e último e converta-os com new Date(value).
- Verifique se cada carimbo de data/hora é finito. O streaming de ações exige carimbos estritamente crescentes dentro de cada lote e após cada candle previamente enfileirado ou anexado.
- Distingua streaming de StockChart estático. setData(): dados estáticos podem ser monotonamente ascendentes ou descendentes e podem conter carimbos iguais; o gráfico normaliza a sua ordem.
Correção
- Converta segundos epoch em milissegundos antes de criar o Float64Array.
- Analise datas ISO uma vez durante a ingestão e ordene observações completas antes de as dividir em colunas.
- Desduplique observações do fluxo de ações antes de anexar. Os métodos de anexação por streaming não atualizam uma candle existente com o mesmo carimbo temporal.
Normalizar carimbos de data/hora durante a ingestão
const timestamp = Float64Array.from(rows, (row) => {
const value = Date.parse(row.recordedAt);
if (!Number.isFinite(value)) throw new TypeError("Invalid recordedAt value");
return value;
});As colunas têm comprimentos diferentes ou valores numéricos inválidos
Aplica‑se a: line, stock.
Sintoma. O gráfico rejeita um conjunto de dados, trunca‑se inesperadamente ou renderiza valores com carimbos de data/hora incorretos.
Causa provável. Dados em colunas foram criados a partir de filtros ou mapeamentos separados, pelo que as colunas de tempo e de valor já não descrevem as mesmas observações.
Verifique
- Compare o comprimento de cada coluna antes de chamar o gráfico.
- Valide a conversão numérica antes de transferir os buffers.
- O Stock addCandles requer seis colunas de tamanho igual; addCandleBatches valida a lista completa de blocos antes de qualquer transferência. Carimbos de tempo inválidos ou comprimentos de coluna inválidos deixam os buffers do chamador anexados.
Corrigir
- Filtrar e ordenar primeiro as observações de origem completas, depois dividi‑las em colunas tipadas alinhadas.
- Use NaN explícito apenas para uma lacuna de séries de linhas documentada; os valores OHLCV devem permanecer candles válidos.
Rejeitar colunas desalinhadas antes da transferência
const lengths = [timestamp.length, open.length, high.length, low.length, close.length, volume.length];
if (!lengths.every((length) => length === lengths[0])) {
throw new RangeError(`OHLCV columns are misaligned: ${lengths.join(", ")}`);
}SSR ou hidratação acede a APIs de gráficos exclusivas do navegador
Aplica-se a: line, stock.
Sintoma: uma renderização no servidor lança um erro porque window, document, Worker ou HTMLCanvasElement não estão disponíveis, ou a hidratação produz uma árvore diferente.
Causa provável. O gráfico interativo no browser foi construído durante a avaliação no servidor em vez de após o cliente montar-se.
Verificar
- Localize a construção do gráfico no âmbito do módulo ou dentro de um componente de servidor.
- Separe a geração de imagens no servidor através de @sixtyfold/ssr da interação no browser.
Correção
- Use o adaptador oficial do framework dentro de um componente propriedade do cliente.
- Renderize um host estável durante SSR e inicialize o gráfico interativo apenas após a montagem.
Mantenha um gráfico Next.js atrás da fronteira do cliente
"use client";
import type { MultiSeriesData, TimeSeriesData } from "@sixtyfold/core";
import { SixtyfoldLineChart } from "@sixtyfold/react/line";
type LineData = TimeSeriesData | MultiSeriesData;
export function ChartPanel({ data }: { data: LineData }) {
return <SixtyfoldLineChart data={data} options={{ renderMode: "auto" }} />;
}Restos de workers ou de memória após navegação
Aplica-se a: line, stock.
Sintoma. A memória aumenta depois de abrir repetidamente a vista, ou gráficos antigos continuam a renderizar após a navegação.
Causa provável. Um gráfico vanilla ou um worker de dados temporário não foi destruído quando a vista proprietária foi removida.
Verificar
- Registe uma captura de heap do browser antes e depois de vários ciclos de montagem/desmontagem.
- Procure instâncias de gráfico retidas, workers, observers ou arrays de origem decodificados.
Corrigir
- Chame destroy() exatamente uma vez para cada instância de gráfico vanilla.
- Encerre workers temporários de fetch/decode após a sua transferência final; os adaptadores oficiais de frameworks destroem automaticamente os workers de gráfico.
Libertar workers de gráfico e de ingestão
return () => {
dataWorker?.terminate();
chart.destroy();
};A interação está lenta ou perde fotogramas
Aplica-se a: line, stock.
Sintoma. O zoom, deslocamento, decodificação inicial ou atualizações de streaming bloqueiam visivelmente ou não atingem a taxa de frames pretendida.
Causa provável. O thread principal está a decodificar ou a remodelar dados em excesso, o gráfico recorreu ao renderizador de reserva, ou a carga de trabalho visível inclui mais passagens de desenho do que o dispositivo de destino consegue suportar.
Verifique
- Inspecione estatísticas.renderMode, frameTime, trabalho visível e prontidão de LOD durante a sequência de interação real.
- Faça o perfil do fetch, decodificação, conversão, transferência e renderização separadamente.
Corrigir
- Use renderMode auto, prepare arrays tipados colunares num worker de dados dedicado, transfira uma vez e termine esse worker de ingestão.
- Faça benchmarks nos navegadores representativos, DPRs, contagens de séries e gestos; 60 FPS é um objetivo de design e não uma garantia independente do dispositivo.
Meça o caminho de renderização ativo
chart.setStatsCallback((stats) => {
console.table({
mode: stats.renderMode,
fps: stats.fps,
frameTime: stats.frameTime,
ready: stats.lodReady,
});
}, { intervalMs: 250 });O detalhe da linha muda abruptamente depois da estabilização do zoom
Aplica-se a: line.
Sintoma: o viewport anima suavemente, mas a textura da linha volta a mudar no final do gesto.
Causa provável: a densidade de apresentação ou o rebase da grelha é demasiado agressivo para a carga de trabalho, ou o código da aplicação substitui os dados ou a aparência após a conclusão da animação.
Verificar
- Reproduza a mesma sequência de viewport enquanto observa a densidade de apresentação, o delta da grelha e as visitas às consultas.
- Verifique chamadas do lado da aplicação setData(), setAppearance() ou restauro de viewport após a animação estabilizar.
Correção
- Comece em modo adaptativo, densidade 0.75, rebaseRatio 1.25 e quantizationStep 0.25.
- Use setLODOptions() para ajustar um coeficiente de cada vez; use densidade 0.25 para preenchimentos de intervalo dispendiosos ou trabalho multi-série excepcionalmente grande.
Ajuste a apresentação sem recriar o gráfico
chart.setLODOptions({
mode: "adaptive",
density: 0.75,
rebaseRatio: 1.25,
quantizationStep: 0.25,
});Uma linha liga pontos através de observações em falta
Aplica-se a: line.
Sintoma: Uma linha atravessa visualmente um intervalo onde não existe nenhuma medição.
Causa provável. Observações em falta foram removidas ou substituídas por zero em vez de serem representadas como uma lacuna alinhada NaN.
Verificar
- Confirme que a coluna X partilhada inclui o intervalo em falta quando é necessária uma quebra visível.
- Verifique se o processo de ingestão converteu valores null em zero.
Correção
- Manter posições X alinhadas e codificar valores de linha em falta como Number.NaN.
- Não sintetize velas OHLCV nem conecte encerramentos de mercado; o comportamento temporal de ações é determinado por velas observadas.
Representar uma lacuna real em séries de linhas
const data = {
x: new Float64Array([0, 1, 2, 3]),
y: new Float64Array([12, Number.NaN, Number.NaN, 18]),
length: 4,
};