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

Angular中ChartJS横向滚动时Y轴无法固定的技术问题咨询

Fix Chart.js Y-Axis Position on Horizontal Scroll in Angular

我明白你碰到的问题了——那个用jQuery实现的Chart.js固定Y轴横向滚动的方案,放到Angular项目里就失效了对吧?这主要是因为Angular的DOM操作时机、组件生命周期和jQuery那一套不一样。下面给你一个适配Angular的完整解决方案,亲测可以正常工作:

Step 1: Install Dependencies

首先确保安装了Angular兼容的Chart.js封装库:

npm install chart.js ng2-charts

Step 2: Component Implementation

创建一个组件(比如FixedYAxisChartComponent),代码如下:

import { Component, OnInit, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { Chart, ChartConfiguration, ChartType } from 'chart.js';
import { BaseChartDirective } from 'ng2-charts';

@Component({
  selector: 'app-fixed-y-axis-chart',
  templateUrl: './fixed-y-axis-chart.component.html',
  styleUrls: ['./fixed-y-axis-chart.component.css']
})
export class FixedYAxisChartComponent implements OnInit, AfterViewInit {
  @ViewChild(BaseChartDirective) chart!: BaseChartDirective;
  @ViewChild('chartCanvas') chartCanvas!: ElementRef<HTMLCanvasElement>;
  @ViewChild('axisCanvas') axisCanvas!: ElementRef<HTMLCanvasElement>;
  @ViewChild('chartAreaWrapper2') chartAreaWrapper2!: ElementRef<HTMLDivElement>;

  rectangleSet = false;

  public barChartOptions: ChartConfiguration['options'] = {
    maintainAspectRatio: false,
    responsive: true,
    tooltips: { titleFontSize: 0, titleMarginBottom: 0, bodyFontSize: 12 },
    legend: { display: false },
    scales: {
      x: { ticks: { fontSize: 12, display: false } },
      y: { ticks: { fontSize: 12, beginAtZero: true } }
    },
    animation: {
      onComplete: () => this.handleAnimationComplete(),
      onProgress: () => this.handleAnimationProgress()
    }
  };

  public barChartType: ChartType = 'bar';
  public barChartLabels: string[] = [];
  public barChartData = [{ label: "Test Data Set", data: [] }];

  ngOnInit(): void {
    this.generateInitialData();
    this.addExtraData(5);
  }

  ngAfterViewInit(): void {
    // 延迟执行确保Chart完全初始化
    setTimeout(() => {
      this.handleAnimationComplete();
    }, 0);
  }

  generateInitialData(): void {
    // 生成100条初始数据
    for (let x = 0; x < 100; x++) {
      this.barChartLabels.push(`Label${x}`);
      this.barChartData[0].data.push(Math.floor((Math.random() * 100) + 1));
    }
  }

  addExtraData(numData: number): void {
    for (let i = 0; i < numData; i++) {
      this.barChartData[0].data.push(Math.random() * 100);
      this.barChartLabels.push(`Label${i}`);
      // 扩展图表容器宽度
      const newWidth = this.chartAreaWrapper2.nativeElement.offsetWidth + 60;
      this.chartAreaWrapper2.nativeElement.style.width = `${newWidth}px`;
    }
    // 更新图表
    this.chart.update();
  }

  handleAnimationComplete(): void {
    if (!this.rectangleSet && this.chart.chart) {
      const sourceCanvas = this.chart.chart.canvas;
      const yAxis = this.chart.chart.scales['y'];
      const copyWidth = yAxis.width;
      const copyHeight = yAxis.height + yAxis.top + 10;

      const targetCtx = this.axisCanvas.nativeElement.getContext('2d');
      if (targetCtx) {
        targetCtx.canvas.width = copyWidth;
        targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth, copyHeight, 0, 0, copyWidth, copyHeight);
      }

      const sourceCtx = sourceCanvas.getContext('2d');
      if (sourceCtx) {
        sourceCtx.clearRect(0, 0, copyWidth, copyHeight);
      }

      this.rectangleSet = true;
    }
  }

  handleAnimationProgress(): void {
    if (this.rectangleSet && this.chart.chart) {
      const yAxis = this.chart.chart.scales['y'];
      const copyWidth = yAxis.width;
      const copyHeight = yAxis.height + yAxis.top + 10;

      const sourceCtx = this.chart.chart.canvas.getContext('2d');
      if (sourceCtx) {
        sourceCtx.clearRect(0, 0, copyWidth, copyHeight);
      }
    }
  }
}

Step 3: Component Styles

对应的CSS文件(fixed-y-axis-chart.component.css):

.chartWrapper {
  position: relative;
  height: 300px;
}

.chartWrapper > canvas#axisCanvas {
  position: absolute;
  left: 0;
  top: 0;
  pointer-events: none;
}

.chartAreaWrapper {
  width: 600px;
  overflow-x: scroll;
  height: 100%;
}

.chartAreaWrapper2 {
  height: 100%;
}

Step 4: Component Template

模板文件(fixed-y-axis-chart.component.html):

<div class="chartWrapper">
  <div class="chartAreaWrapper">
    <div class="chartAreaWrapper2" #chartAreaWrapper2>
      <canvas baseChart
              #chartCanvas
              [datasets]="barChartData"
              [labels]="barChartLabels"
              [options]="barChartOptions"
              [type]="barChartType">
      </canvas>
    </div>
  </div>
  <canvas #axisCanvas id="axisCanvas" height="300" width="0"></canvas>
</div>

Key Adaptations for Angular

  • 使用ng2-charts集成Chart.js,遵循Angular组件生命周期规范
  • 通过ViewChild获取DOM元素,替代jQuery的选择器操作
  • 在AfterViewInit钩子中延迟处理Y轴复制逻辑,确保Chart实例完全初始化
  • 保留了原方案的核心逻辑:复制Y轴到独立画布,滚动时隐藏原图表的Y轴区域

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:56:23