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

React中Chart.js实现带X轴硬边界的可滑动视口问题

React + Chart.js 实现固定宽度X轴的可平移视口问题

问题描述

需要在React中用Chart.js实现固定宽度(如8小时)的可左右平移图表视口,并为X轴设置硬最小/最大边界:红色框为用户可见区域,左侧“1500”是视口左边界,框外“0400”是数据的最右边界。当前图表始终显示全量数据,无法实现平移功能。

现有代码

import moment from "moment";
import Chart from "chart.js/auto";
import { Bar } from "react-chartjs-2";
import zoomPlugin from 'chartjs-plugin-zoom';
import annotationPlugin from 'chartjs-plugin-annotation';
import 'chartjs-adapter-moment';

Chart.register(annotationPlugin,zoomPlugin);

const r = document.querySelector(':root');
const rs = getComputedStyle(r);

const data = {
    datasets: [
      {
        type: 'bar',
        data: [], //value - set through programming
        order: 1
      },
      {
        type: 'bar',
        data: [],
        order: 1
      },
      {
        type: 'bar',
        data: [],
        order: 1
      },
      {
        type: 'bar',
        data: [],
        order: 1
      },
      {
        data: [],
        type: 'line',
        order: 0,
        steppedLine: true,
        stepped: 'before'
       },
       {
        label: "Current Time", //needed for legend
        type: 'line'
       }
    ]
  };

const options = {
    plugins: {
        legend: {
          position: 'bottom',
        },
        annotation:{
            annotations: [{
                type: 'line',
                borderColor: rs.getPropertyValue('--CURRENT_TIMELINE'),
                borderWidth: 2,
                mode: 'vertical',
                xMin: moment().subtract(30, "m").valueOf(),
                xMax: moment().subtract(30, "m").valueOf()
            }]
        }
    },
    zoom: {
        pan: {
            enabled: true
        }
    },
    elements: {
        point:{
            radius: 0
        }
    },
    scales: {
        x: {
            stacked: true,
            display: true,
            offset: false,
            title: {
                display: false,
                text: 'Time'
            },
            type: 'time',
            time: {
                unit: 'hour',
                displayFormats: {
                  'minute': 'HHmm',
                  'hour': 'HHmm',
                }
            },
            ticks: {
                // forces step size to be 50 units
                stepSize: 1
              }
        },
        y: {
            stacked: true,
            min: 0,
            title: {
                display: true,
                text: 'My title'
            }
        }
    }
};

class myChart extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            data: data,
            options: options
        }
    }

    render() { 
        return (
            <div className="chart" id="chart">
                <Bar data={this.state.data} options={this.state.options}/>
            </div>
        );
    }
    }

export default myChart;

解决方案

1. 配置X轴初始可见范围与硬边界

在scales.x中添加初始的min和max,固定视口宽度(比如8小时);同时设置数据的硬边界,限制平移范围:

scales: {
    x: {
        // ...原有配置
        type: 'time',
        // 初始视口:显示最近8小时的数据
        min: moment().subtract(8, 'hour').valueOf(),
        max: moment().valueOf(),
        // 数据硬边界(根据实际数据起止时间调整)
        suggestedMin: moment('0400', 'HHmm').valueOf(),
        suggestedMax: moment('1500', 'HHmm').valueOf(),
        // ...其他配置
    }
}

2. 完善Zoom插件的平移配置

在zoom.pan中限制仅X轴平移,并设置平移的硬边界:

zoom: {
    pan: {
        enabled: true,
        // 仅允许X轴平移
        mode: 'x',
        // 设置平移的硬边界,与X轴的suggestedMin/suggestedMax对应
        limits: {
            x: {
                min: moment('0400', 'HHmm').valueOf(),
                max: moment('1500', 'HHmm').valueOf()
            }
        }
    }
}

3. 动态数据适配(可选)

如果数据是动态加载的,需在更新数据时同步修改X轴的min/max和平移limits,确保边界与实际数据匹配。

修改后的完整关键配置示例

const options = {
    plugins: {
        legend: {
          position: 'bottom',
        },
        annotation:{
            annotations: [{
                type: 'line',
                borderColor: rs.getPropertyValue('--CURRENT_TIMELINE'),
                borderWidth: 2,
                mode: 'vertical',
                xMin: moment().subtract(30, "m").valueOf(),
                xMax: moment().subtract(30, "m").valueOf()
            }]
        }
    },
    zoom: {
        pan: {
            enabled: true,
            mode: 'x',
            limits: {
                x: {
                    min: moment('0400', 'HHmm').valueOf(),
                    max: moment('1500', 'HHmm').valueOf()
                }
            }
        }
    },
    elements: {
        point:{
            radius: 0
        }
    },
    scales: {
        x: {
            stacked: true,
            display: true,
            offset: false,
            title: {
                display: false,
                text: 'Time'
            },
            type: 'time',
            time: {
                unit: 'hour',
                displayFormats: {
                  'minute': 'HHmm',
                  'hour': 'HHmm',
                }
            },
            ticks: {
                stepSize: 1
            },
            // 初始固定8小时视口
            min: moment().subtract(8, 'hour').valueOf(),
            max: moment().valueOf(),
            // 数据硬边界
            suggestedMin: moment('0400', 'HHmm').valueOf(),
            suggestedMax: moment('1500', 'HHmm').valueOf()
        },
        y: {
            stacked: true,
            min: 0,
            title: {
                display: true,
                text: 'My title'
            }
        }
    }
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 23:43:30