You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LightningChart JS微秒/纳秒数据展示及刻度、Tooltip格式化问题

问题分析与解决方案

核心问题根源

  1. Date.parse的精度限制:JavaScript原生Date对象仅支持毫秒级精度,解析带微秒/纳秒的时间戳时,会自动截断小数部分,导致数据精度丢失,同时错误的时间戳会引发X轴刻度显示异常(如441186.59.59.108这类格式错误)。
  2. 默认时间刻度策略不支持高精度格式:LightningChart JS的默认Time刻度策略仅显示到毫秒,无法适配微秒/纳秒级的时间显示需求。

解决方案步骤

1. 实现高精度时间戳解析函数

替换Date.parse,手动解析时间字符串以保留微秒/纳秒精度,将时间转换为带小数的毫秒数值(适配linear-highPrecision轴的高精度特性)。

// 解析微秒/纳秒级时间戳,返回带小数的毫秒数值
parseHighPrecisionTimestamp(timestamp: string): number {
  const [datePart, fractionalPart] = timestamp.split('.');
  const baseMs = Date.parse(datePart);
  if (!fractionalPart) return baseMs;

  const fractionalLength = fractionalPart.length;
  let fractionalMs = 0;
  if (fractionalLength === 6) {
    // 微秒转毫秒:x / 1000
    fractionalMs = parseFloat(`0.${fractionalPart}`) * 1000;
  } else if (fractionalLength === 9) {
    // 纳秒转毫秒:x / 1000000
    fractionalMs = parseFloat(`0.${fractionalPart}`) * 1000;
  }
  return baseMs + fractionalMs;
}

2. 自定义X轴刻度与AutoCursor格式

修改图表初始化代码,自定义X轴刻度标签和AutoCursor tooltip的显示格式,分别适配微秒/纳秒数据。

createChartInstance() {
  const container = this.el.nativeElement.querySelector("#chart-container");
  const lc = lightningChart({
    license: this.LIGHTNING_CHART_LICENSE_KEY,
    licenseInformation: {
      appTitle: "LightningChart JS Trial",
      company: "LightningChart Ltd."
    },
  })
  this.chart = lc.ChartXY({ 
    container, 
    theme: Themes.light, 
    defaultAxisX: { type: 'linear-highPrecision' }, 
    animationsEnabled: false 
  });
  this.chart.setTitle('FDR Chart');
  
  // 自定义AutoCursor的tooltip格式
  this.chart.setAutoCursor((cursor) => {
    cursor.setResultTableAutoTextStyle(true)
          .setTickMarkerXVisible(false)
          .setTickMarkerYAutoTextStyle(true)
          .setResultTableFormatter((builder, series, x, y, axisX, axisY) => {
            const date = new Date(Math.floor(x));
            const fractionalPart = x - Math.floor(x);
            // 基础时间格式:HH:mm:ss
            let timeStr = date.toLocaleTimeString('en-GB', { 
              hour: '2-digit', minute: '2-digit', second: '2-digit' 
            });
            // 根据通道类型判断显示微秒还是纳秒(需匹配你的通道命名规则)
            const isNanoChannel = series.getName().includes('纳秒');
            if (isNanoChannel) {
              const nanoseconds = Math.round(fractionalPart * 1e6);
              timeStr += `.${nanoseconds.toString().padStart(9, '0')}`;
            } else {
              const microseconds = Math.round(fractionalPart * 1000);
              timeStr += `.${microseconds.toString().padStart(6, '0')}`;
            }
            builder.addRow('时间', timeStr);
            builder.addRow(axisY.getTitle(), y.toFixed(2));
          });
  });
  
  this.chart.getDefaultAxisY().dispose();
  const axisX = this.chart.getDefaultAxisX();
  
  // 自定义X轴刻度标签格式
  axisX.setTickStrategy(AxisTickStrategies.Time, (tickStrategy) => {
    return tickStrategy
      .setDateOrigin((timestamp) => new Date(Math.floor(timestamp)))
      .setLabelFormatter((timestamp) => {
        const date = new Date(Math.floor(timestamp));
        const fractionalPart = timestamp - Math.floor(timestamp);
        let timeStr = date.toLocaleTimeString('en-GB', { 
          hour: '2-digit', minute: '2-digit', second: '2-digit' 
        });
        // 根据小数部分判断精度级别
        if (fractionalPart > 0.000001) {
          const microseconds = Math.round(fractionalPart * 1000);
          timeStr += `.${microseconds.toString().padStart(6, '0')}`;
        } else if (fractionalPart > 0) {
          const nanoseconds = Math.round(fractionalPart * 1e6);
          timeStr += `.${nanoseconds.toString().padStart(9, '0')}`;
        }
        return timeStr;
      });
  })
  .setScrollStrategy(AxisScrollStrategies.progressive)
  // 初始化轴范围时使用高精度解析
  .setDefaultInterval({ 
    start: this.parseHighPrecisionTimestamp('2020-04-30T23:49:58.5'), 
    end: this.parseHighPrecisionTimestamp('2020-04-30T23:49:59.49998'), 
    stopAxisAfter: false 
  });

  this.chart.setMouseInteractions(true);
  this.chart.setMouseInteractionRectangleFit(false);
  this.chart.onSeriesBackgroundMouseDoubleClick(() => {
    this.chart.forEachAxis((axis) => axis.fit());
  });
}

