virtual scroll for scrolling grids

This commit is contained in:
Timo 2020-11-30 18:12:09 +02:00
parent 9aea9c3635
commit 40f519afd6
6 changed files with 109 additions and 1 deletions

View File

@ -84,6 +84,8 @@ import { CircleButtonComponent } from './components/buttons/circle-button/circle
import { ChevronButtonComponent } from './components/buttons/chevron-button/chevron-button.component';
import { DictionaryListingScreenComponent } from './screens/admin/dictionary-listing-screen/dictionary-listing-screen.component';
import { CustomTooltipModule } from './common/red-tooltip/custom-tooltip.module';
import { ScrollingModule } from '@angular/cdk/scrolling';
import { VirtualScrollComponent } from './utils/virtual-scroll/virtual-scroll.component';
export function HttpLoaderFactory(httpClient: HttpClient) {
return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json');
@ -135,7 +137,8 @@ export function HttpLoaderFactory(httpClient: HttpClient) {
UserButtonComponent,
CircleButtonComponent,
ChevronButtonComponent,
DictionaryListingScreenComponent
DictionaryListingScreenComponent,
VirtualScrollComponent
],
imports: [
BrowserModule,

View File

@ -152,6 +152,8 @@
</div>
</div>
</div>
<redaction-virtual-scroll></redaction-virtual-scroll>
</div>
</div>

View File

@ -0,0 +1,59 @@
export function syncScroll(elements: HTMLElement[]) {
// clearing existing listeners
for (const element of elements) {
element.removeEventListener('scroll', (<any>element).scrollSync);
}
// setting-up the new listeners
for (let idx = 0; idx < elements.length; ) {
const loopElement: any = elements[idx++];
loopElement.eX = loopElement.eY = 0;
((el) => {
el['addEventListener'](
'scroll',
(el.scrollSync = () => {
let scrollX = el['scrollLeft'];
let scrollY = el['scrollTop'];
const xRate = scrollX / (el['scrollWidth'] - el['clientWidth']);
const yRate = scrollY / (el['scrollHeight'] - el['clientHeight']);
const updateX = scrollX !== el.eX;
const updateY = scrollY !== el.eY;
let otherEl,
i = 0;
el.eX = scrollX;
el.eY = scrollY;
for (; i < elements.length; ) {
otherEl = elements[i++];
if (otherEl !== el) {
if (
updateX &&
Math.round(
otherEl['scrollLeft'] - (scrollX = otherEl.eX = Math.round(xRate * (otherEl['scrollWidth'] - otherEl['clientWidth'])))
)
) {
otherEl['scrollLeft'] = scrollX;
}
if (
updateY &&
Math.round(
otherEl['scrollTop'] - (scrollY = otherEl.eY = Math.round(yRate * (otherEl['scrollHeight'] - otherEl['clientHeight'])))
)
) {
otherEl['scrollTop'] = scrollY;
}
}
}
}),
0
);
})(loopElement);
}
}

View File

@ -0,0 +1,3 @@
<div class="virtual-scroll" #scrollElement>
<div class="virtual" [style.height]="height + 'px'"></div>
</div>

View File

@ -0,0 +1,15 @@
.virtual-scroll {
// TODO fix this - pass information as input or such
display: none;
position: fixed;
width: 10px;
right: 480px;
bottom: 0;
z-index: 100;
top: 191px;
overflow: auto;
.virtual {
height: 2000px;
}
}

View File

@ -0,0 +1,26 @@
import { AfterViewInit, Component, ElementRef, Input, ViewChild } from '@angular/core';
import { syncScroll } from '../sync-scroll';
@Component({
selector: 'redaction-virtual-scroll',
templateUrl: './virtual-scroll.component.html',
styleUrls: ['./virtual-scroll.component.scss']
})
export class VirtualScrollComponent implements AfterViewInit {
@Input() targetQuerySelector = '.red-content';
@ViewChild('scrollElement')
scrollElement: ElementRef;
content: HTMLElement;
height: number;
factor: number;
constructor() {}
ngAfterViewInit(): void {
this.content = document.querySelector(this.targetQuerySelector);
this.factor = this.content.clientHeight / this.scrollElement.nativeElement.clientHeight;
this.height = Math.round(this.content.scrollHeight / this.factor);
console.log(this.factor, this.height);
syncScroll([this.scrollElement.nativeElement, this.content]);
}
}