Skip to content

Commit

Permalink
[#6] Started implementing a ScrollManager
Browse files Browse the repository at this point in the history
  • Loading branch information
icegreentea committed Feb 13, 2022
1 parent d56d49a commit 41836e4
Show file tree
Hide file tree
Showing 3 changed files with 226 additions and 0 deletions.
16 changes: 16 additions & 0 deletions core.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
.coresheet_content {
/* width: 100%; */
overflow: scroll;
height: 100%;
}

.coresheet {
Expand All @@ -35,6 +36,20 @@

}

.coresheet > tbody > tr > td:first-child {
position: sticky;
left: 0;

border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
border-right: 1px solid #ccc;
border-bottom: 1px solid transparent;
background-color: #f3f3f3;
padding: 2px;
z-index: 999;

}

.coresheet > thead > tr > td {
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
Expand All @@ -49,6 +64,7 @@
position: -webkit-sticky;
position: sticky;
top: 0;
z-index: 1000;
}

.coresheet > tbody > tr > td
Expand Down
174 changes: 174 additions & 0 deletions core.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ class Grid {
#focused_cell = null;
#active_textarea = null;
table_element = null;
scroll_element = null;

constructor(element, header_data, data) {
this.element = element;
Expand All @@ -10,6 +11,7 @@ class Grid {

this._createTable();
this.selection_manager = new SelectionManager(this.table_element);
this.scroll_manager = new ScrollManager(this.table_element, this.scroll_element);
this.table_element.addEventListener("tableselectionchanged", (e) =>
this.tableSelectionChanged(e)
);
Expand All @@ -19,6 +21,7 @@ class Grid {
this.element.classList.add("coresheet_container");
let inner_el = document.createElement("div");
inner_el.classList.add("coresheet_content");
this.scroll_element = inner_el;
this.element.appendChild(inner_el);

let table = document.createElement("table");
Expand Down Expand Up @@ -581,6 +584,10 @@ function getLogicalCell(table_element, logical_x, logical_y) {
);
}

function getGridCell(table_element, grid_x, grid_y) {
return table_element.querySelector(`td[data-grid-x="${grid_x}"][data-grid-y="${grid_y}"]`);
}

function clampedDecrement(x, limit) {
if (x > limit) return x - 1;
return x;
Expand All @@ -605,3 +612,170 @@ function getLogicalCoord(element) {
parseInt(element.getAttribute("data-logical-y")),
];
}

function _isCellVisible(view_bounds, cell_bounds) {
return _isRowVisible(view_bounds, cell_bounds) && _isColumnVisible(view_bounds, cell_bounds);
}

function _isCellFullyVisible(view_bounds, cell_bounds) {
return (
_isRowFullyVisible(view_bounds, cell_bounds) && _isColumnFullyVisible(view_bounds, cell_bounds)
);
}

function _isRowVisible(view_bounds, cell_bounds) {
const { top, bottom } = view_bounds;
if (cell_bounds.top >= top && cell_bounds.bottom <= bottom) return true;
if (cell_bounds.top <= top && cell_bounds.bottom >= top) return true;
if (cell_bounds.top <= bottom && cell_bounds.bottom >= bottom) return true;
return false;
}

function _isRowFullyVisible(view_bounds, cell_bounds) {
return cell_bounds.top >= view_bounds.top && cell_bounds.bottom <= view_bounds.bottom;
}

function _isColumnVisible(view_bounds, cell_bounds) {
const { left, right } = view_bounds;
if (cell_bounds.left >= left && cell_bounds.right <= right) return true;
if (cell_bounds.left <= left && cell_bounds.right >= left) return true;
if (cell_bounds.left <= right && cell_bounds.right >= right) return true;
return false;
}

function _isColumnFullyVisible(view_bounds, cell_bounds) {
return cell_bounds.left >= view_bounds.left && cell_bounds.right <= view_bounds.right;
}

class ScrollManager {
constructor(table_element, scroll_element) {
this.table_element = table_element;
this.scroll_element = scroll_element;
}

get view_bounds() {
let { left, bottom, right, top } = this.scroll_element.getBoundingClientRect();
let { width: index_width, height: header_height } = getGridCell(
this.table_element,
0,
0
).getBoundingClientRect();
left = left + index_width;
top = top + header_height;
right = right - (this.scroll_element.offsetWidth - this.scroll_element.clientWidth);
bottom = bottom - (this.scroll_element.offsetHeight - this.scroll_element.clientHeight);
return { left, bottom, right, top };
}

isLogicalCellVisible(logical_x, logical_y) {
const cell = getLogicalCell(this.table_element, logical_x, logical_y);
return _isCellVisible(
this.scroll_element.getBoundingClientRect(),
cell.getBoundingClientRect()
);
}

isLogicalCellFullyVisible(logical_x, logical_y) {
const cell = getLogicalCell(this.table_element, logical_x, logical_y);
return _isCellFullyVisible(
this.scroll_element.getBoundingClientRect(),
cell.getBoundingClientRect()
);
}

getVisibleRows() {
const cells = Array.from(this.table_element.querySelectorAll("tbody > tr > td:first-child"));
return cells
.filter((c) => {
return _isRowVisible(this.view_bounds, c.getBoundingClientRect());
})
.map((c) => {
return parseInt(c.getAttribute("data-logical-y"));
});
}

getFullyVisibleRows() {
const cells = Array.from(this.table_element.querySelectorAll("tbody > tr > td:first-child"));
return cells
.filter((c) => {
return _isRowFullyVisible(this.view_bounds, c.getBoundingClientRect());
})
.map((c) => {
return parseInt(c.getAttribute("data-logical-y"));
});
}

getVisibleColumns() {
const cells = Array.from(
this.table_element.querySelectorAll("thead > tr > td:not(:first-child)")
);
return cells
.filter((c) => {
return _isColumnVisible(this.view_bounds, c.getBoundingClientRect());
})
.map((c) => {
return parseInt(c.getAttribute("data-logical-x"));
});
}

getFullyVisibleColumns() {
const cells = Array.from(
this.table_element.querySelectorAll("thead > tr > td:not(:first-child)")
);
return cells
.filter((c) => {
return _isColumnVisible(this.view_bounds, c.getBoundingClientRect());
})
.map((c) => {
return parseInt(c.getAttribute("data-logical-x"));
});
}

getNextVisibleRowDown() {
const visible_rows = this.getFullyVisibleRows();
return getLogicalCell(this.table_element, 0, visible_rows[visible_rows.length - 1] + 1);
}

getNextVisibleRowUp() {
const visible_rows = this.getFullyVisibleRows();
return getLogicalCell(this.table_element, 0, visible_rows[0] - 1);
}

getNextVisibleColumnLeft() {
const visible_cols = this.getFullyVisibleColumns();
return getLogicalCell(this.table_element, visible_cols[0] - 1, 0);
}

getNextVisibleColumnRight() {
const visible_cols = this.getFullyVisibleColumns();
return getLogicalCell(this.table_element, visible_cols[visible_cols.length - 1] + 1, 0);
}

scrollRowUp() {
const prev_row = this.getNextVisibleRowUp();
if (prev_row === null) return;
const offset = prev_row.getBoundingClientRect().top - this.view_bounds.top;
this.scroll_element.scrollBy(0, offset);
}

scrollRowDown() {
const next_row = this.getNextVisibleRowDown();
if (next_row === null) return;
const offset = next_row.getBoundingClientRect().bottom - this.view_bounds.bottom;
this.scroll_element.scrollBy(0, offset + 1);
}

scrollColumnLeft() {
const next_col = this.getNextVisibleColumnLeft();
if (next_col === null) return;
const offset = next_col.getBoundingClientRect().left - this.view_bounds.left;
this.scroll_element.scrollBy(offset, 0);
}

scrollColumnRight() {
const next_col = this.getNextVisibleColumnRight();
if (next_col === null) return;
const offset = next_col.getBoundingClientRect().right - this.view_bounds.right;
this.scroll_element.scrollBy(offset + 1, 0);
}
}
36 changes: 36 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,42 @@
{"A" : 123, "B": 234, "C": 3455555555555555, "D": 12345678901234567890, "E": 12345678901234567890, "F": 12345678901234567890, "G": 12345678901234567890, "H": 12345678901234567890},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},
{"A" : 123, "B": 234, "C": 345},

])
</script>
Expand Down

0 comments on commit 41836e4

Please sign in to comment.