mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-16 05:28:12 -07:00
kibo: database: part 2
This commit is contained in:
@@ -1607,7 +1607,7 @@
|
||||
</main>
|
||||
<aside id="aside">
|
||||
<div id="charts" hidden></div>
|
||||
<div id="database" hidden></div>
|
||||
<div id="table" hidden></div>
|
||||
<div id="simulation" hidden></div>
|
||||
</aside>
|
||||
<div id="share-div" hidden>
|
||||
|
||||
@@ -21,11 +21,11 @@ const importSignals = import("./v0.2.4-treeshaked/script.js").then(
|
||||
(compute, effect) => {
|
||||
let dispose = /** @type {VoidFunction | null} */ (null);
|
||||
// @ts-ignore
|
||||
_signals.createEffect(compute, (v) => {
|
||||
_signals.createEffect(compute, (v, oldV) => {
|
||||
dispose?.();
|
||||
signals.createRoot((_dispose) => {
|
||||
dispose = _dispose;
|
||||
effect(v);
|
||||
return effect(v, oldV);
|
||||
});
|
||||
signals.onCleanup(() => dispose?.());
|
||||
});
|
||||
|
||||
@@ -223,7 +223,7 @@ function createUtils() {
|
||||
* @param {Object} arg
|
||||
* @param {string | HTMLElement} arg.inside
|
||||
* @param {string} arg.title
|
||||
* @param {VoidFunction} arg.onClick
|
||||
* @param {(event: MouseEvent) => void} arg.onClick
|
||||
*/
|
||||
createButtonElement({ inside: text, onClick, title }) {
|
||||
const button = window.document.createElement("button");
|
||||
@@ -438,47 +438,62 @@ function createUtils() {
|
||||
};
|
||||
},
|
||||
/**
|
||||
* @param {Object} param0
|
||||
* @param {string} param0.name
|
||||
* @param {string} param0.value
|
||||
* @template {string} Name
|
||||
* @template {string} Value
|
||||
* @template {Value | {name: Name; value: Value}} T
|
||||
* @param {T} arg
|
||||
*/
|
||||
createOption({ name, value }) {
|
||||
createOption(arg) {
|
||||
const option = window.document.createElement("option");
|
||||
option.value = value;
|
||||
option.innerText = name;
|
||||
if (typeof arg === "object") {
|
||||
option.value = arg.value;
|
||||
option.innerText = arg.name;
|
||||
} else {
|
||||
option.value = arg;
|
||||
option.innerText = arg;
|
||||
}
|
||||
return option;
|
||||
},
|
||||
/**
|
||||
* @template {string} Name
|
||||
* @template {string} Value
|
||||
* @template {{name: Name; value: Value}} T
|
||||
* @template {Value | {name: Name; value: Value}} T
|
||||
* @param {Object} args
|
||||
* @param {string} args.id
|
||||
* @param {string} [args.id]
|
||||
* @param {boolean} [args.deep]
|
||||
* @param {(({name: Name; value: Value} & T) | {name: string; list: ({name: Name; value: Value} & T)[]})[]} args.list
|
||||
* @param {readonly ((T) | {name: string; list: T[]})[]} args.list
|
||||
* @param {Signal<T>} args.signal
|
||||
*/
|
||||
createSelect({ id, list, signal, deep = false }) {
|
||||
const select = window.document.createElement("select");
|
||||
select.name = id;
|
||||
select.id = id;
|
||||
|
||||
if (id) {
|
||||
select.name = id;
|
||||
select.id = id;
|
||||
}
|
||||
|
||||
/** @type {Record<string, VoidFunction>} */
|
||||
const setters = {};
|
||||
|
||||
list.forEach((anyOption, index) => {
|
||||
if ("list" in anyOption) {
|
||||
if (typeof anyOption === "object" && "list" in anyOption) {
|
||||
const { name, list } = anyOption;
|
||||
const optGroup = window.document.createElement("optgroup");
|
||||
optGroup.label = name;
|
||||
select.append(optGroup);
|
||||
list.forEach((option) => {
|
||||
optGroup.append(this.createOption(option));
|
||||
setters[option.value] = () => signal.set(() => option);
|
||||
const key = /** @type {string} */ (
|
||||
typeof option === "object" ? option.value : option
|
||||
);
|
||||
setters[key] = () => signal.set(() => option);
|
||||
});
|
||||
} else {
|
||||
select.append(this.createOption(anyOption));
|
||||
setters[anyOption.value] = () => signal.set(() => anyOption);
|
||||
const key = /** @type {string} */ (
|
||||
typeof anyOption === "object" ? anyOption.value : anyOption
|
||||
);
|
||||
setters[key] = () => signal.set(() => anyOption);
|
||||
}
|
||||
if (deep && index !== list.length - 1) {
|
||||
select.append(window.document.createElement("hr"));
|
||||
@@ -493,7 +508,10 @@ function createUtils() {
|
||||
}
|
||||
});
|
||||
|
||||
select.value = signal().value;
|
||||
const initialSignal = signal();
|
||||
const initialValue =
|
||||
typeof initialSignal === "object" ? initialSignal.value : initialSignal;
|
||||
select.value = String(initialValue);
|
||||
|
||||
return { select, signal };
|
||||
},
|
||||
@@ -706,7 +724,7 @@ function createUtils() {
|
||||
id.includes("ohlc")
|
||||
) {
|
||||
unit = "USD";
|
||||
} else if (id.includes("count")) {
|
||||
} else if (id.includes("count") || id.match(/v[1-3]/g)) {
|
||||
unit = "Count";
|
||||
} else if (id.includes("date")) {
|
||||
unit = "Date";
|
||||
@@ -720,7 +738,7 @@ function createUtils() {
|
||||
unit = "WU";
|
||||
} else if (id.includes("vbytes") || id.includes("vsize")) {
|
||||
unit = "vB";
|
||||
} else if (id.includes("version") || id.match(/v[1-3]/g)) {
|
||||
} else if (id.includes("version")) {
|
||||
unit = "Version";
|
||||
} else if (id === "value") {
|
||||
unit = "Sats";
|
||||
@@ -839,6 +857,20 @@ function createUtils() {
|
||||
return v;
|
||||
},
|
||||
},
|
||||
vecIds: {
|
||||
/**
|
||||
* @param {VecId[]} v
|
||||
*/
|
||||
serialize(v) {
|
||||
return v.join(",");
|
||||
},
|
||||
/**
|
||||
* @param {string} v
|
||||
*/
|
||||
deserialize(v) {
|
||||
return /** @type {VecId[]} */ (v.split(","));
|
||||
},
|
||||
},
|
||||
number: {
|
||||
/**
|
||||
* @param {number} v
|
||||
@@ -1273,7 +1305,16 @@ function createVecsResources(signals, utils) {
|
||||
return {
|
||||
url: utils.api.genUrl(index, id, from),
|
||||
fetched,
|
||||
async fetch() {
|
||||
/**
|
||||
* Defaults
|
||||
* - from: -10_000
|
||||
* - to: undefined
|
||||
*
|
||||
* @param {Object} [args]
|
||||
* @param {number} [args.from]
|
||||
* @param {number} [args.to]
|
||||
*/
|
||||
async fetch(args) {
|
||||
if (loading) return fetched();
|
||||
if (at) {
|
||||
const diff = new Date().getTime() - at.getTime();
|
||||
@@ -1288,7 +1329,8 @@ function createVecsResources(signals, utils) {
|
||||
},
|
||||
index,
|
||||
id,
|
||||
from,
|
||||
args?.from ?? from,
|
||||
args?.to,
|
||||
)
|
||||
);
|
||||
at = new Date();
|
||||
@@ -1381,7 +1423,7 @@ function getElements() {
|
||||
selectors: getElementById("frame-selectors"),
|
||||
style: getComputedStyle(window.document.documentElement),
|
||||
charts: getElementById("charts"),
|
||||
database: getElementById("database"),
|
||||
table: getElementById("table"),
|
||||
simulation: getElementById("simulation"),
|
||||
};
|
||||
}
|
||||
@@ -1956,7 +1998,7 @@ function main() {
|
||||
undefined
|
||||
);
|
||||
let firstTimeLoadingChart = true;
|
||||
let firstTimeLoadingDatabase = true;
|
||||
let firstTimeLoadingTable = true;
|
||||
let firstTimeLoadingSimulation = true;
|
||||
|
||||
signals.createEffect(options.selected, (option) => {
|
||||
@@ -2008,13 +2050,13 @@ function main() {
|
||||
|
||||
break;
|
||||
}
|
||||
case "database": {
|
||||
element = elements.database;
|
||||
case "table": {
|
||||
element = elements.table;
|
||||
|
||||
if (firstTimeLoadingDatabase) {
|
||||
const databaseScript = import("./database.js");
|
||||
utils.dom.importStyleAndThen("/styles/database.css", () =>
|
||||
databaseScript.then(({ init }) =>
|
||||
if (firstTimeLoadingTable) {
|
||||
const tableScript = import("./table.js");
|
||||
utils.dom.importStyleAndThen("/styles/table.css", () =>
|
||||
tableScript.then(({ init }) =>
|
||||
signals.runWithOwner(owner, () =>
|
||||
init({
|
||||
colors,
|
||||
@@ -2022,13 +2064,14 @@ function main() {
|
||||
signals,
|
||||
utils,
|
||||
vecsResources,
|
||||
option,
|
||||
vecIdToIndexes,
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
firstTimeLoadingDatabase = false;
|
||||
firstTimeLoadingTable = false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -63,13 +63,13 @@
|
||||
*
|
||||
* @typedef {Required<Omit<PartialChartOption, "top" | "bottom">> & ProcessedChartOptionAddons & ProcessedOptionAddons} ChartOption
|
||||
*
|
||||
* @typedef {Object} PartialDatabaseOptionSpecific
|
||||
* @property {"database"} kind
|
||||
* @typedef {Object} PartialTableOptionSpecific
|
||||
* @property {"table"} kind
|
||||
* @property {string} title
|
||||
*
|
||||
* @typedef {PartialOption & PartialDatabaseOptionSpecific} PartialDatabaseOption
|
||||
* @typedef {PartialOption & PartialTableOptionSpecific} PartialTableOption
|
||||
*
|
||||
* @typedef {Required<PartialDatabaseOption> & ProcessedOptionAddons} DatabaseOption
|
||||
* @typedef {Required<PartialTableOption> & ProcessedOptionAddons} TableOption
|
||||
*
|
||||
* @typedef {Object} PartialSimulationOptionSpecific
|
||||
* @property {"simulation"} kind
|
||||
@@ -88,9 +88,9 @@
|
||||
*
|
||||
* @typedef {Required<PartialUrlOption> & ProcessedOptionAddons} UrlOption
|
||||
*
|
||||
* @typedef {PartialChartOption | PartialDatabaseOption | PartialSimulationOption | PartialUrlOption} AnyPartialOption
|
||||
* @typedef {PartialChartOption | PartialTableOption | PartialSimulationOption | PartialUrlOption} AnyPartialOption
|
||||
*
|
||||
* @typedef {ChartOption | DatabaseOption | SimulationOption | UrlOption} Option
|
||||
* @typedef {ChartOption | TableOption | SimulationOption | UrlOption} Option
|
||||
*
|
||||
* @typedef {Object} PartialOptionsGroup
|
||||
* @property {string} name
|
||||
@@ -187,17 +187,18 @@ function createPartialOptions(colors) {
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {VecIdSumBase & TotalVecIdBase} args.concat
|
||||
* @param {string} [args.name]
|
||||
*/
|
||||
function createSumTotalSeries({ concat }) {
|
||||
function createSumTotalSeries({ concat, name }) {
|
||||
return /** @satisfies {AnyFetchedSeriesBlueprint[]} */ ([
|
||||
{
|
||||
key: `${concat}-sum`,
|
||||
title: "Sum",
|
||||
title: name ? `${name} Sum` : "Sum",
|
||||
color: colors.bitcoin,
|
||||
},
|
||||
{
|
||||
key: `total-${concat}`,
|
||||
title: "Total",
|
||||
title: name ? `Total ${name}` : "Total",
|
||||
color: colors.offBitcoin,
|
||||
defaultActive: false,
|
||||
},
|
||||
@@ -439,41 +440,42 @@ function createPartialOptions(colors) {
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Version",
|
||||
tree: [
|
||||
{
|
||||
name: "1",
|
||||
title: "Transaction V1 Count",
|
||||
bottom: [
|
||||
createBaseSeries({
|
||||
key: "tx-v1",
|
||||
name: "Count",
|
||||
}),
|
||||
...createSumTotalSeries({ concat: "tx-v1" }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "2",
|
||||
title: "Transaction V2 Count",
|
||||
bottom: [
|
||||
createBaseSeries({
|
||||
key: "tx-v2",
|
||||
name: "Count",
|
||||
}),
|
||||
...createSumTotalSeries({ concat: "tx-v2" }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "3",
|
||||
title: "Transaction V3 Count",
|
||||
bottom: [
|
||||
createBaseSeries({
|
||||
key: "tx-v3",
|
||||
name: "Count",
|
||||
}),
|
||||
...createSumTotalSeries({ concat: "tx-v3" }),
|
||||
],
|
||||
},
|
||||
name: "Versions",
|
||||
title: "Transaction Versions",
|
||||
bottom: [
|
||||
// {
|
||||
// name: "1",
|
||||
// title: "Transaction V1 Count",
|
||||
// bottom: [
|
||||
createBaseSeries({
|
||||
key: "tx-v1",
|
||||
name: "v1 Count",
|
||||
}),
|
||||
...createSumTotalSeries({ concat: "tx-v1", name: "v1" }),
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// name: "2",
|
||||
// title: "Transaction V2 Count",
|
||||
// bottom: [
|
||||
createBaseSeries({
|
||||
key: "tx-v2",
|
||||
name: "v2 Count",
|
||||
}),
|
||||
...createSumTotalSeries({ concat: "tx-v2", name: "v2" }),
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// name: "3",
|
||||
// title: "Transaction V3 Count",
|
||||
// bottom: [
|
||||
createBaseSeries({
|
||||
key: "tx-v3",
|
||||
name: "v3 Count",
|
||||
}),
|
||||
...createSumTotalSeries({ concat: "tx-v3", name: "v3" }),
|
||||
// ],
|
||||
// },
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -529,9 +531,9 @@ function createPartialOptions(colors) {
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: "database",
|
||||
title: "Database",
|
||||
name: "Database",
|
||||
kind: "table",
|
||||
title: "Table",
|
||||
name: "Table",
|
||||
},
|
||||
{
|
||||
name: "Simulations",
|
||||
@@ -875,8 +877,8 @@ export function initOptions({
|
||||
/** @type {Option} */
|
||||
let option;
|
||||
|
||||
if ("kind" in anyPartial && anyPartial.kind === "database") {
|
||||
option = /** @satisfies {DatabaseOption} */ ({
|
||||
if ("kind" in anyPartial && anyPartial.kind === "table") {
|
||||
option = /** @satisfies {TableOption} */ ({
|
||||
kind: anyPartial.kind,
|
||||
id: anyPartial.kind,
|
||||
name: anyPartial.name,
|
||||
|
||||
@@ -3,22 +3,36 @@
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {VecIdToIndexes} args.vecIdToIndexes
|
||||
* @param {Option} args.option
|
||||
* @param {Utilities} args.utils
|
||||
* @param {Signals} args.signals
|
||||
* @param {VecsResources} args.vecsResources
|
||||
*/
|
||||
function createTable({ utils, vecIdToIndexes, signals, vecsResources }) {
|
||||
function createTable({
|
||||
utils,
|
||||
vecIdToIndexes,
|
||||
signals,
|
||||
option,
|
||||
vecsResources,
|
||||
}) {
|
||||
const indexToVecIds = createIndexToVecIds(vecIdToIndexes);
|
||||
|
||||
const serializedIndexes = createSerializedIndexes();
|
||||
/** @type {SerializedIndex} */
|
||||
const defaultSerializedIndex = "height";
|
||||
const serializedIndex = signals.createSignal({
|
||||
name: /** @type {SerializedIndex} */ (defaultSerializedIndex),
|
||||
value: String(serializedIndexToIndex(defaultSerializedIndex)),
|
||||
});
|
||||
/** @type {Signal<SerializedIndex>} */
|
||||
const serializedIndex = signals.createSignal(
|
||||
/** @type {SerializedIndex} */ (defaultSerializedIndex),
|
||||
{
|
||||
save: {
|
||||
...utils.serde.string,
|
||||
keyPrefix: "table",
|
||||
key: "index",
|
||||
},
|
||||
},
|
||||
);
|
||||
const index = signals.createMemo(() =>
|
||||
serializedIndexToIndex(serializedIndex().name),
|
||||
serializedIndexToIndex(serializedIndex()),
|
||||
);
|
||||
|
||||
const table = window.document.createElement("table");
|
||||
@@ -28,21 +42,35 @@ function createTable({ utils, vecIdToIndexes, signals, vecsResources }) {
|
||||
addRandomCol: undefined,
|
||||
};
|
||||
|
||||
signals.createEffect(index, (index) => {
|
||||
table.innerHTML = "";
|
||||
signals.createEffect(index, (index, prevIndex) => {
|
||||
if (prevIndex !== undefined) {
|
||||
utils.url.resetParams(option);
|
||||
}
|
||||
|
||||
const possibleVecIds = indexToVecIds[index];
|
||||
|
||||
const columns = signals.createSignal(/** @type {VecId[]} */ ([]), {
|
||||
equals: false,
|
||||
save: {
|
||||
...utils.serde.vecIds,
|
||||
keyPrefix: `table-${serializedIndex()}`,
|
||||
key: `columns`,
|
||||
},
|
||||
});
|
||||
columns.set((l) => l.filter((id) => possibleVecIds.includes(id)));
|
||||
|
||||
signals.createEffect(columns, (columns) => {
|
||||
console.log(columns);
|
||||
});
|
||||
|
||||
table.innerHTML = "";
|
||||
const thead = window.document.createElement("thead");
|
||||
table.append(thead);
|
||||
const trHead = window.document.createElement("tr");
|
||||
const selects = signals.createSignal(
|
||||
/** @type {HTMLSelectElement[]} */ ([]),
|
||||
{
|
||||
equals: false,
|
||||
},
|
||||
);
|
||||
thead.append(trHead);
|
||||
const tbody = window.document.createElement("tbody");
|
||||
table.append(tbody);
|
||||
|
||||
const rowElements = signals.createSignal(
|
||||
/** @type {HTMLTableRowElement[]} */ ([]),
|
||||
);
|
||||
@@ -50,11 +78,12 @@ function createTable({ utils, vecIdToIndexes, signals, vecsResources }) {
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {HTMLSelectElement} args.select
|
||||
* @param {VoidFunction} [args.onLeft]
|
||||
* @param {VoidFunction} [args.onRight]
|
||||
* @param {VoidFunction} [args.onRemove]
|
||||
* @param {Unit} [args.unit]
|
||||
* @param {(event: MouseEvent) => void} [args.onLeft]
|
||||
* @param {(event: MouseEvent) => void} [args.onRight]
|
||||
* @param {(event: MouseEvent) => void} [args.onRemove]
|
||||
*/
|
||||
function addThCol({ select, onLeft, onRight, onRemove }) {
|
||||
function addThCol({ select, onLeft, onRight, onRemove, unit: _unit }) {
|
||||
const th = window.document.createElement("th");
|
||||
th.scope = "col";
|
||||
trHead.append(th);
|
||||
@@ -62,6 +91,9 @@ function createTable({ utils, vecIdToIndexes, signals, vecsResources }) {
|
||||
div.append(select);
|
||||
const strip = window.document.createElement("div");
|
||||
const unit = window.document.createElement("span");
|
||||
if (_unit) {
|
||||
unit.innerHTML = _unit;
|
||||
}
|
||||
const moveLeft = utils.dom.createButtonElement({
|
||||
inside: "←",
|
||||
title: "Move column to the left",
|
||||
@@ -94,22 +126,24 @@ function createTable({ utils, vecIdToIndexes, signals, vecsResources }) {
|
||||
};
|
||||
}
|
||||
|
||||
const { select } = utils.dom.createSelect({
|
||||
id: "col-index",
|
||||
list: serializedIndexes.map((serializedIndex) => ({
|
||||
name: serializedIndex,
|
||||
value: String(serializedIndexToIndex(serializedIndex)),
|
||||
})),
|
||||
signal: serializedIndex,
|
||||
addThCol({
|
||||
...utils.dom.createSelect({
|
||||
list: serializedIndexes,
|
||||
signal: serializedIndex,
|
||||
}),
|
||||
unit: "Index",
|
||||
});
|
||||
const th = addThCol({ select });
|
||||
th.setUnit("Index");
|
||||
|
||||
let from = 0;
|
||||
let to = 0;
|
||||
|
||||
vecsResources
|
||||
.getOrCreate(index, serializedIndex().name)
|
||||
.getOrCreate(index, serializedIndex())
|
||||
.fetch()
|
||||
.then((vec) => {
|
||||
if (!vec) return;
|
||||
from = /** @type {number} */ (vec[0]);
|
||||
to = /** @type {number} */ (vec.at(-1)) + 1;
|
||||
const trs = /** @type {HTMLTableRowElement[]} */ ([]);
|
||||
for (let i = vec.length - 1; i >= 0; i--) {
|
||||
const value = vec[i];
|
||||
@@ -117,184 +151,182 @@ function createTable({ utils, vecIdToIndexes, signals, vecsResources }) {
|
||||
trs.push(tr);
|
||||
tbody.append(tr);
|
||||
const th = window.document.createElement("th");
|
||||
th.innerHTML = String(value);
|
||||
th.innerHTML = serializeValue({
|
||||
value,
|
||||
unit: "Index",
|
||||
});
|
||||
th.scope = "row";
|
||||
tr.append(th);
|
||||
}
|
||||
rowElements.set(() => trs);
|
||||
});
|
||||
|
||||
const columnIds = signals.createSignal(/** @type {VecId[]} */ ([]), {
|
||||
equals: false,
|
||||
});
|
||||
|
||||
const owner = signals.getOwner();
|
||||
|
||||
const possibleVecids = indexToVecIds[index];
|
||||
|
||||
obj.addRandomCol = function () {
|
||||
/**
|
||||
* @param {VecId} vecId
|
||||
* @param {number} [_colIndex]
|
||||
*/
|
||||
function addCol(vecId, _colIndex = columns().length) {
|
||||
signals.runWithOwner(owner, () => {
|
||||
const vecId =
|
||||
possibleVecids[Math.round(Math.random() * possibleVecids.length)];
|
||||
const colIndex = signals.createSignal(columnIds().length);
|
||||
/** @type {VoidFunction | undefined} */
|
||||
let dispose;
|
||||
signals.createRoot((_dispose) => {
|
||||
dispose = _dispose;
|
||||
|
||||
const vecIdOption = signals.createSignal({
|
||||
name: vecId,
|
||||
value: vecId,
|
||||
});
|
||||
const { select } = utils.dom.createSelect({
|
||||
id: `col-${colIndex() + 1}`,
|
||||
list: possibleVecids.map((vecId) => ({
|
||||
const vecIdOption = signals.createSignal({
|
||||
name: vecId,
|
||||
value: vecId,
|
||||
})),
|
||||
signal: vecIdOption,
|
||||
});
|
||||
selects.set((l) => {
|
||||
l.push(select);
|
||||
return l;
|
||||
});
|
||||
/**
|
||||
* @param {boolean} right
|
||||
*/
|
||||
function createMoveColumnFunction(right) {
|
||||
return () =>
|
||||
colIndex.set((oldI) => {
|
||||
const newI = oldI + (right ? 1 : -1);
|
||||
const currentSelect = selects()[oldI];
|
||||
const currentSelectSibling = currentSelect.nextSibling;
|
||||
const newSelect = selects()[newI];
|
||||
[selects()[oldI], selects()[newI]] = [
|
||||
selects()[newI],
|
||||
selects()[oldI],
|
||||
];
|
||||
console.log(oldI, newI, selects());
|
||||
const newSelectSibling = newSelect.nextSibling;
|
||||
newSelectSibling?.before(currentSelect);
|
||||
currentSelectSibling?.before(newSelect);
|
||||
return newI;
|
||||
});
|
||||
}
|
||||
const th = addThCol({
|
||||
select,
|
||||
onLeft: createMoveColumnFunction(false),
|
||||
onRight: createMoveColumnFunction(true),
|
||||
});
|
||||
});
|
||||
const { select } = utils.dom.createSelect({
|
||||
list: possibleVecIds.map((vecId) => ({
|
||||
name: vecId,
|
||||
value: vecId,
|
||||
})),
|
||||
signal: vecIdOption,
|
||||
});
|
||||
|
||||
signals.createEffect(rowElements, (rowElements) => {
|
||||
if (!rowElements.length) return;
|
||||
for (let i = 0; i < rowElements.length; i++) {
|
||||
const td = window.document.createElement("td");
|
||||
rowElements[i].append(td);
|
||||
}
|
||||
|
||||
signals.createEffect(vecIdOption, ({ name: vecId }) => {
|
||||
const unit = utils.vecidToUnit(vecId);
|
||||
th.setUnit(unit);
|
||||
|
||||
const valuesPromise = vecsResources
|
||||
.getOrCreate(index, vecId)
|
||||
.fetch();
|
||||
|
||||
columnIds.set((l) => {
|
||||
if (columnIds().length === colIndex()) {
|
||||
l.push(vecId);
|
||||
} else {
|
||||
l[colIndex()] = vecId;
|
||||
}
|
||||
console.log(l);
|
||||
if (_colIndex === columns().length) {
|
||||
columns.set((l) => {
|
||||
l.push(vecId);
|
||||
return l;
|
||||
});
|
||||
}
|
||||
|
||||
valuesPromise.then((vec) => {
|
||||
if (!vec) return;
|
||||
// const diff = vec.length - rowElements.length;
|
||||
for (let i = 0; i < rowElements.length; i++) {
|
||||
const iRev = vec.length - 1 - i;
|
||||
const value = vec[iRev];
|
||||
const colIndex = signals.createSignal(_colIndex);
|
||||
|
||||
/** @type {string | number | undefined} */
|
||||
let serialized;
|
||||
/**
|
||||
* @param {boolean} right
|
||||
* @returns {(event: MouseEvent) => void}
|
||||
*/
|
||||
function createMoveColumnFunction(right) {
|
||||
return () => {
|
||||
const oldColIndex = colIndex();
|
||||
const newColIndex = oldColIndex + (right ? 1 : -1);
|
||||
|
||||
if (typeof value !== "number") {
|
||||
serialized = value;
|
||||
} else if (value !== 18446744073709552000) {
|
||||
if (
|
||||
unit === "USD" ||
|
||||
unit === "Difficulty" ||
|
||||
unit === "sat/vB"
|
||||
) {
|
||||
serialized = value.toLocaleString("en-us", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
} else if (unit === "BTC") {
|
||||
serialized = value.toLocaleString("en-us", {
|
||||
minimumFractionDigits: 8,
|
||||
maximumFractionDigits: 8,
|
||||
});
|
||||
} else {
|
||||
serialized = value.toLocaleString("en-us");
|
||||
}
|
||||
}
|
||||
const currentTh = /** @type {HTMLTableCellElement} */ (
|
||||
trHead.childNodes[oldColIndex + 1]
|
||||
);
|
||||
const oterTh = /** @type {HTMLTableCellElement} */ (
|
||||
trHead.childNodes[newColIndex + 1]
|
||||
);
|
||||
|
||||
signals.runWithOwner(owner, () => {
|
||||
signals.createEffect(colIndex, (colIndex) => {
|
||||
// @ts-ignore
|
||||
rowElements[i].childNodes[colIndex + 1].innerHTML =
|
||||
serialized;
|
||||
});
|
||||
});
|
||||
if (right) {
|
||||
oterTh.after(currentTh);
|
||||
} else {
|
||||
oterTh.before(currentTh);
|
||||
}
|
||||
});
|
||||
|
||||
columns.set((l) => {
|
||||
[l[oldColIndex], l[newColIndex]] = [
|
||||
l[newColIndex],
|
||||
l[oldColIndex],
|
||||
];
|
||||
return l;
|
||||
});
|
||||
|
||||
const rows = rowElements();
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
const element = rows[i].childNodes[oldColIndex + 1];
|
||||
const sibling = rows[i].childNodes[newColIndex + 1];
|
||||
const temp = element.textContent;
|
||||
element.textContent = sibling.textContent;
|
||||
sibling.textContent = temp;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const th = addThCol({
|
||||
select,
|
||||
unit: utils.vecidToUnit(vecId),
|
||||
onLeft: createMoveColumnFunction(false),
|
||||
onRight: createMoveColumnFunction(true),
|
||||
onRemove: () => {
|
||||
const ci = colIndex();
|
||||
trHead.childNodes[ci + 1].remove();
|
||||
columns.set((l) => {
|
||||
l.splice(ci, 1);
|
||||
return l;
|
||||
});
|
||||
const rows = rowElements();
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
rows[i].childNodes[ci + 1].remove();
|
||||
}
|
||||
dispose?.();
|
||||
},
|
||||
});
|
||||
|
||||
signals.createEffect(columns, () => {
|
||||
colIndex.set(Array.from(trHead.children).indexOf(th.element) - 1);
|
||||
});
|
||||
|
||||
console.log(colIndex());
|
||||
|
||||
signals.createEffect(rowElements, (rowElements) => {
|
||||
if (!rowElements.length) return;
|
||||
for (let i = 0; i < rowElements.length; i++) {
|
||||
const td = window.document.createElement("td");
|
||||
rowElements[i].append(td);
|
||||
}
|
||||
|
||||
signals.createEffect(
|
||||
() => vecIdOption().name,
|
||||
(vecId, prevVecId) => {
|
||||
const unit = utils.vecidToUnit(vecId);
|
||||
th.setUnit(unit);
|
||||
|
||||
const vec = vecsResources.getOrCreate(index, vecId);
|
||||
|
||||
vec.fetch({ from, to });
|
||||
|
||||
columns.set((l) => {
|
||||
const i = l.indexOf(prevVecId ?? vecId);
|
||||
if (i === -1) {
|
||||
l.push(vecId);
|
||||
} else {
|
||||
l[i] = vecId;
|
||||
}
|
||||
return l;
|
||||
});
|
||||
|
||||
signals.createEffect(vec.fetched, (vec) => {
|
||||
if (!vec) return;
|
||||
|
||||
const thIndex = colIndex() + 1;
|
||||
|
||||
for (let i = 0; i < rowElements.length; i++) {
|
||||
const iRev = vec.length - 1 - i;
|
||||
const value = vec[iRev];
|
||||
// @ts-ignore
|
||||
rowElements[i].childNodes[thIndex].innerHTML =
|
||||
serializeValue({
|
||||
value,
|
||||
unit,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return () => vecId;
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// signals.runWithOwner(owner, () => {
|
||||
// const thIndex = thHead.length;
|
||||
// const possibleVecids = indexToVecIds[index()];
|
||||
// const i = Math.round(Math.random() * possibleVecids.length);
|
||||
// const vecId = signals.createSignal({
|
||||
// name: possibleVecids[i],
|
||||
// value: possibleVecids[i],
|
||||
// });
|
||||
// const th = addThCol();
|
||||
// const { select } = utils.dom.createSelect({
|
||||
// id: `col-${vecId}`,
|
||||
// list: possibleVecids.map((vecId) => ({
|
||||
// name: vecId,
|
||||
// value: vecId,
|
||||
// })),
|
||||
// signal: vecId,
|
||||
// });
|
||||
// th.append(select);
|
||||
// signals.createEffect(
|
||||
// () => /** @type {const} */ ([index(), vecId(), rowElements()]),
|
||||
// ([index, vecId, trsBody]) => {
|
||||
// if (!trsBody.length) return;
|
||||
// vecsResources
|
||||
// .getOrCreate(index, vecId.name)
|
||||
// .fetch()
|
||||
// .then((vec) => {
|
||||
// if (!vec) return;
|
||||
// console.log({ vec, trsBody, index });
|
||||
// for (let i = 0; i < vec.length; i++) {
|
||||
// const iRev = vec.length - 1 - i;
|
||||
// const value = vec[iRev];
|
||||
// const td = window.document.createElement("td");
|
||||
// td.innerHTML = String(value);
|
||||
// trsBody[i].append(td);
|
||||
// }
|
||||
// });
|
||||
// },
|
||||
// );
|
||||
// });
|
||||
signals.onCleanup(() => {
|
||||
dispose?.();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
columns().forEach((vecId, colIndex) => addCol(vecId, colIndex));
|
||||
|
||||
obj.addRandomCol = function () {
|
||||
const vecId =
|
||||
possibleVecIds[Math.floor(Math.random() * possibleVecIds.length)];
|
||||
addCol(vecId);
|
||||
};
|
||||
// setTimeout(addCol, 2000);
|
||||
// addRandomCol();
|
||||
// addRandomCol();
|
||||
// addRandomCol();
|
||||
|
||||
return () => index;
|
||||
});
|
||||
|
||||
return obj;
|
||||
@@ -305,6 +337,7 @@ function createTable({ utils, vecIdToIndexes, signals, vecsResources }) {
|
||||
* @param {Colors} args.colors
|
||||
* @param {Signals} args.signals
|
||||
* @param {Utilities} args.utils
|
||||
* @param {Option} args.option
|
||||
* @param {Elements} args.elements
|
||||
* @param {VecsResources} args.vecsResources
|
||||
* @param {VecIdToIndexes} args.vecIdToIndexes
|
||||
@@ -313,13 +346,14 @@ export function init({
|
||||
colors,
|
||||
elements,
|
||||
signals,
|
||||
option,
|
||||
utils,
|
||||
vecsResources,
|
||||
vecIdToIndexes,
|
||||
}) {
|
||||
const parent = elements.database;
|
||||
const parent = elements.table;
|
||||
const { headerElement } = utils.dom.createHeader({
|
||||
title: "Database",
|
||||
title: "Table",
|
||||
});
|
||||
parent.append(headerElement);
|
||||
|
||||
@@ -331,6 +365,7 @@ export function init({
|
||||
utils,
|
||||
vecIdToIndexes,
|
||||
vecsResources,
|
||||
option,
|
||||
});
|
||||
div.append(table.element);
|
||||
|
||||
@@ -458,3 +493,30 @@ function createIndexToVecIds(vecIdToIndexes) {
|
||||
});
|
||||
return indexToVecIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {number | OHLCTuple} args.value
|
||||
* @param {Unit} args.unit
|
||||
*/
|
||||
function serializeValue({ value, unit }) {
|
||||
if (typeof value !== "number") {
|
||||
return String(value);
|
||||
} else if (value !== 18446744073709552000) {
|
||||
if (unit === "USD" || unit === "Difficulty" || unit === "sat/vB") {
|
||||
return value.toLocaleString("en-us", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
} else if (unit === "BTC") {
|
||||
return value.toLocaleString("en-us", {
|
||||
minimumFractionDigits: 8,
|
||||
maximumFractionDigits: 8,
|
||||
});
|
||||
} else {
|
||||
return value.toLocaleString("en-us");
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#database {
|
||||
#table {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -39,6 +39,10 @@
|
||||
padding: 0.25rem 1rem;
|
||||
}
|
||||
|
||||
td {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
th:first-child {
|
||||
padding-left: var(--main-padding);
|
||||
}
|
||||
Reference in New Issue
Block a user