Skip to content

Commit

Permalink
feat: Add status bar (#10)
Browse files Browse the repository at this point in the history
Co-authored-by: David Kouril <[email protected]>
Co-authored-by: Etowah Adams <[email protected]>
  • Loading branch information
3 people authored Jul 5, 2024
1 parent dfac1f1 commit 2ca3aac
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 6 deletions.
3 changes: 2 additions & 1 deletion .zed/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"!typescript-language-server",
"!vtsls",
"!eslint"
]
],
"format_on_save": "off"
}
}
}
25 changes: 25 additions & 0 deletions lib/clients/DataTable.css
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,28 @@ tr:first-child td {
background-color: var(--white);
user-select: none;
}

.status-bar {
position: absolute;
right: 0;
font-family: var(--sans-serif);
margin-right: 20px;
margin-top: 5px;
}

.status-bar button {
border: none;
background-color: var(--white);
color: var(--primary);
font-weight: 600;
font-size: 0.875rem;
cursor: pointer;
margin-right: 10px;
}

.status-bar span {
color: var(--gray);
font-weight: 400;
font-size: 0.75rem;
font-variant-numeric: tabular-nums;
}
10 changes: 10 additions & 0 deletions lib/clients/DataTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Histogram } from "./Histogram.ts";
import { ValueCounts } from "./ValueCounts.ts";

import stylesString from "./DataTable.css?raw";
import { StatusBar } from "./StatusBar.ts";

interface DataTableOptions {
table: string;
Expand Down Expand Up @@ -175,6 +176,15 @@ export class DataTable extends MosaicClient {
fieldInfo(infos: Array<Info>) {
let classes = classof(this.#meta.schema);

{
let statusBar = new StatusBar({
table: this.#meta.table,
filterBy: this.filterBy,
});
this.coordinator.connect(statusBar);
this.#shadowRoot.appendChild(statusBar.node());
}

// @deno-fmt-ignore
this.#templateRow = html`<tr><td></td>${
infos.map((info) => html.fragment`<td class=${classes[info.column]}></td>`)
Expand Down
3 changes: 1 addition & 2 deletions lib/clients/Histogram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export class Histogram extends MosaicClient implements Mark {
#source: { table: string; column: string; type: "number" | "date" };
#el: HTMLElement = document.createElement("div");
#channels: Array<Channel> = [];
#markSet: Set<unknown> = new Set();
#interval: mplot.Interval1D | undefined = undefined;
#initialized: boolean = false;
#fieldInfo: boolean = false;
Expand Down Expand Up @@ -67,6 +66,7 @@ export class Histogram extends MosaicClient implements Mark {
selection: this.filterBy,
field: this.#source.column,
brush: undefined,
peers: false,
});
}
}
Expand Down Expand Up @@ -176,7 +176,6 @@ export class Histogram extends MosaicClient implements Mark {
getAttribute(_name: string) {
return undefined;
},
markSet: this.#markSet,
};
}
}
Expand Down
82 changes: 82 additions & 0 deletions lib/clients/StatusBar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import * as arrow from "apache-arrow";
// @deno-types="../deps/mosaic-core.d.ts"
import { type Interactor, MosaicClient, Selection } from "@uwdata/mosaic-core";
// @deno-types="../deps/mosaic-sql.d.ts"
import { count, Query } from "@uwdata/mosaic-sql";

interface StatusBarOptions {
table: string;
filterBy?: Selection;
}

