igx-grid のグリッド領域に対してマウスを上下左右の端まで近づけると、その方向へ自動的にスクロールできるようにする方法を紹介します。この動作は、水平方向のスクロールを担うheaderContainerと垂直方向のスクロールを担うverticalScrollContainer(いずれもIgxGridForOfDirective)が持つscrollNext() / scrollPrev()メソッドを、マウス位置に応じて一定間隔で呼び出すことで実現します。

igx-grid の設定

後述するheaderContainer / verticalScrollContainerにアクセスできるように、テンプレート側で#gridというテンプレート参照変数を付与しておきます。

<igx-grid #grid ... width="900px" height="500px">
  ...
</igx-grid>

コンポーネント側では、@ViewChildIgxGridComponentのインスタンスを取得します。

import { IGX_GRID_DIRECTIVES, IgxGridComponent } from '@infragistics/igniteui-angular/grids/grid';

@ViewChild('grid', { read: IgxGridComponent, static: true })
public grid: IgxGridComponent;

scrollNext() / scrollPrev() の呼び出し

グリッドの描画完了後、内部のdiv要素(.igx-grid__tbody-content)に対してmousemovemouseleaveイベントを登録します。mousemoveではマウスが端に近づいたかどうかを判定し、mouseleaveでは自動スクロールを停止します。

ngAfterViewInit(): void {
  const tbody = this.grid.nativeElement.querySelector('.igx-grid__tbody-content') as HTMLElement | null;
  if (!tbody) {
    return;
  }
  this.removeMouseMoveListener = this.renderer.listen(tbody, 'mousemove', (event: MouseEvent) =>
    this.onTbodyMouseMove(tbody, event),
  );
  this.removeMouseLeaveListener = this.renderer.listen(tbody, 'mouseleave', () => this.stopEdgeScrolling());
}

マウス座標がグリッドの端(既定では20px以内)に入っている間は方向('prev' / 'next')を判定し、一定間隔(既定では150ms)ごとに水平方向はheaderContainer.scrollNext() / headerContainer.scrollPrev()、垂直方向はverticalScrollContainer.scrollNext() / verticalScrollContainer.scrollPrev()を呼び出すことで自動スクロールを実行します。マウスが端から離れるとsetIntervalを停止し、スクロールを止めます。

private onTbodyMouseMove(tbody: HTMLElement, event: MouseEvent): void {
  const rect = tbody.getBoundingClientRect();
  this.setHorizontalScrolling(this.getEdgeDirection(event.clientX, rect.left, rect.right));
  this.setVerticalScrolling(this.getEdgeDirection(event.clientY, rect.top, rect.bottom));
}

private getEdgeDirection(position: number, start: number, end: number): 'prev' | 'next' | null {
  if (position <= start + EDGE_SCROLL_THRESHOLD_PX) {
    return 'prev';
  }
  if (position >= end - EDGE_SCROLL_THRESHOLD_PX) {
    return 'next';
  }
  return null;
}

private setHorizontalScrolling(direction: 'prev' | 'next' | null): void {
  if (direction === this.horizontalScrollDirection) {
    return;
  }
  if (this.horizontalScrollTimer) {
    clearInterval(this.horizontalScrollTimer);
    this.horizontalScrollTimer = null;
  }
  this.horizontalScrollDirection = direction;
  if (direction) {
    this.horizontalScrollTimer = setInterval(
      () =>
        direction === 'next'
          ? this.grid.headerContainer.scrollNext()
          : this.grid.headerContainer.scrollPrev(),
      EDGE_SCROLL_INTERVAL_MS,
    );
  }
}

private setVerticalScrolling(direction: 'prev' | 'next' | null): void {
  if (direction === this.verticalScrollDirection) {
    return;
  }
  if (this.verticalScrollTimer) {
    clearInterval(this.verticalScrollTimer);
    this.verticalScrollTimer = null;
  }
  this.verticalScrollDirection = direction;
  if (direction) {
    this.verticalScrollTimer = setInterval(
      () =>
        direction === 'next'
          ? this.grid.verticalScrollContainer.scrollNext()
          : this.grid.verticalScrollContainer.scrollPrev(),
      EDGE_SCROLL_INTERVAL_MS,
    );
  }
}

実行結果

実装が完了すると、グリッド内でマウスを移動させた際に、上下左右の端に近づくと自動的にその方向へスクロールされるようになります。マウスが端から離れると、スクロールは停止します。

Tagged:

製品について

Ignite UI for Angular