solid-ui
Version:
UI library for Solid applications
217 lines • 8.33 kB
JavaScript
// Build a 2D matrix of values
//
// dom AKA document
// query a Query object of rdflib.js with a valid pattern
// vx A variable object, the one to be used for the X variable (horiz)
// vy A variable object, the one to be used for the Y variable (vertical)
// vvalue A variable object, the one to be used for the cell value
// returns A DOM element with the matrix in it, which has a .refresh() function.
//
// Options:
// cellFunction(td, x, y, value) fill the TD element of a single cell
// xDecreasing set true for x axis to be in decreasing order.
// yDecreasing set true for y axis to be in decreasing order.
// set_x array of X values to be define initial rows (order irrelevant)
// set_y array of Y values to be define initial columns
//
// Features:
// Header row at top (x axis) and left (y-axis) generated automatically.
// Extra rows and columns are inserted as needed to hold new data points
// matrix.refresh() will re-run the query and adjust the display
import * as utils from '../utils';
import * as $rdf from 'rdflib';
import { solidLogicSingleton } from 'solid-logic';
const kb = solidLogicSingleton.store;
export function matrixForQuery(dom, query, vx, vy, vvalue, options, whenDone) {
// @@ TODO Remove need to cast to any
const matrix = dom.createElement('table');
const header = dom.createElement('tr');
const corner = header.appendChild(dom.createElement('td'));
corner.setAttribute('class', 'MatrixCorner');
matrix.appendChild(header); // just one for now
matrix.lastHeader = header; // Element before data
let columns = []; // Vector
const rows = []; // Associative array
const setCell = function (cell, x, y, value) {
while (cell.firstChild) {
// Empty any previous
cell.removeChild(cell.firstChild);
}
cell.setAttribute('style', '');
cell.style.textAlign = 'center';
if (options.cellFunction) {
options.cellFunction(cell, x, y, value);
}
else {
cell.textContent = utils.label(value);
cell.setAttribute('style', 'padding: 0.3em');
}
delete cell.old;
};
const rowFor = function (y1) {
const y = y1.toNT();
if (rows[y])
return rows[y];
// @@ TODO Remove need for casting to any
const tr = dom.createElement('tr');
const header = tr.appendChild(dom.createElement('td'));
header.setAttribute('style', 'padding: 0.3em;');
header.textContent = utils.label(y1); // first approximation
if (y1.termType === 'NamedNode') {
kb.fetcher.nowOrWhenFetched(y1.uri.split('#')[0], undefined, function (ok, _body, _response) {
if (ok)
header.textContent = utils.label(y1);
});
}
for (let i = 0; i < columns.length; i++) {
setCell(tr.appendChild(dom.createElement('td')), $rdf.fromNT(columns[i]), y1, null);
}
tr.dataValueNT = y;
rows[y] = tr;
for (let ele = matrix.lastHeader.nextSibling; ele; ele = ele.nextSibling) {
// skip header
if ((y > ele.dataValueNT && options && options.yDecreasing) ||
(y < ele.dataValueNT && !(options && options.yDecreasing))) {
return matrix.insertBefore(tr, ele); // return the tr
}
}
return matrix.appendChild(tr); // return the tr
};
const columnNumberFor = function (x1) {
const xNT = x1.toNT(); // xNT is a NT string
let col = null;
// These are data columns (not headings)
for (let i = 0; i < columns.length; i++) {
if (columns[i] === xNT) {
return i;
}
if ((xNT > columns[i] && options.xDecreasing) ||
(xNT < columns[i] && !options.xDecreasing)) {
columns = columns
.slice(0, i)
.concat([xNT])
.concat(columns.slice(i));
col = i;
break;
}
}
if (col === null) {
col = columns.length;
columns.push(xNT);
}
// col is the number of the new column, starting from 0
for (let row = matrix.firstChild; row; row = row.nextSibling) {
// For every row header or not
const y = row.dataValueNT;
const td = dom.createElement('td'); // Add a new cell
td.style.textAlign = 'center';
if (row === matrix.firstChild) {
td.textContent = utils.label(x1);
}
else {
setCell(td, x1, $rdf.fromNT(y), null);
}
if (col === columns.length - 1) {
row.appendChild(td);
}
else {
let t = row.firstChild;
for (let j = 0; j < col + 1; j++) {
// Skip header col too
t = t.nextSibling;
}
row.insertBefore(td, t);
}
}
return col;
};
const markOldCells = function () {
for (let i = 1; i < matrix.children.length; i++) {
const row = matrix.children[i];
for (let j = 1; j < row.children.length; j++) {
row.children[j].old = true;
}
}
};
const clearOldCells = function () {
let row, cell;
const colsUsed = [];
const rowsUsed = [];
if (options.set_y) {
// Knows y values create rows
for (let k = 0; k < options.set_y.length; k++) {
rowsUsed[options.set_y[k]] = true;
}
}
if (options.set_x) {
for (let k = 0; k < options.set_x.length; k++) {
colsUsed[columnNumberFor(options.set_x[k]) + 1] = true;
}
}
for (let i = 1; i < matrix.children.length; i++) {
row = matrix.children[i];
for (let j = 1; j < row.children.length; j++) {
cell = row.children[j];
if (cell.old) {
const y = $rdf.fromNT(row.dataValueNT);
const x = $rdf.fromNT(columns[j - 1]);
setCell(cell, x, y, null);
}
else {
rowsUsed[row.dataValueNT] = true;
colsUsed[j] = true;
}
}
}
for (let i = 0; i < matrix.children.length; i++) {
row = matrix.children[i];
if (i > 0 && !rowsUsed[row.dataValueNT]) {
delete rows[row.dataValueNT];
matrix.removeChild(row);
}
else {
for (let j = row.children.length - 1; j > 0; j--) {
// backwards
const cell = row.children[j];
if (!colsUsed[j]) {
row.removeChild(cell);
}
}
}
}
const newcolumns = [];
for (let j = 0; j < columns.length; j++) {
if (colsUsed[j + 1]) {
newcolumns.push(columns[j]);
}
}
columns = newcolumns;
};
matrix.refresh = function () {
markOldCells();
kb.query(query, addCellFromBindings, undefined, clearOldCells);
};
const addCellFromBindings = function (bindings) {
const x = bindings[vx.toString()];
const y = bindings[vy.toString()];
const value = bindings[(vvalue.toString())];
const row = rowFor(y);
const colNo = columnNumberFor(x);
const cell = row.children[colNo + 1]; // number of Y axis headings
setCell(cell, x, y, value);
};
if (options.set_y) {
// Knows y values create rows
for (let k = 0; k < options.set_y.length; k++) {
rowFor(options.set_y[k]);
}
}
if (options.set_x) {
for (let k = 0; k < options.set_x.length; k++) {
columnNumberFor(options.set_x[k]);
}
}
kb.query(query, addCellFromBindings, undefined, whenDone); // Populate the matrix
return matrix;
}
//# sourceMappingURL=matrix.js.map