3. 修改WebSocket数据处理逻辑

替换Date.parse为自定义解析函数,并使用批量添加数据优化性能(适配10M级纳秒数据量)。

addSeriesToChart(e: any, channelName: string, groupType: string) {
  if (e.target.checked) {
    let axisY = this.chart.addAxisY({ iStack: this.lineSeriesCount })
      .setTitle(channelName)
      .setMargins(15, 15);
    axisY.setMouseInteractions({ pan: true, zoom: false });
    const series = this.chart.addLineSeries({ axisY, dataPattern: { pattern: 'ProgressiveX' } })
      .setName(channelName);

    const subject = webSocket<ChartDataPoint[]>(`ws://192.168.11.145:8002/GetChartDataV3?channel=${channelName}&fileId=${this.fileId}&groupType=${groupType}`);
    subject.subscribe({
      next: (msg: any) => {
        let coordinates = msg.Coordinates;
        this.websocketRunCount += 1;
        if (this.websocketRunCount == 1) {
          const startX = this.parseHighPrecisionTimestamp(coordinates[0].X);
          const endX = this.parseHighPrecisionTimestamp(coordinates[coordinates.length - 1].X);
          const axisX = this.chart.getDefaultAxisX();
          axisX.setInterval({ start: startX, end: endX, stopAxisAfter: false });
        }

        // 批量添加数据,大幅提升大数据量下的性能
        const points = coordinates.map((point: any) => ({
          x: this.parseHighPrecisionTimestamp(point.X),
          y: point.Y
        }));
        series.add(points);
      },
      error: err => console.log(err),
      complete: () => console.log('WebSocket connection closed')
    });

    this.seriesList[channelName] = {
      series: series,
      axisY: axisY,
      subject: subject
    };

    this.lineSeriesCount += 1;
  } else {
    this.lineSeriesCount -= 1;
    this.seriesList[channelName].series.dispose();
    this.seriesList[channelName].axisY.dispose();
    this.seriesList[channelName].subject.unsubscribe();
    delete this.seriesList[channelName];
  }
}

关键优化点说明

  • 精度保留:通过自定义解析函数将微秒/纳秒转换为毫秒的小数部分,完全适配linear-highPrecision轴的高精度特性。
  • 格式控制:针对微秒/纳秒通道分别设置显示格式,确保刻度和tooltip显示符合需求的HH:mm:ss.ffffff或HH:mm:ss.fffffffff格式。
  • 性能优化:使用批量数据添加替代逐个添加,针对10M级纳秒数据大幅降低渲染开销,符合LightningChart JS的大数据处理最佳实践。

内容的提问来源于stack exchange,提问作者Saud Binsaeed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 16:24:51