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

如何在Chart.js中实现Y轴固定的水平滚动图表?

如何在Chart.js中实现Y轴固定的水平滚动图表?

嗨,我看了你遇到的问题——想让Chart.js的Y轴在水平滚动时固定住,跟着教程尝试但Y轴画布始终没显示标签,对吧?咱们一步步来解决这个问题,先分析你现有代码的问题,再给你一个更可靠的实现方案。

问题出在哪儿?

你参考的教程用的是旧版Chart.js的API,而新版Chart.js已经更新了内部属性的结构,比如你代码里的this.scale.xScalePaddingLeft、this.scale.endPoint这些属性在新版里已经不存在了,导致你复制画布的逻辑根本找不到正确的Y轴区域,自然看不到标签。

另外,直接复制主画布的部分区域到第二个画布的方式,很容易因为图表布局变化、版本更新而失效,不如单独渲染Y轴更稳定。

修正后的实现方案

我们可以采用“主图表隐藏Y轴 + 独立画布渲染Y轴”的方式,这样Y轴会固定在左侧,主图表区域可以水平滚动,而且逻辑更清晰:

1. HTML结构

保持你的基础结构,调整一下主画布的宽度设置,让它更适配滚动容器:

<div class="chartWrapper">
    <div class="chartAreaWrapper">
        <canvas id="myChart" height="300"></canvas>
    </div>
    <canvas id="myChartAxis" height="300" width="100"></canvas>
</div>

2. CSS样式

优化布局,给Y轴画布留出固定位置,同时让主图表区域可水平滚动:

.chartWrapper {
  position: relative;
  max-width: 100%;
}
.chartAreaWrapper {
  width: 800px; /* 设置你需要的可滚动宽度 */
  overflow-x: auto;
  padding-left: 100px; /* 给Y轴画布留出空间 */
}
#myChartAxis {
  position: absolute;
  left: 0;
  top: 0;
  width: 100px;
  height: 300px;
  pointer-events: none; /* 避免干扰主图表交互 */
}
#myChart {
  display: block;
  width: 100%;
}

3. JavaScript逻辑

修改主图表配置,隐藏原生Y轴,然后单独在第二个画布上渲染Y轴内容:

var ctx = document.getElementById("myChart").getContext("2d");
const ctx2 = document.getElementById('myChartAxis');

const chartData = {
    labels: ["Person 1", "Person 2"],
  datasets: [{
        data: [
            [new Date('2024-11-18T08:00:00'), new Date('2024-11-18T10:30:00')],
            [new Date('2024-11-18T07:00:00'), new Date('2024-11-18T09:45:00')]
        ],
        backgroundColor: "#8A2BE2"
    },
    {
        data: [
            [new Date('2024-11-18T11:00:00'), new Date('2024-11-18T15:00:00')],
            [new Date('2024-11-18T10:15:00'), new Date('2024-11-18T13:00:00')]
        ],
        backgroundColor: "#007F5C"
    },
    {
        data: [
            [new Date('2024-11-18T14:00:00'), new Date('2024-11-18T15:00:00')],
            [new Date('2024-11-18T15:15:00'), new Date('2024-11-18T17:00:00')]
        ],
        backgroundColor: "#8A2BE2"
    },
    {
        data: [
            [new Date('2024-11-18T15:15:00'), new Date('2024-11-18T17:00:00')],
            null
        ],
        backgroundColor: "#007F5C"
    },
    ],
}

// 主图表:隐藏原生Y轴,只显示数据区域
var myChart = new Chart(ctx, {
    type: 'bar',
    data: chartData,
    options: {
        maintainAspectRatio: false,
        responsive: true,
        indexAxis: 'y',
        plugins: {
            legend: { display: false },
            title: { display: false },
            tooltip: { enabled: false }
        },
        scales: {
            y: {
                display: false, // 隐藏主图表的Y轴
                stacked: true,
            },
            x: {
                grid: { display: false },
                type: 'time',
                time: { unit: 'minute' },
                ticks: { stepSize: 15 },
                min: new Date('2024-11-18T06:00:00'),
                max: new Date('2024-11-18T17:00:00'),
            }
        },
        animation: {
            onComplete: function() {
                renderYAxis(); // 动画完成后渲染Y轴
            }
        }
    }
});

// 单独渲染Y轴到第二个画布
function renderYAxis() {
    // 先清空Y轴画布
    ctx2.clearRect(0, 0, ctx2.canvas.width, ctx2.canvas.height);

    // 获取主图表的Y轴配置和尺寸
    const yAxis = myChart.scales.y;
    const chartHeight = myChart.height;
    const axisWidth = ctx2.canvas.width;

    // 绘制Y轴标签和刻度
    yAxis.ticks.forEach((tick, index) => {
        const yPos = yAxis.getPixelForTick(index);
        // 绘制标签文本
        ctx2.fillStyle = '#666';
        ctx2.font = '12px Arial';
        ctx2.textAlign = 'right';
        ctx2.textBaseline = 'middle';
        ctx2.fillText(tick.label, axisWidth - 10, yPos);

        // 绘制刻度线(可选,根据需求调整)
        ctx2.strokeStyle = '#ddd';
        ctx2.beginPath();
        ctx2.moveTo(axisWidth - 5, yPos);
        ctx2.lineTo(axisWidth, yPos);
        ctx2.stroke();
    });

    // 绘制Y轴轴线(可选)
    ctx2.strokeStyle = '#ddd';
    ctx2.beginPath();
    ctx2.moveTo(axisWidth - 1, 0);
    ctx2.lineTo(axisWidth - 1, chartHeight);
    ctx2.stroke();
}

// 窗口 resize 时重新渲染Y轴,保证布局一致
window.addEventListener('resize', renderYAxis);

额外说明

Chart.js目前没有内置的“固定Y轴”选项,所以双画布的方案是目前最常用的实现方式。上面的代码相比你原来的方案,优势在于:

  • 不依赖旧版API,适配新版Chart.js
  • 单独渲染Y轴,逻辑更可控,不容易因为布局变化失效
  • 可以自定义Y轴的样式(比如字体、颜色、刻度线)

备注:内容来源于stack exchange,提问作者DaBeau96

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 10:35:27