diff --git a/docs/index.html b/docs/index.html
index 9517f0a..bd77c01 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -270,7 +270,7 @@
Outstanding work
console.timeEnd('merge');
-// console.log(table);
+ console.log(table);
// render the table in the target element
document.getElementById('tablan').replaceWith(render.table(table, 'tablan', 'landscape'));
diff --git a/lib/node/index.d.ts b/lib/node/index.d.ts
index 79e37f8..3a75aac 100644
--- a/lib/node/index.d.ts
+++ b/lib/node/index.d.ts
@@ -31,11 +31,11 @@ export declare function table(cube: Cube, axes: Axes(keys: Cube>, axes: Axes, onX: boolean): Array>>;
+export declare function split(cells: Cube>, axes: Axes, onX: boolean): Array>>;
/**
* Merge adjacent cells in a split table on the y and/or x axes.
- * @param table A table of Cells created by a previous call to splitX or splitY.
+ * @param cells A table of Cells created by a previous call to splitX or splitY.
* @param onX A flag to indicate that cells should be merged on the x axis.
* @param onY A flag to indicate that cells should be merged on the y axis.
*/
-export declare function merge(table: Array>>, onX: boolean, onY: boolean): void;
+export declare function merge(cells: Array>>, onX: boolean, onY: boolean): void;
diff --git a/lib/node/index.js b/lib/node/index.js
index 9e69f25..feb4751 100644
--- a/lib/node/index.js
+++ b/lib/node/index.js
@@ -11,9 +11,9 @@ exports.merge = exports.split = exports.table = void 0;
function table(cube, axes, getKey, onX) {
const identity = { index: 0 };
// convert the source data to keys and remove resulting duplicates
- const keys = cube.map(row => row.map(table => table.length ? tableCells(table, getKey, identity) : [{ text: '', style: 'empty', index: [], source: [], rows: 1, cols: 1 }]));
+ const cells = cube.map(row => row.map(table => table.length ? tableCells(table, getKey, identity) : [{ text: '', style: 'empty', index: [], source: [], rows: 1, cols: 1 }]));
// create the resultant table
- return split(keys, axes, onX);
+ return split(cells, axes, onX);
}
exports.table = table;
/**
@@ -22,24 +22,24 @@ exports.table = table;
* @param axes The x and y axes used in the pivot operation to create the cube.
* @param onX A flag to indicate if cells in cube containing multiple values should be split on the x axis (if not, the y axis will be used).
*/
-function split(keys, axes, onX) {
+function split(cells, axes, onX) {
// calcuate the x and y splits required
- const xSplits = axes.x.map((_, iX) => onX ? leastCommonMultiple(keys, row => row[iX].length) : 1);
- const ySplits = keys.map(row => onX ? 1 : leastCommonMultiple(row, table => table.length));
+ const xSplits = axes.x.map((_, iX) => onX ? leastCommonMultiple(cells, row => row[iX].length) : 1);
+ const ySplits = cells.map(row => onX ? 1 : leastCommonMultiple(row, table => table.length));
// iterate and expand the y axis based on the split data
- return expand(keys, ySplits, (row, ySplit, ysi, iY) => {
+ return expand(cells, ySplits, (row, ySplit, ysi, iY) => {
// iterate and expand the x axis based on the split data
- return expand(row, xSplits, (values, xSplit, xsi) => {
+ return expand(row, xSplits, (cell, xSplit, xsi) => {
// generate the cube cells
- return { ...values[Math.floor(values.length * (ysi + xsi) / (xSplit * ySplit))] };
+ return { ...cell[Math.floor(cell.length * (ysi + xsi) / (xSplit * ySplit))] };
// generate the y axis row header cells
}, axes.y[iY].map(criterion => axis(criterion, 'y')));
// generate the x axis column header rows
- }, axes.x[0].map((_, iY) => {
+ }, axes.x[0].map((_, iC) => {
// iterate and expand the x axis
return expand(axes.x, xSplits, xPoint => {
// generate the x axis cells
- return axis(xPoint[iY], 'x');
+ return axis(xPoint[iC], 'x');
// generate the x/y header
}, axes.y[0].map(() => axis({ key: '', value: '' }, 'xy')));
}));
@@ -47,22 +47,22 @@ function split(keys, axes, onX) {
exports.split = split;
/**
* Merge adjacent cells in a split table on the y and/or x axes.
- * @param table A table of Cells created by a previous call to splitX or splitY.
+ * @param cells A table of Cells created by a previous call to splitX or splitY.
* @param onX A flag to indicate that cells should be merged on the x axis.
* @param onY A flag to indicate that cells should be merged on the y axis.
*/
-function merge(table, onX, onY) {
+function merge(cells, onX, onY) {
let next;
- forEachRev(table, (row, iY) => {
- forEachRev(row, (value, iX) => {
- if (onY && iY && (next = table[iY - 1][iX]) && keyEquals(next, value) && next.cols === value.cols) {
- next.rows += value.rows;
- mergeContext(next, value);
+ forEachRev(cells, (row, iY) => {
+ forEachRev(row, (cell, iX) => {
+ if (onY && iY && (next = cells[iY - 1][iX]) && keyEquals(next, cell) && next.cols === cell.cols) {
+ next.rows += cell.rows;
+ mergeContext(next, cell);
row.splice(iX, 1);
}
- else if (onX && iX && (next = row[iX - 1]) && keyEquals(next, value) && next.rows === value.rows) {
- next.cols += value.cols;
- mergeContext(next, value);
+ else if (onX && iX && (next = row[iX - 1]) && keyEquals(next, cell) && next.rows === cell.rows) {
+ next.cols += cell.cols;
+ mergeContext(next, cell);
row.splice(iX, 1);
}
});
@@ -73,11 +73,11 @@ exports.merge = merge;
* Merges the context of two adjacent cells.
* @hidden
*/
-function mergeContext(next, value) {
- value.index.forEach((index, i) => {
+function mergeContext(next, cell) {
+ cell.index.forEach((index, i) => {
if (!next.index.includes(index)) {
next.index.push(index);
- next.source.push(value.source[i]);
+ next.source.push(cell.source[i]);
}
});
}
diff --git a/package.json b/package.json
index 84c3148..68595ec 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@steelbreeze/landscape",
- "version": "3.4.1",
+ "version": "3.4.2",
"description": "Landscape map viewpoint visualisation",
"main": "lib/node/index.js",
"module": "lib/node/index.js",
diff --git a/src/index.old b/src/index.old
deleted file mode 100644
index ed7dee1..0000000
--- a/src/index.old
+++ /dev/null
@@ -1,198 +0,0 @@
-import { Axes, Cube, Func, Pair, Row, Table } from '@steelbreeze/pivot';
-
-/** The final text and class name to use when rendering cells in a table. */
-export interface Key {
- /** The text to use in the final table rendering. */
- text: string;
-
- /** The class name to use in the final table rendering. */
- style: string;
-}
-
-/** An extension of key, adding the number of rows and columns the key will occupy in the final table rendering. */
-export interface Cell extends Key {
- /** Unique keys for the source context. */
- index: Array;
-
- /** The the rows that this this key came from. */
- source: Array;
-
- /** The number of rows to occupy. */
- rows: number;
-
- /** The number of columns to occupy. */
- cols: number;
-}
-
-/**
- * Generates a table from a cube and it's axis.
- * @param cube The source cube.
- * @param axes The x and y axes used in the pivot operation to create the cube.
- * @param getKey A callback to generate a key containing the text and className used in the table from the source records,
- * @param onX A flag to indicate if cells in cube containing multiple values should be split on the x axis (if not, the y axis will be used).
- */
-export function table(cube: Cube, axes: Axes, getKey: Func, onX: boolean): Array>> {
- const identity = { index: 0 };
-
- // convert the source data to keys and remove resulting duplicates
- const cells = cube.map(row => row.map(table => table.length ? tableCells(table, getKey, identity) : [{ text: '', style: 'empty', index: [], source: [], rows: 1, cols: 1 }]));
-
- // create the resultant table
- return split(cells, axes, onX);
-}
-
-/**
- * Splits a cube of keys into a table, creating mutiple rows or columns where a cell in a cube has multiple values.
- * @param cube The source cube.
- * @param axes The x and y axes used in the pivot operation to create the cube.
- * @param onX A flag to indicate if cells in cube containing multiple values should be split on the x axis (if not, the y axis will be used).
- */
-function split(cells: Cube>, axes: Axes, onX: boolean): Array>> {
- // calcuate the x and y splits required
- const xSplits = axes.x.map((_, iX) => onX ? leastCommonMultiple(cells, row => row[iX].length) : 1);
- const ySplits = cells.map(row => onX ? 1 : leastCommonMultiple(row, table => table.length));
-
- // iterate and expand the y axis based on the split data
- return expand(cells, ySplits, (row, ySplit, ysi, iY) => {
-
- // iterate and expand the x axis based on the split data
- return expand(row, xSplits, (table, xSplit, xsi) => {
-
- // generate the cube cells
- return { ...(table[Math.floor(table.length * (ysi + xsi) * ySplit / xSplit)]) }; // NOTE: clone cells from the cube so subsiquent merge operation work
-
- // generate the y axis row header cells
- }, axes.y[iY].map(criterion => axis(criterion, 'y')));
-
- // generate the x axis column header rows
- }, axes.x[0].map((_, iX) => {
-
- // iterate and expand the x axis
- return expand(axes.x, xSplits, x => {
-
- // generate the x axis cells
- return axis(x[iX], 'x');
-
- // generate the x/y header
- }, axes.y[0].map(() => axis({ key: '', value: '' }, 'xy')));
- }));
-}
-
-/**
- * Merge adjacent cells in a split table on the y and/or x axes.
- * @param table A table of Cells created by a previous call to splitX or splitY.
- * @param onX A flag to indicate that cells should be merged on the x axis.
- * @param onY A flag to indicate that cells should be merged on the y axis.
- */
-export function merge(table: Array>>, onX: boolean, onY: boolean): void {
- let next;
-
- forEachRev(table, (row, iY) => {
- forEachRev(row, (value, iX) => {
- if (onY && iY && (next = table[iY - 1][iX]) && keyEquals(next, value) && next.cols === value.cols) {
- next.rows += value.rows;
- mergeContext(next, value);
- row.splice(iX, 1);
- } else if (onX && iX && (next = row[iX - 1]) && keyEquals(next, value) && next.rows === value.rows) {
- next.cols += value.cols;
- mergeContext(next, value);
- row.splice(iX, 1);
- }
- });
- });
-}
-
-/**
- * Merges the context of two adjacent cells.
- * @hidden
- */
-function mergeContext(next: Cell, value: Cell): void {
- value.index.forEach((index, i) => {
- if (!next.index.includes(index)) {
- next.index.push(index);
- next.source.push(value.source[i]);
- }
- });
-}
-
-/**
- * Convert a table of rows into a table of cells.
- * @hidden
- */
-function tableCells(table: Table, getKey: Func, identity: { index: number }): Table> {
- const result: Table> = [];
-
- for (const row of table) {
- const key = getKey(row);
- const cell = result.find(cell => keyEquals(cell, key));
-
- if (cell) {
- cell.index.push(identity.index);
- cell.source.push(row);
- } else {
- result.push({ ...key, index: [identity.index], source: [row], rows: 1, cols: 1 });
- }
-
- identity.index++;
- }
-
- return result;
-}
-
-/**
- * Expands an array using, splitting values into multiple based on a set of corresponding splits then maps the data to a desired structure.
- * @hidden
- */
-function expand(values: TSource[], splits: number[], callbackfn: (value: TSource, split: number, iSplit: number, iValue: number) => TResult, seed: TResult[]): TResult[] {
- values.forEach((value, iValue) => {
- const split = splits[iValue];
-
- for (let iSplit = 0; iSplit < split; ++iSplit) {
- seed.push(callbackfn(value, split, iSplit, iValue));
- }
- });
-
- return seed;
-}
-
-/**
- * A reverse for loop
- * @param hidden
- */
-function forEachRev(values: Array, callbackfn: (value: TValue, index: number) => void): void {
- for (let index = values.length; index--;) {
- callbackfn(values[index], index);
- }
-}
-
-/**
- * Returns the least common multiple of a set of integers generated from an object.
- * @hidden
- */
-function leastCommonMultiple(source: Array, callbackfn: Func): number {
- return source.map(value => callbackfn(value) || 1).reduce((a, b) => (a * b) / greatestCommonFactor(a, b));
-}
-
-/**
- * Returns the greatest common factor of two numbers
- * @hidden
- */
-function greatestCommonFactor(a: number, b: number): number {
- return b ? greatestCommonFactor(b, a % b) : a;
-}
-
-/**
- * Compare two keys for equality
- * @hidden
- */
-function keyEquals(a: Key, b: Key): boolean {
- return a.text === b.text && a.style === b.style;
-}
-
-/**
- * Creates a cell within a table for a column or row heading.
- * @hidden
- */
-function axis(pair: Pair, name: string): Cell {
- return { text: pair.value, style: `axis ${name} ${pair.key}`, index: [], source: [], rows: 1, cols: 1 };
-}
diff --git a/src/index.ts b/src/index.ts
index e31b1fe..cb6c564 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -35,10 +35,10 @@ export function table(cube: Cube, axes: Axes, getK
const identity = { index: 0 };
// convert the source data to keys and remove resulting duplicates
- const keys = cube.map(row => row.map(table => table.length ? tableCells(table, getKey, identity) : [{ text: '', style: 'empty', index: [], source: [], rows: 1, cols: 1 }]));
+ const cells = cube.map(row => row.map(table => table.length ? tableCells(table, getKey, identity) : [{ text: '', style: 'empty', index: [], source: [], rows: 1, cols: 1 }]));
// create the resultant table
- return split(keys, axes, onX);
+ return split(cells, axes, onX);
}
/**
@@ -47,31 +47,31 @@ export function table(cube: Cube, axes: Axes, getK
* @param axes The x and y axes used in the pivot operation to create the cube.
* @param onX A flag to indicate if cells in cube containing multiple values should be split on the x axis (if not, the y axis will be used).
*/
-export function split(keys: Cube>, axes: Axes, onX: boolean): Array>> {
+export function split(cells: Cube>, axes: Axes, onX: boolean): Array>> {
// calcuate the x and y splits required
- const xSplits = axes.x.map((_, iX) => onX ? leastCommonMultiple(keys, row => row[iX].length) : 1);
- const ySplits = keys.map(row => onX ? 1 : leastCommonMultiple(row, table => table.length));
+ const xSplits = axes.x.map((_, iX) => onX ? leastCommonMultiple(cells, row => row[iX].length) : 1);
+ const ySplits = cells.map(row => onX ? 1 : leastCommonMultiple(row, table => table.length));
// iterate and expand the y axis based on the split data
- return expand(keys, ySplits, (row, ySplit, ysi, iY) => {
+ return expand(cells, ySplits, (row, ySplit, ysi, iY) => {
// iterate and expand the x axis based on the split data
- return expand(row, xSplits, (values, xSplit, xsi) => {
+ return expand(row, xSplits, (cell, xSplit, xsi) => {
// generate the cube cells
- return { ...values[Math.floor(values.length * (ysi + xsi) / (xSplit * ySplit))] };
+ return { ...cell[Math.floor(cell.length * (ysi + xsi) / (xSplit * ySplit))] };
// generate the y axis row header cells
}, axes.y[iY].map(criterion => axis(criterion, 'y')));
// generate the x axis column header rows
- }, axes.x[0].map((_, iY) => {
+ }, axes.x[0].map((_, iC) => {
// iterate and expand the x axis
return expand(axes.x, xSplits, xPoint => {
// generate the x axis cells
- return axis(xPoint[iY], 'x');
+ return axis(xPoint[iC], 'x');
// generate the x/y header
}, axes.y[0].map(() => axis({ key: '', value: '' }, 'xy')));
@@ -81,22 +81,22 @@ export function split(keys: Cube>, axes: Axes
/**
* Merge adjacent cells in a split table on the y and/or x axes.
- * @param table A table of Cells created by a previous call to splitX or splitY.
+ * @param cells A table of Cells created by a previous call to splitX or splitY.
* @param onX A flag to indicate that cells should be merged on the x axis.
* @param onY A flag to indicate that cells should be merged on the y axis.
*/
-export function merge(table: Array>>, onX: boolean, onY: boolean): void {
+export function merge(cells: Array>>, onX: boolean, onY: boolean): void {
let next;
- forEachRev(table, (row, iY) => {
- forEachRev(row, (value, iX) => {
- if (onY && iY && (next = table[iY - 1][iX]) && keyEquals(next, value) && next.cols === value.cols) {
- next.rows += value.rows;
- mergeContext(next, value);
+ forEachRev(cells, (row, iY) => {
+ forEachRev(row, (cell, iX) => {
+ if (onY && iY && (next = cells[iY - 1][iX]) && keyEquals(next, cell) && next.cols === cell.cols) {
+ next.rows += cell.rows;
+ mergeContext(next, cell);
row.splice(iX, 1);
- } else if (onX && iX && (next = row[iX - 1]) && keyEquals(next, value) && next.rows === value.rows) {
- next.cols += value.cols;
- mergeContext(next, value);
+ } else if (onX && iX && (next = row[iX - 1]) && keyEquals(next, cell) && next.rows === cell.rows) {
+ next.cols += cell.cols;
+ mergeContext(next, cell);
row.splice(iX, 1);
}
});
@@ -107,11 +107,11 @@ export function merge(table: Array>>, onX: bo
* Merges the context of two adjacent cells.
* @hidden
*/
-function mergeContext(next: Cell, value: Cell): void {
- value.index.forEach((index, i) => {
+function mergeContext(next: Cell, cell: Cell): void {
+ cell.index.forEach((index, i) => {
if (!next.index.includes(index)) {
next.index.push(index);
- next.source.push(value.source[i]);
+ next.source.push(cell.source[i]);
}
});
}
| | | | | | | |