mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-29 22:43:58 +00:00
grid scroll bars
This commit is contained in:
@@ -1,15 +1,36 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import FontIcon from '../icons/FontIcon.svelte';
|
||||||
|
import DropDownButton from '../widgets/DropDownButton.svelte';
|
||||||
|
|
||||||
import ColumnLabel from './ColumnLabel.svelte';
|
import ColumnLabel from './ColumnLabel.svelte';
|
||||||
|
|
||||||
|
export let column;
|
||||||
export let conid = undefined;
|
export let conid = undefined;
|
||||||
export let database = undefined;
|
export let database = undefined;
|
||||||
export let column;
|
export let grouping = undefined;
|
||||||
|
export let order = undefined;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="label">
|
<div class="label">
|
||||||
|
{#if grouping}
|
||||||
|
<span class="grouping">
|
||||||
|
{grouping == 'COUNT DISTINCT' ? 'distinct' : grouping.toLowerCase()}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
<ColumnLabel {...column} />
|
<ColumnLabel {...column} />
|
||||||
</div>
|
</div>
|
||||||
|
{#if order == 'ASC'}
|
||||||
|
<span class="icon">
|
||||||
|
<FontIcon icon="img sort-asc" />
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
{#if order == 'DESC'}
|
||||||
|
<span class="icon">
|
||||||
|
<FontIcon icon="img sort-desc" />
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
<DropDownButton />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
{value.toString()}
|
{value.toString()}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if hintFieldsAllowed && hintFieldsAllowed.includes(col.uniqueName)}
|
{#if hintFieldsAllowed && hintFieldsAllowed.includes(col.uniqueName) && rowData}
|
||||||
<span class="hint">{rowData[col.hintColumnName]}</span>
|
<span class="hint">{rowData[col.hintColumnName]}</span>
|
||||||
{/if}
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
import ColumnHeaderControl from './ColumnHeaderControl.svelte';
|
import ColumnHeaderControl from './ColumnHeaderControl.svelte';
|
||||||
import DataGridRow from './DataGridRow.svelte';
|
import DataGridRow from './DataGridRow.svelte';
|
||||||
import { countColumnSizes, countVisibleRealColumns } from './gridutil';
|
import { countColumnSizes, countVisibleRealColumns } from './gridutil';
|
||||||
|
import HorizontalScrollBar from './HorizontalScrollBar.svelte';
|
||||||
|
import VerticalScrollBar from './VerticalScrollBar.svelte';
|
||||||
|
|
||||||
export let loadNextData = undefined;
|
export let loadNextData = undefined;
|
||||||
export let grider = undefined;
|
export let grider = undefined;
|
||||||
@@ -17,7 +19,7 @@
|
|||||||
let firstVisibleRowScrollIndex = 0;
|
let firstVisibleRowScrollIndex = 0;
|
||||||
let firstVisibleColumnScrollIndex = 0;
|
let firstVisibleColumnScrollIndex = 0;
|
||||||
// $: firstVisibleRowScrollIndex = 0;
|
// $: firstVisibleRowScrollIndex = 0;
|
||||||
$: visibleRowCountUpperBound = 25;
|
// $: visibleRowCountUpperBound = 25;
|
||||||
|
|
||||||
// $: console.log('grider', grider);
|
// $: console.log('grider', grider);
|
||||||
$: columns = display.allColumns;
|
$: columns = display.allColumns;
|
||||||
@@ -29,6 +31,9 @@
|
|||||||
$: gridScrollAreaHeight = containerHeight - 2 * rowHeight;
|
$: gridScrollAreaHeight = containerHeight - 2 * rowHeight;
|
||||||
$: gridScrollAreaWidth = containerWidth - columnSizes.frozenSize - headerColWidth - 32;
|
$: gridScrollAreaWidth = containerWidth - columnSizes.frozenSize - headerColWidth - 32;
|
||||||
|
|
||||||
|
$: visibleRowCountUpperBound = Math.ceil(gridScrollAreaHeight / Math.floor(Math.max(1, rowHeight)));
|
||||||
|
$: visibleRowCountLowerBound = Math.floor(gridScrollAreaHeight / Math.ceil(Math.max(1, rowHeight)));
|
||||||
|
|
||||||
$: visibleRealColumns = countVisibleRealColumns(
|
$: visibleRealColumns = countVisibleRealColumns(
|
||||||
columnSizes,
|
columnSizes,
|
||||||
firstVisibleColumnScrollIndex,
|
firstVisibleColumnScrollIndex,
|
||||||
@@ -36,12 +41,17 @@
|
|||||||
columns
|
columns
|
||||||
);
|
);
|
||||||
|
|
||||||
$: console.log('visibleRealColumns', visibleRealColumns);
|
// $: console.log('visibleRealColumns', visibleRealColumns);
|
||||||
|
$: console.log('visibleRowCountUpperBound', visibleRowCountUpperBound);
|
||||||
|
$: console.log('rowHeight', rowHeight);
|
||||||
|
$: console.log('containerHeight', containerHeight);
|
||||||
|
|
||||||
$: realColumnUniqueNames = _.range(columnSizes.realCount).map(
|
$: realColumnUniqueNames = _.range(columnSizes.realCount).map(
|
||||||
realIndex => (columns[columnSizes.realToModel(realIndex)] || {}).uniqueName
|
realIndex => (columns[columnSizes.realToModel(realIndex)] || {}).uniqueName
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$: maxScrollColumn = columnSizes.scrollInView(0, columns.length - 1 - columnSizes.frozenCount, gridScrollAreaWidth);
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (loadNextData && firstVisibleRowScrollIndex + visibleRowCountUpperBound >= grider.rowCount) {
|
if (loadNextData && firstVisibleRowScrollIndex + visibleRowCountUpperBound >= grider.rowCount) {
|
||||||
loadNextData();
|
loadNextData();
|
||||||
@@ -54,7 +64,7 @@
|
|||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="header-cell" data-row="header" data-col="header" />
|
<td class="header-cell" data-row="header" data-col="header" bind:clientHeight={rowHeight} />
|
||||||
{#each visibleRealColumns as col (col.uniqueName)}
|
{#each visibleRealColumns as col (col.uniqueName)}
|
||||||
<td
|
<td
|
||||||
class="header-cell"
|
class="header-cell"
|
||||||
@@ -69,10 +79,22 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{#each _.range(firstVisibleRowScrollIndex, firstVisibleRowScrollIndex + visibleRowCountUpperBound) as rowIndex (rowIndex)}
|
{#each _.range(firstVisibleRowScrollIndex, firstVisibleRowScrollIndex + visibleRowCountUpperBound) as rowIndex (rowIndex)}
|
||||||
<DataGridRow {rowIndex} {grider} {visibleRealColumns} />
|
<DataGridRow {rowIndex} {grider} {visibleRealColumns} {rowHeight} />
|
||||||
{/each}
|
{/each}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<HorizontalScrollBar
|
||||||
|
minimum={0}
|
||||||
|
maximum={maxScrollColumn}
|
||||||
|
viewportRatio={gridScrollAreaWidth / columnSizes.getVisibleScrollSizeSum()}
|
||||||
|
on:scroll={e => (firstVisibleColumnScrollIndex = e.detail)}
|
||||||
|
/>
|
||||||
|
<VerticalScrollBar
|
||||||
|
minimum={0}
|
||||||
|
maximum={grider.rowCount - visibleRowCountUpperBound + 2}
|
||||||
|
viewportRatio={visibleRowCountUpperBound / grider.rowCount}
|
||||||
|
on:scroll={e => (firstVisibleRowScrollIndex = e.detail)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@@ -98,7 +120,7 @@
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background-color: var(--theme-bg-2);
|
background-color: var(--theme-bg-1);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.filter-cell {
|
.filter-cell {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
.map(col => col.uniqueName);
|
.map(col => col.uniqueName);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<tr>
|
<tr style={`height: ${rowHeight}px`}>
|
||||||
<RowHeaderCell {rowIndex} />
|
<RowHeaderCell {rowIndex} />
|
||||||
{#each visibleRealColumns as col (col.uniqueName)}
|
{#each visibleRealColumns as col (col.uniqueName)}
|
||||||
<DataGridCell {rowIndex} {rowData} {col} {hintFieldsAllowed} />
|
<DataGridCell {rowIndex} {rowData} {col} {hintFieldsAllowed} />
|
||||||
|
|||||||
35
packages/web/src/datagrid/HorizontalScrollBar.svelte
Normal file
35
packages/web/src/datagrid/HorizontalScrollBar.svelte
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
export let viewportRatio = 0.5;
|
||||||
|
export let minimum;
|
||||||
|
export let maximum;
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
let width;
|
||||||
|
let node;
|
||||||
|
$: contentSize = Math.round(width / viewportRatio);
|
||||||
|
|
||||||
|
function handleScroll() {
|
||||||
|
const position = node.scrollLeft;
|
||||||
|
const ratio = position / (contentSize - width);
|
||||||
|
if (ratio < 0) return 0;
|
||||||
|
const res = ratio * (maximum - minimum + 1) + minimum;
|
||||||
|
dispatch('scroll', Math.floor(res + 0.3));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div bind:clientWidth={width} bind:this={node} on:scroll={handleScroll} class="main">
|
||||||
|
<div style={`width: ${contentSize}px`}> </div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.main {
|
||||||
|
overflow-x: scroll;
|
||||||
|
height: 16px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
36
packages/web/src/datagrid/VerticalScrollBar.svelte
Normal file
36
packages/web/src/datagrid/VerticalScrollBar.svelte
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
export let viewportRatio = 0.5;
|
||||||
|
export let minimum;
|
||||||
|
export let maximum;
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
let height;
|
||||||
|
let node;
|
||||||
|
$: contentSize = Math.round(height / viewportRatio);
|
||||||
|
|
||||||
|
function handleScroll() {
|
||||||
|
const position = node.scrollTop;
|
||||||
|
const ratio = position / (contentSize - height);
|
||||||
|
if (ratio < 0) return 0;
|
||||||
|
let res = ratio * (maximum - minimum + 1) + minimum;
|
||||||
|
dispatch('scroll', Math.floor(res + 0.3));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div bind:clientHeight={height} bind:this={node} on:scroll={handleScroll} class="main">
|
||||||
|
<div style={`height: ${contentSize}px`}> </div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.main {
|
||||||
|
overflow-y: scroll;
|
||||||
|
width: 20px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
width: 20px;
|
||||||
|
bottom: 16px;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
8
packages/web/src/widgets/DropDownButton.svelte
Normal file
8
packages/web/src/widgets/DropDownButton.svelte
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<script>
|
||||||
|
import FontIcon from '../icons/FontIcon.svelte';
|
||||||
|
import InlineButton from './InlineButton.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<InlineButton square>
|
||||||
|
<FontIcon icon="icon chevron-down" />
|
||||||
|
</InlineButton>
|
||||||
@@ -11,9 +11,12 @@
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.outer {
|
.outer {
|
||||||
background: linear-gradient(to bottom, var(--theme-bg-2) 5%, var(--theme-bg-3) 100%);
|
--bg-1: var(--theme-bg-1);
|
||||||
background-color: var(--theme-bg-2);
|
--bg-2: var(--theme-bg-3);
|
||||||
border: 1px solid var(--theme-bg-3);
|
|
||||||
|
background: linear-gradient(to bottom, var(--bg-1) 5%, var(--bg-2) 100%);
|
||||||
|
background-color: var(--bg-1);
|
||||||
|
border: 1px solid var(--bg-2);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
@@ -30,9 +33,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.outer:hover:not(.disabled) {
|
.outer:hover:not(.disabled) {
|
||||||
border: 1px solid var(--theme-bg-2);
|
border: 1px solid var(--bg-1);
|
||||||
background: linear-gradient(to bottom, var(--theme-bg-3) 5%, var(--theme-bg-2) 100%);
|
background: linear-gradient(to bottom, var(--bg-2) 5%, var(--bg-1) 100%);
|
||||||
background-color: var(--theme-bg-3);
|
background-color: var(--bg-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.inner {
|
.inner {
|
||||||
|
|||||||
Reference in New Issue
Block a user