Dépannage

Vérifications et corrections copiables pour les erreurs courantes d’intégration de graphiques.

Ces modes d’échec sont générés à partir des mêmes connaissances versionnées utilisées par diagnose_chart. Commencez par le symptôme qui correspond le mieux à l’application, appliquez la vérification diagnostique et ne conservez que les corrections qui préservent le cycle de vie documenté et le contrat de propriété des tableaux typés.

Si aucune entrée ne correspond, inspectez le symbole pertinent dans la référence API imbriquée ou demandez au serveur MCP local d’exécuter un diagnostic ciblé. Réduisez la reproduction à renderMode: "main" et animated: false uniquement comme étape de diagnostic, pas comme configuration de production automatique.

Index des symptômes

Le canvas est vide ou a une taille nulle

S’applique à : line, stock.

Symptôme. Le graphique s'initialise sans erreur visible, mais aucune courbe n'apparaît ou le canevas mesure zéro pixel de haut.

Cause probable. L'élément hôte du canevas n'avait pas de hauteur définie lorsque le moteur de rendu s'est initialisé.

Vérifier

  • Inspectez l'hôte et le canevas avec getBoundingClientRect(); la largeur et la hauteur doivent toutes deux être supérieures à zéro.
  • Vérifiez si un ancêtre en flex ou grid a effondré la ligne du graphique.

Correction

  • Donnez à l’hôte une hauteur concrète ou une min-height avant que initialize() ne s’exécute.
  • Laissez le canvas remplir cet hôte au lieu de compter sur les dimensions intrinsèques du canvas.

Donnez au graphique un conteneur de taille mesurable

.chart-host {
  position: relative;
  width: 100%;
  height: clamp(20rem, 55vh, 34rem);
}

.chart-host > canvas {
  display: block;
  width: 100%;
  height: 100%;
}

Les données sont définies avant que le graphique soit prêt

S’applique à : line, stock.

Symptôme : le premier jeu de données n’apparaît pas, alors qu’une mise à jour ultérieure ou un remontage fonctionne.

Cause probable : une intégration vanilla a appelé une méthode de données avant la fin de initialize(), ou a initialisé le même canvas plus d’une fois.

Vérifier

  • Vérifiez que initialize() est attendu exactement une fois pour chaque instance de graphique.
  • Si un framework gère la vue, préférez l’adaptateur officiel afin que l’ordre de montage et de démontage soit géré pour vous.
  • La disponibilité de l’adaptateur se déclenche une fois après l’initialisation et le premier lot réussi de données, d’apparence et de props de viewport ; ce n’est pas une notification de trame peinte.

Corriger

  • Attendez initialize() avant d’appeler setData() ou setMultiSeriesData().
  • Détruisez l’ancien graphique avant de réutiliser son canvas pour une autre instance.
  • Pour une installation de prop d’adaptateur rejetée, fournissez des props corrigées pour réessayer sans remonter le composant. Les données installées avec succès ne sont pas transférées de nouveau. Une défaillance terminale du renderer exige un remontage.

Utilisez le cycle de vie vanilla dans l’ordre

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();
}

Le rendu par worker revient au thread principal

S’applique à : line, stock.

Symptôme. Un graphique fonctionne mais bascule vers un rendu sur le thread principal, ou la construction du worker échoue uniquement en production.

Cause probable. Le worker, OffscreenCanvas, transferControlToOffscreen, ou la Content Security Policy déployée ont empêché le renderer du worker de démarrer.

Vérifier

  • Utilisez temporairement setStatsCallback() et inspectez les statistiques.renderMode.
  • Vérifiez la console du navigateur et la directive Content Security Policy « worker-src ».

Corriger

  • Laissez renderMode sur auto, sauf si forcer un mode est nécessaire pour le diagnostic.
  • Autorisez l’URL du worker générée par l’application dans « worker-src » et conservez le repli sur le thread principal opérationnel.

Confirmez le moteur de rendu résolu

chart.setStatsCallback((stats) => {
  console.info("Sixtyfold renderer:", stats.renderMode);
  chart.setStatsCallback(null);
});

Les tableaux typés deviennent détachés après setData

S’applique à : line, stock.

Symptôme : un tableau typé source a byteLength 0 ou n’est plus lisible après que des données ont été affectées à un graphique utilisant un worker.

Cause probable. Les données de graphique en masse sont transférées au moteur en mode worker ; les objets transférés ArrayBuffers quittent l'appelant.

