diff --git a/.eslintrc.json b/.eslintrc.json
index c9ecad2e..d1d87bff 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,7 +1,8 @@
{
"parser": "babel-eslint",
"plugins": [
- "prettier"
+ "prettier",
+ "html"
],
"env": {
"browser": true,
diff --git a/README.md b/README.md
index 442e7e33..c2264658 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ named ``,
which renders a regular HTML `` to a `fixed` position within a scollable
viewport. Only visible cells are rendered and queried from a natively `async`
virtual data model, making `regular-table` ideal for enormous or remote data
-sets. Use it to build high-performance Data Grids,
+sets. Use it to build Data Grids,
Spreadsheets, Pivot Tables, File Trees, or anytime you need:
* Just a regular ``.
@@ -89,12 +89,6 @@ to write a simple _virtual_ data model to access `DATA` and `COLUMN_NAMES`
indirectly.
```javascript
-const COLUMN_NAMES = [
- "Column 1 (number)",
- "Column 2 (string)",
- "Column 3 (boolean)",
-];
-
const DATA = [
[0, 1, 2, 3, 4, 5],
["A", "B", "C", "D", "E", "F"],
@@ -102,30 +96,57 @@ const DATA = [
];
```
+When clipped by the scrollable viewport, you may end up with a `` of just
+a rectangular region of `DATA`:
+
+
+
+
+| 0 |
+A |
+
+
+| 1 |
+B |
+
+
+
+
Here's a simple _virtual_ data model for this example, the function
`getDataSlice()`. This function is called by your `` whenever it
needs more data, with coordinate arguments, `(x0, y0)` to `(x1, y1)`. Only
this region is needed to render the viewport, so `getDataSlice()` returns
-this rectangular `slice` of `DATA`, as well as overall dimensions the overall
-dimensions of `DATA` itself ( `num_rows`, `num_columns`), for sizing the
-virtual scroll area:
+this rectangular `slice` of `DATA`:
```javascript
function getDataSlice(x0, y0, x1, y1) {
const data = DATA.slice(x0, x1).map(col => col.slice(y0, y1));
- const column_indices = COLUMN_NAMES.slice(x0, x1);
const num_columns = DATA.length;
const num_rows = DATA[0].length;
return {
num_rows,
num_columns,
- column_indices,
data
};
}
```
+For the window (0, 0) to (2, 2), `getDataSlice()` would generate an Object
+like this, containing the `data` slice, as well as the overall dimensions of
+`DATA` itself ( `num_rows`, `num_columns`), for sizing the scroll area.
+
+```json
+{
+ "num_rows": 26,
+ "num_columns": 3,
+ "data": [
+ [0, 1],
+ ["A", "B"]
+ ]
+}
+```
+
To render this virtual data model to a regular HTML ``, all you need to
do is register this data model via the `setDataModel()` method:
@@ -143,12 +164,6 @@ scroll, more data will be fetched from `getDataSlice()`, and parts of the
-
-
- | Column 1 (number) |
- Column 2 (string) |
-
-
| 0 |
@@ -203,6 +218,196 @@ self.addEventListener("message", async (event) => {
});
```
+## Column and Row Headers
+
+`regular-table` can also generate Hierarchial Row and Column Headers, using
+`` elements which layout in a `fixed` position within the virtual table.
+It can generate Column Headers (within the ``), or Row Headers (the first
+children of each `tbody tr`), via the `column_headers` and `row_headers`
+properties (respectively) of your data model's `Response` object.
+
+
+
+
+
+| Column 1 (number) |
+Column 2 (string) |
+
+
+
+
+| 0 |
+A |
+
+
+| 1 |
+B |
+
+
+
+
+This can be renderered with `column_headers`, a two dimensional `Array` which
+must be of length `x1 - x0`.
+one `Array` for every column in your `data` window. A modified
+`getDataSlice()` which describes this ``:
+
+```javascript
+const COLUMN_HEADERS = [
+ ["Column 1 (number)"],
+ ["Column 2 (string)"],
+ ["Column 3 (boolean)"],
+];
+
+function getDataSlice(x0, y0, x1, y1) {
+ const data = DATA.slice(x0, x1).map(col => col.slice(y0, y1));
+ const column_headers = COLUMN_NAMES.slice(x0, x1);
+ const num_columns = DATA.length;
+ const num_rows = DATA[0].length;
+
+ return {
+ column_headers,
+ num_rows,
+ num_columns,
+ data
+ };
+}
+```
+
+Samples response:
+
+```json
+{
+ "num_rows": 26,
+ "num_columns": 3,
+ "data": [
+ [0, 1],
+ ["A", "B"]
+ ],
+ "column_headers": [
+ ["Column 1 (number)"],
+ ["Column 2 (string)"]
+ ]
+}
+```
+
+Resulting HTML:
+
+```html
+
+
+
+
+
+ | Column 1 (number) |
+ Column 2 (string) |
+
+
+
+
+ | 0 |
+ A |
+
+
+ | 1 |
+ B |
+
+
+
+
+
+```
+
+## Hierarchial/Group Headers
+
+`regular-table` supports multiple `` of ``, and also uses `colspan` and
+`rowspan` to merge simple consecutive names, which allows description of simple
+Row and Column Group Hierarchies such as this:
+
+
+
+
+
+ |
+Colgroup 1 |
+
+
+| Column 1 |
+Column 2 |
+
+
+
+
+| Rowgroup 1 |
+Row 1 |
+0 |
+A |
+
+
+| Row 2 |
+1 |
+B |
+
+
+
+
+A sample response object that renders this `` would look like this:
+
+```json
+{
+ "num_rows": 26,
+ "num_columns": 3,
+ "data": [
+ [0, 1],
+ ["A", "B"]
+ ],
+ "row_headers": [
+ ["Rowgroup 1", "Row 1"],
+ ["Rowgroup 1", "Row 2"]
+ ],
+ "column_headers": [
+ ["Colgroup 1", "Column 1"],
+ ["Colgroup 1", "Column 2"]
+ ]
+}
+```
+
+Note that in the rendered HTML below, for these Row and Column `Array`,
+repeated elements in a sequence will be automatically merged via `rowspan` and
+`colspan` attributes. In this example, e.g. `"Rowgroup 1"` will only output
+to one `` node in the resulting ``:
+
+```html
+
+
+
+
+
+ |
+ Colgroup 1 |
+
+
+ | Column 1 |
+ Column 2 |
+
+
+
+
+ | Rowgroup 1 |
+ Row 1 |
+ 0 |
+ A |
+
+
+ | Row 2 |
+ 1 |
+ B |
+
+
+
+
+
+```
+
## Development
First install `dev_dependencies`:
diff --git a/examples/2d_array.html b/examples/2d_array.html
index 2f4d2933..c4d654e7 100644
--- a/examples/2d_array.html
+++ b/examples/2d_array.html
@@ -21,36 +21,30 @@
| | |
+
+
+
+
+
+
diff --git a/examples/canvas_data_model.html b/examples/canvas_data_model.html
index 933d1950..df5410c4 100644
--- a/examples/canvas_data_model.html
+++ b/examples/canvas_data_model.html
@@ -34,21 +34,21 @@
margin: 0;
overflow: auto;
}
- th, td {
+ th:not(:first-child), td {
height: 20px !important;
min-width: 20px !important;
max-width: 20px !important;
padding: 0px;
}
- th {
- transform: rotate(-90deg);
- transform-origin: 30% 92%;
+ th {
color: white;
font-family: monospace;
- text-align: left !important;
- border-bottom-width: 0px !important;
- height: 40px !important;
- border-left: 1px solid white;
+ }
+ tbody th:first-child {
+ vertical-align: top;
+ border-bottom: 1px solid white;
+ border-right: 0px !important;
+ text-align: left;
}
regular-table {
position: absolute;
@@ -67,7 +67,7 @@
bottom: 0;
right: 0;
border-top-width: 0;
- box-shadow: 0px 15px 10px -10px rgba(0,0,0,1);
+ border-left-width: 0;
}
regular-table::-webkit-scrollbar-thumb {
background-color: #fff !important;
@@ -94,45 +94,49 @@
diff --git a/examples/minesweeper.html b/examples/minesweeper.html
new file mode 100644
index 00000000..536e632a
--- /dev/null
+++ b/examples/minesweeper.html
@@ -0,0 +1,283 @@
+
+
+
+
+
+