故障排除

可复制的检查项与修复方法,用于常见图表集成故障。

这些故障模式基于与 diagnose_chart 使用相同版本知识生成。请从与您的应用最接近的症状开始,执行诊断检查,仅采用不破坏已记录生命周期和类型数组所有权约定的修复措施。

如果没有条目匹配,请在嵌套 API 参考中检查相关符号,或请求本地MCP 服务器运行针对性诊断。仅将重现简化为renderMode: "main"和animated: false作为诊断步骤,而不是作为自动投入生产的配置。

症状索引

画布为空或尺寸为零

适用于:line、stock。

症状。 图表初始化时没有可见错误,但未显示绘图或画布高度为零像素。

可能原因。 在渲染器初始化时,画布宿主没有具体高度。

检查

  • 使用 getBoundingClientRect() 检查宿主和画布;宽度和高度都必须大于零。
  • 检查是否有 flex 或 grid 的祖先折叠了图表行。

修复

  • 在调用 initialize() 之前为宿主元素设置一个具体的 height 或 min-height。
  • 让画布填满该宿主元素,而不是依赖画布的固有尺寸。

为图表提供一个可测量的宿主容器

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

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

数据在图表就绪前被设置

适用于:line,stock。

症状。 第一个数据集未显示,但稍后的更新或重新挂载会生效。

可能原因。一个原生集成在 initialize() 完成之前调用了数据方法,或对同一画布多次调用了 initialize()。

检查

  • 确认对每个图表实例恰好等待一次 initialize()。
  • 如果某个框架管理视图,请优先使用官方适配器,以便为您处理挂载和卸载的顺序。
  • 适配器就绪事件在初始化后以及第一批成功的 data、appearance 和 viewport 属性处理完成时触发一次;它并不是已绘制帧的通知。

修复

  • 在调用 setData() 或 setMultiSeriesData() 之前,请先等待 initialize()。
  • 在将旧图表的画布重用于另一个实例之前,请先销毁旧图表。
  • 对于被拒绝的 adapter prop 安装,请提供已修正的 props 以在不重新挂载的情况下重试。已成功安装的数据不会再次传输。终端渲染器失败则需要重新挂载。

按顺序使用原生生命周期

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

Worker 渲染退回到主线程

适用对象:line、stock。

症状。 图表工作正常,但退回到主线程渲染,或仅在生产环境中 Worker 构造失败。

可能原因。 Worker、OffscreenCanvas、transferControlToOffscreen或已部署的内容安全策略阻止了 Worker 渲染器启动。

检查

  • 临时使用 setStatsCallback() 并检查统计信息。renderMode。
  • 检查浏览器控制台和 worker-src 内容安全策略(CSP)指令。

修复

  • 除非为诊断必须强制某种模式,否则请保持 renderMode 设置为 auto。
  • 在 worker-src 中允许应用生成的 Worker URL,并保持主线程回退可用。

确认已解析的渲染器

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

调用 setData 后,类型化数组会变为 detached。

适用于:line,stock。

症状。 将数据传递给由 Worker 支持的图表后,源类型化数组具有 byteLength 0 或无法再读取。

可能原因。 在 Worker 模式下,大量图表数据会被传输到渲染器;被传输的 ArrayBuffers 会从调用方中移除。

检查

  • 在批量数据调用的前后立即检查 byteLength。
  • 确认是否有其他子系统确实需要保留可读副本。

修复

  • 将批量数据调用视为所有权转移。
  • 仅克隆另一个子系统必须保留的列;默认避免复制包含数百万值的数据集。

保留应用程序的有意副本

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

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

// retainedX and retainedY remain readable.

时间轴被压缩、为空或位于遥远的未来

适用于:line、stock。

症状。 刻度显示不合理的日期、可见范围塌缩或平移行为不可预测。

可能原因。 X 列使用了秒或字符串而不是有序的有限纪元毫秒,或观测值未排序。

检查

  • 检查第一个和最后一个时间戳,并使用 new Date(value) 将其转换。
  • 验证每个时间戳是否为有限值。股票流数据要求在每个批次内以及在此前入队或追加的每根蜡烛之后,时间戳严格递增。
  • 区分流式数据与静态 StockChart.setData():静态数据可以单调递增或递减,也可以包含相同的时间戳;图表会规范化其顺序。

修复

  • 在创建 Float64Array 之前将纪元秒转换为毫秒。
  • 在摄取过程中仅解析一次 ISO 日期,并在将完整观测拆分为列之前对其进行排序。
  • 在追加之前对股票流观测去重。流式追加方法不会对具有相同时戳的已有烛形进行更新。