Vérifiez

  • Inspectez byteLength immédiatement avant et après l'appel de transfert des données en masse.
  • Confirmez si un autre sous-système a réellement besoin de conserver une copie lisible.

Correction

  • Considérez l'appel de données en masse comme un transfert de propriété.
  • Clonez uniquement les colonnes qu'un autre sous-système doit conserver ; évitez par défaut de dupliquer des jeux de données de plusieurs millions de valeurs.

Conservez une copie applicative intentionnelle

const retainedX = sourceX.slice();
const retainedY = sourceY.slice();

chart.setData({
  x: sourceX,
  y: sourceY,
  length: sourceX.length,
});

// retainedX and retainedY remain readable.

L’axe temporel est compressé, vide ou situé très loin dans le futur

S’applique à : line, stock.

Symptôme. Les graduations affichent des dates incohérentes, la plage visible se réduit à néant ou le panoramique se comporte de manière imprévisible.

Cause probable. La colonne X utilisait des secondes ou des chaînes au lieu de millisecondes d’époque finies et ordonnées, ou les observations n’étaient pas triées.

Vérifier

  • Inspectez les premiers et derniers horodatages et convertissez-les avec new Date(value).
  • Vérifiez que chaque horodatage est fini. Le streaming de données boursières exige des horodatages strictement croissants au sein de chaque lot et après chaque bougie précédemment mise en file ou ajoutée.
  • Distinguez le streaming des données statiques StockChart.setData(): les données statiques peuvent être monotone croissantes ou décroissantes et contenir des horodatages égaux ; le chart normalise leur ordre.

Correction

  • Convertissez les secondes epoch en millisecondes avant de créer la Float64Array.
  • Analysez les dates ISO une seule fois lors de l'ingestion et triez les observations complètes avant de les répartir en colonnes.
  • Dédupliquez les observations du flux boursier avant d'ajouter. Les méthodes d'ajout en streaming ne mettent pas à jour une bougie existante ayant le même horodatage.

Normaliser les horodatages lors de l’ingestion

const timestamp = Float64Array.from(rows, (row) => {
  const value = Date.parse(row.recordedAt);
  if (!Number.isFinite(value)) throw new TypeError("Invalid recordedAt value");
  return value;
});

Les colonnes ont des longueurs différentes ou des valeurs numériques invalides

S’applique à : line, stock.

Symptôme : le graphique rejette un jeu de données, se tronque de façon inattendue ou affiche des valeurs sous des horodatages incorrects.

Cause probable. Les données en colonnes ont été créées à partir de filtres ou de mappages distincts, de sorte que les colonnes temporelle et des valeurs ne décrivent plus les mêmes observations.

Vérifiez

  • Comparez la longueur de chaque colonne avant d'appeler le graphique.
  • Validez la conversion numérique avant de transférer les buffers.
  • Le stock addCandles nécessite six colonnes de taille égale ; addCandleBatches valide la liste complète de chunks avant tout transfert. Des horodatages invalides ou des longueurs de colonne incorrectes laissent les tampons de l'appelant attachés.

Correction

  • Filtrer et trier d’abord les observations sources complètes, puis les diviser en colonnes typées alignées.
  • N’utiliser NaN explicite que pour un trou de série de lignes documenté ; les valeurs OHLCV doivent rester des chandelles valides.

