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

如何从QuestDB取数并实现带无限滚动的DevExpress缩放滚动图表

解决QuestDB数据获取与DevExtreme无限滚动图表实现问题

一、先解决QuestDB数据获取卡点

核心请求逻辑

QuestDB的REST API支持通过SQL查询获取数据,针对trips表的需求,需要构造查询pickup_datetime和trip_distance的请求,同时处理时间格式和数据转换:

// 封装数据请求函数,支持按时间范围分页
async function fetchTripData(startTime, endTime) {
  // 构造带时间过滤的SQL,限制每页1000条数据
  const sql = `
    SELECT pickup_datetime, trip_distance 
    FROM trips 
    WHERE pickup_datetime BETWEEN '${startTime.toISOString()}' AND '${endTime.toISOString()}'
    ORDER BY pickup_datetime ASC
    LIMIT 1000
  `;
  // 编码SQL避免URL格式问题,指定JSON格式返回
  const encodedQuery = encodeURIComponent(sql);
  const response = await fetch(`https://demo.questdb.io/exec?query=${encodedQuery}&format=json`);
  
  if (!response.ok) throw new Error('数据请求失败');
  const rawData = await response.json();
  
  // 转换为DevExtreme图表兼容的格式:时间转Date对象,键值对结构
  return rawData.dataset.map(row => ({
    pickupDatetime: new Date(row[0]),
    tripDistance: row[1]
  }));
}

取数常见问题排查

  • 跨域错误:demo.questdb.io已开启CORS支持,若仍报错,可在CodeSandbox项目中启用内置代理(项目设置→Server→Add Proxy)
  • SQL语法错误:确保时间字符串为ISO格式(toISOString()自动生成),避免特殊字符未编码
  • 无返回数据:trips表的时间范围集中在2013年左右,初始化时不要用过早的时间范围

二、整合到DevExtreme图表模板

基于DevExtreme的ZoomingAndScrolling React模板,修改数据源和状态管理:

import React, { useState, useEffect, useRef } from 'react';
import { Chart, ArgumentAxis, ValueAxis, LineSeries, Tooltip } from 'devextreme-react/chart';

export default function App() {
  const [chartData, setChartData] = useState([]);
  const lastLoadedEndTime = useRef(null);

  // 初始化加载第一页数据
  useEffect(() => {
    async function loadInitialData() {
      // 先获取表中最早的记录时间
      const minTimeRes = await fetch(`https://demo.questdb.io/exec?query=${encodeURIComponent('SELECT MIN(pickup_datetime) FROM trips')}&format=json`);
      const minTimeRaw = await minTimeRes.json();
      const minTime = new Date(minTimeRaw.dataset[0][0]);
      // 第一页取7天的数据(可根据数据密度调整)
      const endTime = new Date(minTime.getTime() + 7 * 24 * 60 * 60 * 1000);
      
      const initialData = await fetchTripData(minTime, endTime);
      setChartData(initialData);
      lastLoadedEndTime.current = endTime;
    }
    loadInitialData();
  }, []);

  // 加载下一页数据
  async function loadNextPage() {
    if (!lastLoadedEndTime.current) return;
    const startTime = lastLoadedEndTime.current;
    const endTime = new Date(startTime.getTime() + 7 * 24 * 60 * 60 * 1000);
    
    const newData = await fetchTripData(startTime, endTime);
    if (newData.length === 0) return; // 无更多数据
    
    setChartData(prev => [...prev, ...newData]);
    lastLoadedEndTime.current = endTime;
  }

  // 监听滚动事件,触发无限加载
  const handleScroll = (e) => {
    const scrollElement = e.component.getScrollableElement();
    const { scrollLeft, clientWidth, scrollWidth } = scrollElement;
    // 滚动到右侧90%位置时加载下一页
    if (scrollLeft + clientWidth >= scrollWidth * 0.9) {
      loadNextPage();
    }
  };

  return (
    <Chart
      dataSource={chartData}
      onScroll={handleScroll}
      zoomMode="x"
      scrollingMode="infinite"
      height={600}
    >
      <ArgumentAxis argumentType="datetime" title={{ text: '取车时间' }} />
      <ValueAxis title={{ text: '行程距离' }} />
      <LineSeries argumentField="pickupDatetime" valueField="tripDistance" name="行程距离" />
      <Tooltip enabled={true} />
    </Chart>
  );
}

// 数据请求函数
async function fetchTripData(startTime, endTime) {
  const sql = `
    SELECT pickup_datetime, trip_distance 
    FROM trips 
    WHERE pickup_datetime BETWEEN '${startTime.toISOString()}' AND '${endTime.toISOString()}'
    ORDER BY pickup_datetime ASC
    LIMIT 1000
  `;
  const encodedQuery = encodeURIComponent(sql);
  const response = await fetch(`https://demo.questdb.io/exec?query=${encodedQuery}&format=json`);
  
  if (!response.ok) throw new Error('数据请求失败');
  const rawData = await response.json();
  
  return rawData.dataset.map(row => ({
    pickupDatetime: new Date(row[0]),
    tripDistance: row[1]
  }));
}

三、验证无限滚动功能

  1. 初始化时图表加载第一页7天的行程数据
  2. 向右滚动图表到接近边缘时,自动加载下7天的数据
  3. 重复滚动可持续加载,直到trips表数据耗尽

关键配置说明

  • scrollingMode="infinite":开启DevExtreme图表的无限滚动模式
  • onScroll事件:监听滚动位置,触发分页加载
  • 时间范围分页:通过BETWEEN条件和LIMIT实现高效的数据分段获取,避免一次性加载全部数据导致性能问题

内容的提问来源于stack exchange,提问作者Omkar Lolge

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 03:25:19