removed perspective intersection observer

This commit is contained in:
Jan Prochazka 2022-07-31 15:28:04 +02:00
parent fe31cfb552
commit bf51f45934
6 changed files with 173 additions and 77 deletions

View File

@ -4,7 +4,7 @@ import { format } from 'path';
import { PerspectiveBindingGroup, PerspectiveCache } from './PerspectiveCache'; import { PerspectiveBindingGroup, PerspectiveCache } from './PerspectiveCache';
import { PerspectiveDataLoader } from './PerspectiveDataLoader'; import { PerspectiveDataLoader } from './PerspectiveDataLoader';
const PERSPECTIVE_PAGE_SIZE = 100; export const PERSPECTIVE_PAGE_SIZE = 10;
export interface PerspectiveDatabaseConfig { export interface PerspectiveDatabaseConfig {
conid: string; conid: string;

View File

@ -76,13 +76,14 @@ export class PerspectiveDisplayRow {
rowCellSkips: boolean[] = null; rowCellSkips: boolean[] = null;
rowJoinIds: number[] = []; rowJoinIds: number[] = [];
incompleteRowsIndicator: string[] = null; // incompleteRowsIndicator: string[] = null;
} }
export class PerspectiveDisplay { export class PerspectiveDisplay {
columns: PerspectiveDisplayColumn[] = []; columns: PerspectiveDisplayColumn[] = [];
rows: PerspectiveDisplayRow[] = []; rows: PerspectiveDisplayRow[] = [];
readonly columnLevelCount: number; readonly columnLevelCount: number;
loadIndicatorsCounts: { [uniqueName: string]: number } = {};
constructor(public root: PerspectiveTreeNode, rows: any[]) { constructor(public root: PerspectiveTreeNode, rows: any[]) {
// dbg('source rows', rows); // dbg('source rows', rows);
@ -92,7 +93,7 @@ export class PerspectiveDisplay {
} }
this.columnLevelCount = _max(this.columns.map(x => x.parentNodes.length)) + 1; this.columnLevelCount = _max(this.columns.map(x => x.parentNodes.length)) + 1;
const collectedRows = this.collectRows(rows, root.childNodes); const collectedRows = this.collectRows(rows, root.childNodes);
// dbg('collected rows', collectedRows); dbg('collected rows', collectedRows);
// console.log('COLLECTED', JSON.stringify(collectedRows, null, 2)); // console.log('COLLECTED', JSON.stringify(collectedRows, null, 2));
// this.mergeRows(collectedRows); // this.mergeRows(collectedRows);
this.mergeRows(collectedRows); this.mergeRows(collectedRows);
@ -212,16 +213,22 @@ export class PerspectiveDisplay {
} }
mergeRow(collectedRow: CollectedPerspectiveDisplayRow, rowIndex: number): number { mergeRow(collectedRow: CollectedPerspectiveDisplayRow, rowIndex: number): number {
if (collectedRow.incompleteRowsIndicator?.length > 0) {
for (const indicator of collectedRow.incompleteRowsIndicator) {
if (!this.loadIndicatorsCounts[indicator]) {
this.loadIndicatorsCounts[indicator] = rowIndex;
}
if (rowIndex < this.loadIndicatorsCounts[indicator]) {
this.loadIndicatorsCounts[indicator] = rowIndex;
}
}
return 0;
}
const mainRow = this.getRowAt(rowIndex); const mainRow = this.getRowAt(rowIndex);
for (let i = 0; i < collectedRow.columnIndexes.length; i++) { for (let i = 0; i < collectedRow.columnIndexes.length; i++) {
mainRow.rowData[collectedRow.columnIndexes[i]] = collectedRow.rowData[i]; mainRow.rowData[collectedRow.columnIndexes[i]] = collectedRow.rowData[i];
} }
if (collectedRow.incompleteRowsIndicator) {
mainRow.incompleteRowsIndicator = [
...(mainRow.incompleteRowsIndicator || []),
...collectedRow.incompleteRowsIndicator,
];
}
let rowCount = 1; let rowCount = 1;
for (const subrows of collectedRow.subRowCollections) { for (const subrows of collectedRow.subRowCollections) {

View File

@ -12,13 +12,17 @@ test('test flat view', () => {
const root = new PerspectiveTableNode(artistTable, chinookDbInfo, createPerspectiveConfig(), null, null, null, null); const root = new PerspectiveTableNode(artistTable, chinookDbInfo, createPerspectiveConfig(), null, null, null, null);
const display = new PerspectiveDisplay(root, artistDataFlat); const display = new PerspectiveDisplay(root, artistDataFlat);
console.log(display.rows); // console.log(display.loadIndicatorsCounts);
expect(display.rows.length).toEqual(5); // console.log(display.rows);
expect(display.rows.length).toEqual(4);
expect(display.rows[0]).toEqual( expect(display.rows[0]).toEqual(
expect.objectContaining({ expect.objectContaining({
rowData: ['AC/DC'], rowData: ['AC/DC'],
}) })
); );
expect(display.loadIndicatorsCounts).toEqual({
Artist: 4,
});
}); });
test('test one level nesting', () => { test('test one level nesting', () => {
@ -34,8 +38,9 @@ test('test one level nesting', () => {
); );
const display = new PerspectiveDisplay(root, artistDataAlbum); const display = new PerspectiveDisplay(root, artistDataAlbum);
console.log(display.rows); console.log(display.loadIndicatorsCounts);
expect(display.rows.length).toEqual(7); // console.log(display.rows);
expect(display.rows.length).toEqual(6);
expect(display.rows[0]).toEqual( expect(display.rows[0]).toEqual(
expect.objectContaining({ expect.objectContaining({
rowData: ['AC/DC', 'For Those About To Rock We Salute You'], rowData: ['AC/DC', 'For Those About To Rock We Salute You'],
@ -63,6 +68,11 @@ test('test one level nesting', () => {
rowSpans: [1, 1], rowSpans: [1, 1],
}) })
); );
expect(display.loadIndicatorsCounts).toEqual({
Artist: 6,
'Artist.Album': 6,
});
}); });
test('test two level nesting', () => { test('test two level nesting', () => {
@ -79,7 +89,7 @@ test('test two level nesting', () => {
const display = new PerspectiveDisplay(root, artistDataAlbumTrack); const display = new PerspectiveDisplay(root, artistDataAlbumTrack);
console.log(display.rows); console.log(display.rows);
expect(display.rows.length).toEqual(9); expect(display.rows.length).toEqual(8);
expect(display.rows[0]).toEqual( expect(display.rows[0]).toEqual(
expect.objectContaining({ expect.objectContaining({
rowData: ['AC/DC', 'For Those About To Rock We Salute You', 'For Those About To Rock (We Salute You)'], rowData: ['AC/DC', 'For Those About To Rock We Salute You', 'For Those About To Rock (We Salute You)'],

View File

@ -1,55 +1,56 @@
export default [ export default [
{ {
"ArtistId": 1, ArtistId: 1,
"Name": "AC/DC", Name: 'AC/DC',
"Album": [ Album: [
{ {
"Title": "For Those About To Rock We Salute You", Title: 'For Those About To Rock We Salute You',
"ArtistId": 1 ArtistId: 1,
}, },
{ {
"Title": "Let There Be Rock", Title: 'Let There Be Rock',
"ArtistId": 1 ArtistId: 1,
} },
] ],
}, },
{ {
"ArtistId": 2, ArtistId: 2,
"Name": "Accept", Name: 'Accept',
"Album": [ Album: [
{ {
"Title": "Balls to the Wall", Title: 'Balls to the Wall',
"ArtistId": 2 ArtistId: 2,
}, },
{ {
"Title": "Restless and Wild", Title: 'Restless and Wild',
"ArtistId": 2 ArtistId: 2,
} },
] ],
}, },
{ {
"ArtistId": 3, ArtistId: 3,
"Name": "Aerosmith", Name: 'Aerosmith',
"Album": [ Album: [
{ {
"Title": "Big Ones", Title: 'Big Ones',
"ArtistId": 3 ArtistId: 3,
} },
] ],
}, },
{ {
"ArtistId": 4, ArtistId: 4,
"Name": "Alanis Morissette", Name: 'Alanis Morissette',
"Album": [ Album: [
{ {
"Title": "Jagged Little Pill", Title: 'Jagged Little Pill',
"ArtistId": 4 ArtistId: 4,
} },
] {
}, incompleteRowsIndicator: ['Artist.Album'],
{ },
"incompleteRowsIndicator": [ ],
"Artist" },
] {
} incompleteRowsIndicator: ['Artist'],
] },
];

View File

@ -3,6 +3,7 @@
export let rootNode; export let rootNode;
export let onLoadNext; export let onLoadNext;
export let incompleteRowsIndicator;
let domObserved; let domObserved;
@ -30,4 +31,4 @@
}); });
</script> </script>
<div bind:this={domObserved}>... data to be loaded</div> <div bind:this={domObserved} on:click={onLoadNext}>... data to be loaded {incompleteRowsIndicator.join(',')}</div>

View File

@ -12,9 +12,9 @@
</script> </script>
<script lang="ts"> <script lang="ts">
import { PerspectiveDisplay, PerspectiveTreeNode } from 'dbgate-datalib'; import { PerspectiveDisplay, PerspectiveTreeNode, PERSPECTIVE_PAGE_SIZE } from 'dbgate-datalib';
import _, { values } from 'lodash'; import _, { values } from 'lodash';
import { onMount } from 'svelte'; import { onMount, tick } from 'svelte';
import resizeObserver from '../utility/resizeObserver'; import resizeObserver from '../utility/resizeObserver';
import PerspectiveIntersectionObserver from './PerspectiveIntersectionObserver.svelte'; import PerspectiveIntersectionObserver from './PerspectiveIntersectionObserver.svelte';
import debug from 'debug'; import debug from 'debug';
@ -40,6 +40,7 @@
let dataRows; let dataRows;
let domWrapper; let domWrapper;
let domTable;
let errorMessage; let errorMessage;
let isLoading = false; let isLoading = false;
@ -51,7 +52,7 @@
const loadProps = node.getNodeLoadProps(parentRows); const loadProps = node.getNodeLoadProps(parentRows);
let { rows, incomplete } = await node.dataProvider.loadData({ let { rows, incomplete } = await node.dataProvider.loadData({
...loadProps, ...loadProps,
topCount: counts[node.uniqueName] || 100, topCount: counts[node.uniqueName] || PERSPECTIVE_PAGE_SIZE,
}); });
// console.log('ROWS', rows, node.isRoot); // console.log('ROWS', rows, node.isRoot);
@ -111,7 +112,7 @@
try { try {
await loadLevelData(node, rows, counts); await loadLevelData(node, rows, counts);
dataRows = rows; dataRows = rows;
dbg('display rows', rows); dbg('data rows', rows);
errorMessage = null; errorMessage = null;
} catch (err) { } catch (err) {
console.error(err); console.error(err);
@ -142,6 +143,11 @@
$: loadData(root, $loadedCounts); $: loadData(root, $loadedCounts);
$: display = root && dataRows ? new PerspectiveDisplay(root, dataRows) : null; $: display = root && dataRows ? new PerspectiveDisplay(root, dataRows) : null;
$: {
display;
checkLoadAdditionalData();
}
function buildMenu() { function buildMenu() {
return [ return [
{ {
@ -152,16 +158,86 @@
}, },
]; ];
} }
function getLastVisibleRowIndex() {
var rows = domTable.querySelectorAll('tbody>tr');
const wrapBox = domWrapper.getBoundingClientRect();
let rowIndex = 0;
// let lastTr = null;
for (const row of rows) {
const box = row.getBoundingClientRect();
// console.log('BOX', box);
if (box.y > wrapBox.bottom) {
break;
}
// if (box.y > domWrapper.scrollTop + wrapBox.height) {
// break;
// }
// lastTr = row;
rowIndex += 1;
}
return rowIndex;
}
async function checkLoadAdditionalData() {
if (!display) return;
await tick();
if (!domTable) return;
const rowIndex = getLastVisibleRowIndex();
const growIndicators = _.keys(display.loadIndicatorsCounts).filter(
indicator => rowIndex >= display.loadIndicatorsCounts[indicator]
);
// console.log('growIndicators', growIndicators);
// console.log('display.loadIndicatorsCounts IN', display.loadIndicatorsCounts);
// console.log('rowIndex', rowIndex);
if (growIndicators.length > 0) {
dbg('load next', growIndicators);
loadedCounts.update(counts => {
const res = { ...counts };
for (const id of growIndicators) {
res[id] = (res[id] || PERSPECTIVE_PAGE_SIZE) + PERSPECTIVE_PAGE_SIZE;
}
return res;
});
}
// console.log('LAST VISIBLE ROW', rowIndex, wrapBox.height, lastTr, lastTr.getBoundingClientRect());
// var start = 0;
// var end = rows.length;
// var count = 0;
// while (start != end) {
// var mid = start + Math.floor((end - start) / 2);
// if ($(rows[mid]).offset().top < document.documentElement.scrollTop) start = mid + 1;
// else end = mid;
// }
// console.log('SCROLL', domTable.querySelector('tr:visible:last'));
}
// $: console.log('display.loadIndicatorsCounts', display?.loadIndicatorsCounts);
</script> </script>
<div class="wrapper" bind:this={domWrapper} use:resizeObserver={true} use:contextMenu={buildMenu}> <div
class="wrapper"
bind:this={domWrapper}
use:resizeObserver={true}
use:contextMenu={buildMenu}
on:scroll={checkLoadAdditionalData}
>
{#if display} {#if display}
<table> <table bind:this={domTable}>
<thead> <thead>
{#each _.range(display.columnLevelCount) as columnLevel} {#each _.range(display.columnLevelCount) as columnLevel}
<tr> <tr>
{#each display.columns as column} {#each display.columns as column}
<PerspectiveHeaderControl label={column.title} {column} {columnLevel} {setConfig} {config} /> <PerspectiveHeaderControl {column} {columnLevel} {setConfig} {config} />
{/each} {/each}
</tr> </tr>
{/each} {/each}
@ -185,12 +261,13 @@
<td colspan={display.columns.length} <td colspan={display.columns.length}
><PerspectiveIntersectionObserver ><PerspectiveIntersectionObserver
rootNode={domWrapper} rootNode={domWrapper}
incompleteRowsIndicator={row.incompleteRowsIndicator}
onLoadNext={() => { onLoadNext={() => {
dbg('load next', row.incompleteRowsIndicator); dbg('load next', row.incompleteRowsIndicator);
loadedCounts.update(counts => { loadedCounts.update(counts => {
const res = { ...counts }; const res = { ...counts };
for (const id of row.incompleteRowsIndicator) { for (const id of row.incompleteRowsIndicator) {
res[id] = (res[id] || 100) + 100; res[id] = (res[id] || PERSPECTIVE_PAGE_SIZE) + PERSPECTIVE_PAGE_SIZE;
} }
return res; return res;
}); });