在摄取期间规范化时间戳

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

列具有不同长度或无效的数值

适用于:line,stock。

症状。 图表拒绝数据集、意外截断或在错误的时间戳下渲染数值。

可能原因。列式数据是由不同的筛选或映射生成的,因此时间列和值列不再描述相同的观测。

检查

  • 在调用图表之前比较每一列的长度。
  • 在传输缓冲区之前验证数值转换。
  • Stock addCandles 需要六个等宽列;addCandleBatches 在任何传输之前验证完整的块列表。无效的时间戳或列长度会导致调用者缓冲区仍被附着。

修复

  • 先对完整源观测进行过滤和排序,然后将其拆分为对齐的类型化列。
  • 仅在文档化的折线系列间断中使用显式 NaN;OHLCV 值必须保持为有效的蜡烛。

在传输前拒绝对齐错误的列

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

服务器端渲染或水合过程中访问仅浏览器可用的图表 API

适用于:line、stock。

症状。 服务器渲染因 window、document、Worker 或 HTMLCanvasElement 无法使用而抛出异常,或水合导致不同的节点树。

可能原因。 交互式浏览器图表在服务器评估期间构建,而非客户端挂载后构建。

检查

  • 查找在模块作用域或服务器组件内部的图表构建。
  • 通过 @sixtyfold/ssr 将服务器端图像生成与浏览器交互分离。

修复

  • 在客户端拥有的组件内使用官方框架适配器。
  • 在服务端渲染期间呈现一个稳定的宿主,并仅在挂载后初始化交互式图表。

在客户端边界后保留一个 Next.js 图表。

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

导航后仍有 Worker 或内存残留

适用于:line,stock。

症状。 反复打开视图后内存增长,或导航后旧图表仍继续渲染。

可能原因。 当其所属视图被移除时,未销毁原生图表或临时数据 Worker。

检查

  • 在多次挂载/卸载周期之前和之后记录浏览器堆快照。
  • 查找仍被保留的图表实例、Worker、观察者或已解码的源数组。

修复

  • 对每个原生图表实例仅调用一次 destroy()。
  • 在临时 fetch/decode Worker 完成最后一次传输后终止它们;官方框架适配器会自动销毁图表 Worker。

释放图表和摄取(ingestion)Worker

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

交互响应迟缓或出现帧丢失

适用于:line、stock。

症状。 缩放、平移、初始解码或流式更新出现明显阻塞或未达到目标帧率。

可能原因。 主线程正在解码或重塑过多数据、图表回退到备用渲染器,或可见工作负载包含超过目标设备可维持的绘制通过次数。

检查

  • 检查统计信息。renderMode、frameTime、可见工作项与交互序列中的细节层级就绪状态。
  • 分别分析获取、解码、转换、传输与渲染的性能。

修复

  • 使用 renderMode auto,在专用数据 Worker 中准备列式类型数组,进行一次传输,然后终止该摄取 Worker。
  • 针对具有代表性的浏览器、设备像素比(DPR)、系列数量和手势进行基准测试;60 FPS 是设计目标,而不是与设备无关的保证。

测量活动渲染路径

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

缩放稳定后线条细节突变

适用于:line。

症状。 视口在手势结束时平滑动画,但线条纹理在手势结束时发生变化。

可能原因。 展示密度或网格重基准化对工作负载过于激进,或应用代码在动画结束后替换了数据或外观。

检查

  • 在观察展示密度、网格增量和查询访问的同时重放相同的视口序列。
  • 在动画停止后检查应用端是否有 setData()、setAppearance() 或视口恢复的调用。

修复

  • 从自适应模式开始,密度设为 0.75,rebaseRatio 为 1.25,quantizationStep 为 0.25。
  • 使用 setLODOptions() 逐个调节系数;对于开销大的范围填充或异常大的多系列工作,使用密度 0.25。

在不重新创建图表的情况下调整展示

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

折线跨越缺失的观测点连接

适用于:line。

症状。 折线在没有测量值的时间区间上视觉上穿过。

可能原因。缺失的观测值被移除或用零替换,而不是以对齐的 NaN 间隙表示。

检查

  • 确认共享的 X 列在需要可见中断时包含该缺失区间。
  • 检查摄取过程是否将 null 值转换为零。

修复

  • 保持 X 位置对齐,并将缺失的折线值编码为 Number.NaN。
  • 不要合成 OHLCV K 线或连接市场停盘;股票时间尺度行为由观测到的 K 线驱动。

表示真实折线序列的断档

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