Rejeter les colonnes mal alignées avant le transfert

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(", ")}`);
}

Le rendu côté serveur ou l’hydratation accède à des API de chart réservées au navigateur

S’applique à : line, stock.

Symptôme : un rendu serveur lève une exception parce que window, document, Worker ou HTMLCanvasElement est indisponible, ou l’hydratation produit un arbre différent.

Cause probable. Le graphique interactif dans le navigateur a été construit pendant l'évaluation côté serveur au lieu d'être créé après le montage côté client.

Vérifier

  • Recherchez la construction du graphique au niveau du module ou à l'intérieur d'un composant serveur.
  • Séparez la génération d'images côté serveur via @sixtyfold/ssr de l'interaction dans le navigateur.

Correction

  • Utilisez l’adaptateur officiel du framework à l’intérieur d’un composant appartenant au client.
  • Rendez un hôte stable pendant le SSR et initialisez le graphique interactif uniquement après le montage.

Conservez un graphique Next.js derrière la frontière client

"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" }} />;
}

Des workers ou de la mémoire persistent après la navigation

S'applique à : line, stock.

Symptôme. La mémoire augmente après l'ouverture répétée de la vue, ou d'anciens graphiques continuent de se rendre après la navigation.

Cause probable. Un chart vanilla ou un worker temporaire de données n'a pas été détruit lorsque sa vue propriétaire a été supprimée.

Vérifier

  • Enregistrez un snapshot du tas du navigateur avant et après plusieurs cycles de montage/démontage.
  • Recherchez des instances de chart retenues, des workers, des observers ou des tableaux de sources décodées.

Corriger

  • Appelez destroy() exactement une fois pour chaque instance de graphique vanilla.
  • Terminez les workers temporaires de fetch/decode après leur dernier transfert ; les adaptateurs officiels de framework détruisent automatiquement les workers de graphique.

Libérez les workers de graphique et d’ingestion

return () => {
  dataWorker?.terminate();
  chart.destroy();
};

L’interaction est lente ou des images sont perdues

S'applique à : line, stock.

Symptôme : le zoom, le panoramique, le décodage initial ou les mises à jour en streaming bloquent visiblement ou n'atteignent pas la fréquence d'images cible.

Cause probable : le thread principal décode ou redimensionne trop de données, le graphique est tombé sur le renderer de secours, ou la charge visible inclut plus de passes de rendu que le dispositif cible ne peut soutenir.

Vérifiez

  • Inspectez les statistiques.renderMode, frameTime, travail visible et disponibilité du LOD pendant la séquence d'interaction réelle.
  • Profilage séparé du fetch, du décodage, de la conversion, du transfert et du rendu.

Corriger

  • Utilisez renderMode auto, préparez des tableaux typés columnaires dans un data worker dédié, transférez une fois, puis terminez ce worker d'ingestion.
  • Effectuez des benchmarks sur des navigateurs représentatifs, des DPR, des nombres de séries et des gestes ; 60 FPS est un objectif de conception plutôt qu’une garantie indépendante du dispositif.

Mesurer le chemin de rendu actif

chart.setStatsCallback((stats) => {
  console.table({
    mode: stats.renderMode,
    fps: stats.fps,
    frameTime: stats.frameTime,
    ready: stats.lodReady,
  });
}, { intervalMs: 250 });

Le niveau de détail des lignes change brusquement une fois le zoom stabilisé

S’applique à : line.

Symptôme. Le viewport s'anime en douceur mais la texture de la ligne change à nouveau à la fin du geste.

Cause probable. La densité de présentation ou le rebasing de la grille est trop agressif pour la charge de travail, ou le code de l'application remplace les données ou l'apparence après la fin de l'animation.

Vérifier

  • Rejouez la même séquence de viewport en observant la densité de présentation, le delta de grille et les visites de requêtes.
  • Vérifiez la présence d’un appel côté application à setData(), setAppearance() ou d’une restauration de la fenêtre d’affichage une fois l’animation terminée.

Correction

  • Commencez en mode adaptatif, densité 0,75, rebaseRatio 1,25 et quantizationStep 0,25.
  • Utilisez setLODOptions() pour ajuster un coefficient à la fois ; utilisez une densité de 0,25 pour des remplissages de plage coûteux ou des travaux multi-séries exceptionnellement volumineux.

Ajuster la présentation sans recréer le graphique

chart.setLODOptions({
  mode: "adaptive",
  density: 0.75,
  rebaseRatio: 1.25,
  quantizationStep: 0.25,
});

Une ligne relie des observations manquantes

S’applique à : line.

Symptôme : une ligne traverse visuellement un intervalle sans mesure.

Cause probable : des observations manquantes ont été supprimées ou remplacées par zéro au lieu d’être représentées comme un trou aligné NaN.

Vérifier

  • Confirmez que la colonne X partagée inclut l’intervalle manquant lorsqu’une coupure visible est requise.
  • Vérifiez si l’ingestion a converti les valeurs nulles en zéro.

Correction

  • Conserver l'alignement des positions X et encoder les valeurs de ligne manquantes en tant que Number.NaN.
  • Ne synthétisez pas de chandelles OHLCV ni ne reliez les fermetures de marché ; le comportement à l'échelle temporelle des actions est déterminé par les chandelles observées.

Représenter un vrai intervalle dans une série de lignes

const data = {
  x: new Float64Array([0, 1, 2, 3]),
  y: new Float64Array([12, Number.NaN, Number.NaN, 18]),
  length: 4,
};