Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 22 additions & 10 deletions dist/js/tabulator.js
Original file line number Diff line number Diff line change
Expand Up @@ -2485,10 +2485,16 @@
}

let diff = this.fitDataColActualWidthCheck(column);

if(diff){
this.scrollLeft = this.elementVertical.scrollLeft = this.elementVertical.scrollLeft + diff;
this.vDomPadRight -= diff;
// Keep the header's horizontal position in lockstep with
// the body when we bump scrollLeft mid-handler. Without
// this, the header is only re-synced via the body's
// queued scroll event, which leaves it visibly behind
// the body during a continuous left-scroll.
this.table.columnManager.scrollHorizontal(this.scrollLeft);
}

}else {
Expand Down Expand Up @@ -2780,20 +2786,26 @@

//scroll horizontally to match table body
scrollHorizontal(left){
this.contentsElement.scrollLeft = left;

// Translate the headers instead of scrolling a separate
// overflow container. This keeps the header in lockstep with
// the body's native scroll (including sub-pixel and momentum),
// rather than having a second scroll system that the body has
// to push values into asynchronously.
this.headersElement.style.transform = "translateX(" + (-left) + "px)";
this.contentsElement.scrollLeft = 0;

this.scrollLeft = left;

this.renderer.scrollColumns(left);
}

initializeScrollWheelWatcher(){
this.contentsElement.addEventListener("wheel", (e) => {
var left;

if(e.deltaX){
left = this.contentsElement.scrollLeft + e.deltaX;
left = this.scrollLeft + e.deltaX;

this.table.rowManager.scrollHorizontal(left);
this.table.columnManager.scrollHorizontal(left);
}
Expand Down Expand Up @@ -16123,7 +16135,7 @@
});

editorElement.addEventListener("focus", (e) => {
var left = this.table.columnManager.contentsElement.scrollLeft;
var left = this.table.columnManager.scrollLeft;

var headerPos = this.table.rowManager.element.scrollLeft;

Expand Down Expand Up @@ -21076,7 +21088,7 @@

config.mousemove = function(e){
if(column.parent === self.moving.parent){
if((((self.touchMove ? e.touches[0].pageX : e.pageX) - Helpers.elOffset(colEl).left) + self.table.columnManager.contentsElement.scrollLeft) > (column.getWidth() / 2)){
if((((self.touchMove ? e.touches[0].pageX : e.pageX) - Helpers.elOffset(colEl).left) + self.table.columnManager.scrollLeft) > (column.getWidth() / 2)){
if(self.toCol !== column || !self.toColAfter){
colEl.parentNode.insertBefore(self.placeholderElement, colEl.nextSibling);
self.moveColumn(column, true);
Expand Down
2 changes: 1 addition & 1 deletion dist/js/tabulator.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/js/tabulator.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/js/tabulator.min.js.map

Large diffs are not rendered by default.

32 changes: 22 additions & 10 deletions dist/js/tabulator_esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -9806,7 +9806,7 @@ class Filter extends Module{
});

editorElement.addEventListener("focus", (e) => {
var left = this.table.columnManager.contentsElement.scrollLeft;
var left = this.table.columnManager.scrollLeft;

var headerPos = this.table.rowManager.element.scrollLeft;

Expand Down Expand Up @@ -14759,7 +14759,7 @@ class MoveColumns extends Module{

config.mousemove = function(e){
if(column.parent === self.moving.parent){
if((((self.touchMove ? e.touches[0].pageX : e.pageX) - Helpers.elOffset(colEl).left) + self.table.columnManager.contentsElement.scrollLeft) > (column.getWidth() / 2)){
if((((self.touchMove ? e.touches[0].pageX : e.pageX) - Helpers.elOffset(colEl).left) + self.table.columnManager.scrollLeft) > (column.getWidth() / 2)){
if(self.toCol !== column || !self.toColAfter){
colEl.parentNode.insertBefore(self.placeholderElement, colEl.nextSibling);
self.moveColumn(column, true);
Expand Down Expand Up @@ -24071,10 +24071,16 @@ class VirtualDomHorizontal extends Renderer{
}

let diff = this.fitDataColActualWidthCheck(column);

if(diff){
this.scrollLeft = this.elementVertical.scrollLeft = this.elementVertical.scrollLeft + diff;
this.vDomPadRight -= diff;
// Keep the header's horizontal position in lockstep with
// the body when we bump scrollLeft mid-handler. Without
// this, the header is only re-synced via the body's
// queued scroll event, which leaves it visibly behind
// the body during a continuous left-scroll.
this.table.columnManager.scrollHorizontal(this.scrollLeft);
}

}else {
Expand Down Expand Up @@ -24366,20 +24372,26 @@ class ColumnManager extends CoreFeature {

//scroll horizontally to match table body
scrollHorizontal(left){
this.contentsElement.scrollLeft = left;

// Translate the headers instead of scrolling a separate
// overflow container. This keeps the header in lockstep with
// the body's native scroll (including sub-pixel and momentum),
// rather than having a second scroll system that the body has
// to push values into asynchronously.
this.headersElement.style.transform = "translateX(" + (-left) + "px)";
this.contentsElement.scrollLeft = 0;

this.scrollLeft = left;

this.renderer.scrollColumns(left);
}

initializeScrollWheelWatcher(){
this.contentsElement.addEventListener("wheel", (e) => {
var left;

if(e.deltaX){
left = this.contentsElement.scrollLeft + e.deltaX;
left = this.scrollLeft + e.deltaX;

this.table.rowManager.scrollHorizontal(left);
this.table.columnManager.scrollHorizontal(left);
}
Expand Down
2 changes: 1 addition & 1 deletion dist/js/tabulator_esm.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/js/tabulator_esm.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/js/tabulator_esm.min.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/js/tabulator_esm.min.mjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/js/tabulator_esm.min.mjs.map

Large diffs are not rendered by default.

32 changes: 22 additions & 10 deletions dist/js/tabulator_esm.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9806,7 +9806,7 @@ class Filter extends Module{
});

editorElement.addEventListener("focus", (e) => {
var left = this.table.columnManager.contentsElement.scrollLeft;
var left = this.table.columnManager.scrollLeft;

var headerPos = this.table.rowManager.element.scrollLeft;

Expand Down Expand Up @@ -14759,7 +14759,7 @@ class MoveColumns extends Module{

config.mousemove = function(e){
if(column.parent === self.moving.parent){
if((((self.touchMove ? e.touches[0].pageX : e.pageX) - Helpers.elOffset(colEl).left) + self.table.columnManager.contentsElement.scrollLeft) > (column.getWidth() / 2)){
if((((self.touchMove ? e.touches[0].pageX : e.pageX) - Helpers.elOffset(colEl).left) + self.table.columnManager.scrollLeft) > (column.getWidth() / 2)){
if(self.toCol !== column || !self.toColAfter){
colEl.parentNode.insertBefore(self.placeholderElement, colEl.nextSibling);
self.moveColumn(column, true);
Expand Down Expand Up @@ -24071,10 +24071,16 @@ class VirtualDomHorizontal extends Renderer{
}

let diff = this.fitDataColActualWidthCheck(column);

if(diff){
this.scrollLeft = this.elementVertical.scrollLeft = this.elementVertical.scrollLeft + diff;
this.vDomPadRight -= diff;
// Keep the header's horizontal position in lockstep with
// the body when we bump scrollLeft mid-handler. Without
// this, the header is only re-synced via the body's
// queued scroll event, which leaves it visibly behind
// the body during a continuous left-scroll.
this.table.columnManager.scrollHorizontal(this.scrollLeft);
}

}else {
Expand Down Expand Up @@ -24366,20 +24372,26 @@ class ColumnManager extends CoreFeature {

//scroll horizontally to match table body
scrollHorizontal(left){
this.contentsElement.scrollLeft = left;

// Translate the headers instead of scrolling a separate
// overflow container. This keeps the header in lockstep with
// the body's native scroll (including sub-pixel and momentum),
// rather than having a second scroll system that the body has
// to push values into asynchronously.
this.headersElement.style.transform = "translateX(" + (-left) + "px)";
this.contentsElement.scrollLeft = 0;

this.scrollLeft = left;

this.renderer.scrollColumns(left);
}

initializeScrollWheelWatcher(){
this.contentsElement.addEventListener("wheel", (e) => {
var left;

if(e.deltaX){
left = this.contentsElement.scrollLeft + e.deltaX;
left = this.scrollLeft + e.deltaX;

this.table.rowManager.scrollHorizontal(left);
this.table.columnManager.scrollHorizontal(left);
}
Expand Down
2 changes: 1 addition & 1 deletion dist/js/tabulator_esm.mjs.map

Large diffs are not rendered by default.

20 changes: 13 additions & 7 deletions src/js/core/ColumnManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,20 +129,26 @@ export default class ColumnManager extends CoreFeature {

//scroll horizontally to match table body
scrollHorizontal(left){
this.contentsElement.scrollLeft = left;

// Translate the headers instead of scrolling a separate
// overflow container. This keeps the header in lockstep with
// the body's native scroll (including sub-pixel and momentum),
// rather than having a second scroll system that the body has
// to push values into asynchronously.
this.headersElement.style.transform = "translateX(" + (-left) + "px)";
this.contentsElement.scrollLeft = 0;

this.scrollLeft = left;

this.renderer.scrollColumns(left);
}

initializeScrollWheelWatcher(){
this.contentsElement.addEventListener("wheel", (e) => {
var left;

if(e.deltaX){
left = this.contentsElement.scrollLeft + e.deltaX;
left = this.scrollLeft + e.deltaX;

this.table.rowManager.scrollHorizontal(left);
this.table.columnManager.scrollHorizontal(left);
}
Expand Down
8 changes: 7 additions & 1 deletion src/js/core/rendering/renderers/VirtualDomHorizontal.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,10 +411,16 @@ export default class VirtualDomHorizontal extends Renderer{
}

let diff = this.fitDataColActualWidthCheck(column);

if(diff){
this.scrollLeft = this.elementVertical.scrollLeft = this.elementVertical.scrollLeft + diff;
this.vDomPadRight -= diff;
// Keep the header's horizontal position in lockstep with
// the body when we bump scrollLeft mid-handler. Without
// this, the header is only re-synced via the body's
// queued scroll event, which leaves it visibly behind
// the body during a continuous left-scroll.
this.table.columnManager.scrollHorizontal(this.scrollLeft);
}

}else{
Expand Down
2 changes: 1 addition & 1 deletion src/js/modules/Filter/Filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ export default class Filter extends Module{
});

editorElement.addEventListener("focus", (e) => {
var left = this.table.columnManager.contentsElement.scrollLeft;
var left = this.table.columnManager.scrollLeft;

var headerPos = this.table.rowManager.element.scrollLeft;

Expand Down
2 changes: 1 addition & 1 deletion src/js/modules/MoveColumns/MoveColumns.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export default class MoveColumns extends Module{

config.mousemove = function(e){
if(column.parent === self.moving.parent){
if((((self.touchMove ? e.touches[0].pageX : e.pageX) - Helpers.elOffset(colEl).left) + self.table.columnManager.contentsElement.scrollLeft) > (column.getWidth() / 2)){
if((((self.touchMove ? e.touches[0].pageX : e.pageX) - Helpers.elOffset(colEl).left) + self.table.columnManager.scrollLeft) > (column.getWidth() / 2)){
if(self.toCol !== column || !self.toColAfter){
colEl.parentNode.insertBefore(self.placeholderElement, colEl.nextSibling);
self.moveColumn(column, true);
Expand Down
78 changes: 78 additions & 0 deletions test/e2e/horizontal-vdom.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Tabulator Horizontal vDOM Test</title>
<link rel="stylesheet" href="../../dist/css/tabulator.min.css" />
<script src="../../dist/js/tabulator.js"></script>
<style>
body {
padding: 20px;
font-family: Arial, sans-serif;
}
#test-table {
width: 600px;
height: 300px;
}
#metrics {
margin-top: 12px;
font-family: monospace;
white-space: pre;
}
</style>
</head>
<body>
<h1>Tabulator Horizontal vDOM Test</h1>
<div id="test-table"></div>
<div id="metrics"></div>

<script>
document.addEventListener("DOMContentLoaded", function () {
// 100+ columns matches the scenario in github issue #3551.
const NUM_COLS = 120;
const columns = [];
for (let i = 0; i < NUM_COLS; i++) {
columns.push({ title: "Column header " + i, field: "c" + i });
}

const data = [];
for (let r = 0; r < 200; r++) {
const row = { id: r };
for (let i = 0; i < NUM_COLS; i++) {
// Vary text length per column so widths differ
row["c" + i] = "row " + r + " / col " + i + " " + "x".repeat((i * 3) % 11);
}
data.push(row);
}

window.testTable = new Tabulator("#test-table", {
data,
columns,
layout: "fitData",
renderHorizontal: "virtual",
});

window.measure = function() {
const tableEl = document.querySelector("#test-table");
const body = tableEl.querySelector(".tabulator-tableholder");
const headerContents = tableEl.querySelector(".tabulator-header-contents");
const headers = tableEl.querySelector(".tabulator-headers");
const tableInner = tableEl.querySelector(".tabulator-tableholder .tabulator-table");

return {
bodyScrollLeft: body.scrollLeft,
bodyScrollWidth: body.scrollWidth,
bodyClientWidth: body.clientWidth,
headerScrollLeft: headerContents.scrollLeft,
headerScrollWidth: headerContents.scrollWidth,
headerClientWidth: headerContents.clientWidth,
headersWidth: headers.offsetWidth,
bodyTableWidth: tableInner.offsetWidth,
bodyTablePadLeft: tableInner.style.paddingLeft,
bodyTablePadRight: tableInner.style.paddingRight,
};
};
});
</script>
</body>
</html>
Loading
Loading