igx-grid のグリッド領域に対してマウスを上下左右の端まで近づけると、その方向へ自動的にスクロールできるようにする方法を紹介します。この動作は、水平方向のスクロールを担うheaderContainerと垂直方向のスクロールを担うverticalScrollContainer(いずれもIgxGridForOfDirective)が持つscrollNext() / scrollPrev()メソッドを、マウス位置に応じて一定間隔で呼び出すことで実現します。
igx-grid の設定
後述するheaderContainer / verticalScrollContainerにアクセスできるように、テンプレート側で#gridというテンプレート参照変数を付与しておきます。
<igx-grid #grid ... width="900px" height="500px"> ... </igx-grid>
コンポーネント側では、@ViewChildでIgxGridComponentのインスタンスを取得します。
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)に対してmousemoveとmouseleaveイベントを登録します。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,
);
}
}
実行結果
実装が完了すると、グリッド内でマウスを移動させた際に、上下左右の端に近づくと自動的にその方向へスクロールされるようになります。マウスが端から離れると、スクロールは停止します。