export class StatusBar extends MosaicClient {
#table: string;
#el = document.createElement("div");
#button: HTMLButtonElement;
#span: HTMLSpanElement;
#totalRows: number | undefined = undefined;

constructor(options: StatusBarOptions) {
super(options.filterBy);
this.#table = options.table;
this.#button = document.createElement("button");
this.#button.innerText = "Reset";
this.#span = document.createElement("span");

let div = document.createElement("div");
div.appendChild(this.#button);
div.appendChild(this.#span);
this.#el.appendChild(div);
this.#el.classList.add("status-bar");

this.#button.addEventListener("mousedown", () => {
if (!this.filterBy) return;
// TODO: A better way to do this?
// We want to clear all the existing selections
// @see https://github.com/uwdata/mosaic/blob/8e63149753e7d6ca30274c032a04744e14df2fd6/packages/core/src/Selection.js#L265-L272
for (let { source } of this.filterBy.clauses) {
if (!isInteractor(source)) {
console.warn("Skipping non-interactor source", source);
continue;
}
source.reset();
this.filterBy.update(source.clause());
}
});
}

query(filter = []) {
let query = Query.from(this.#table)
.select({ count: count() })
.where(filter);
return query;
}

queryResult(table: arrow.Table<{ count: arrow.Int }>) {
let count = Number(table.get(0)?.count ?? 0);
if (!this.#totalRows) {
// we need to know the total number of rows to display
this.#totalRows = count;
}
let countStr = count.toLocaleString();
if (count == this.#totalRows) {
this.#span.innerText = `${countStr} rows`;
} else {
let totalStr = this.#totalRows.toLocaleString();
this.#span.innerText = `${countStr} of ${totalStr} rows`;
}
return this;
}

node() {
return this.#el;
}
}

function isObject(x: unknown): x is Record<string, unknown> {
return typeof x === "object" && x !== null && !Array.isArray(x);
}

function isInteractor(x: unknown): x is Interactor {
return isObject(x) && "clause" in x && "reset" in x;
}
19 changes: 17 additions & 2 deletions lib/clients/ValueCounts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @deno-types="../deps/mosaic-core.d.ts";
import { MosaicClient, type Selection } from "@uwdata/mosaic-core";
import { clausePoint, MosaicClient, type Selection } from "@uwdata/mosaic-core";
// @deno-types="../deps/mosaic-sql.d.ts";
import {
column,
Expand All @@ -10,8 +10,10 @@ import {
sum,
} from "@uwdata/mosaic-sql";
import type * as arrow from "apache-arrow";
import { effect } from "@preact/signals-core";

import { ValueCountsPlot } from "../utils/ValueCountsPlot.ts";
import { assert } from "../utils/assert.ts";

interface UniqueValuesOptions {
/** The table to query. */
Expand All @@ -26,14 +28,23 @@ export class ValueCounts extends MosaicClient {
#table: string;
#column: string;
#el: HTMLElement = document.createElement("div");
#plot: HTMLElement | undefined;
#plot: ReturnType<typeof ValueCountsPlot> | undefined;

constructor(options: UniqueValuesOptions) {
super(options.filterBy);
this.#table = options.table;
this.#column = options.column;
}

clause(value?: unknown) {
return clausePoint(this.#column, value, { source: this });
}

reset() {
assert(this.#plot, "ValueCounts plot not initialized");
this.#plot.selected.value = undefined;
}

query(filter: Array<SQLExpression>): Query {
let valueCounts = Query
.select({
Expand Down Expand Up @@ -67,6 +78,10 @@ export class ValueCounts extends MosaicClient {
if (!this.#plot) {
this.#plot = ValueCountsPlot(data);
this.#el.appendChild(this.#plot);
effect(() => {
let clause = this.clause(this.#plot!.selected.value);
this.filterBy?.update(clause);
});
}
return this;
}
Expand Down
21 changes: 21 additions & 0 deletions lib/deps/mosaic-core.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,24 @@
import type { Query } from "@uwdata/mosaic-sql";
import type * as arrow from "apache-arrow";

export interface Interactor<T = unknown> {
reset(): void;
clause(update?: T): Clause<Interactor>;
}

export interface Clause<Source> {
source: Source;
clients: Set<MosaicClient>;
predicate: unknown;
value: unknown;
schema: Record<string, unknown>;
}

export class Selection {
predicate(client: MosaicClient): Array<unknown>;
static crossfilter(): Selection;
clauses: Array<Clause<Interactor>>;
update(clause: Clause<unknown>): void;
}

/** Represents a request for information for a column from the coordinator */
Expand Down Expand Up @@ -102,3 +117,9 @@ export class Coordinator {
type Logger = typeof console & {
groupEnd(name?: string): void;
};

export declare function clausePoint<T>(
field: string,
value: unknown,
options: { source: T },
): Clause<T>;
2 changes: 1 addition & 1 deletion lib/utils/ValueCountsPlot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export function ValueCountsPlot(
root.appendChild(container);
root.appendChild(text);
root.appendChild(hitArea);
return root;
return Object.assign(root, { selected });
}

function createBar(opts: {
Expand Down

0 comments on commit 2ca3aac

Please sign in to comment.