Skip to content

Commit

Permalink
feat: autowidth atomic columns
Browse files Browse the repository at this point in the history
  • Loading branch information
skokenes committed Dec 6, 2023
1 parent 77b24b3 commit 48a4a77
Show file tree
Hide file tree
Showing 8 changed files with 338 additions and 110 deletions.
100 changes: 100 additions & 0 deletions packages/malloy-render/src/component/render-result-metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright 2023 Google LLC
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import {DataArray, Explore, Field, Result} from '@malloydata/malloy';
import {valueIsNumber, valueIsString} from './util';

export interface FieldRenderMetadata {
field: Field;
min: number | null;
max: number | null;
minString: string | null;
maxString: string | null;
}

export interface RenderResultMetadata {
fields: Record<string, FieldRenderMetadata>;
}

export function getResultMetadata(result: Result) {
const fieldKeyMap: WeakMap<Field, string> = new WeakMap();
const getFieldKey = (f: Field) => {
if (fieldKeyMap.has(f)) return fieldKeyMap.get(f)!;
const fieldKey = JSON.stringify(f.fieldPath);
fieldKeyMap.set(f, fieldKey);
return fieldKey;
};

const metadata: RenderResultMetadata = {
fields: {},
};

function initFieldMeta(e: Explore) {
for (const f of e.allFields) {
if (f.isAtomicField()) {
const fieldKey = getFieldKey(f);
metadata.fields[fieldKey] = {
field: f,
min: null,
max: null,
minString: null,
maxString: null,
};
} else if (f.isExploreField()) {
initFieldMeta(f);
}
}
}

const populateFieldMeta = (
data: DataArray,
metadata: RenderResultMetadata
) => {
for (const row of data) {
for (const f of data.field.allFields) {
const value = f.isAtomicField() ? row.cell(f).value : undefined;
const fieldKey = getFieldKey(f);
const fieldMeta = metadata.fields[fieldKey];
if (valueIsNumber(f, value)) {
const n = value;
fieldMeta.min = Math.min(fieldMeta.min ?? n, n);
fieldMeta.max = Math.max(fieldMeta.max ?? n, n);
} else if (valueIsString(f, value)) {
const s = value;
if (!fieldMeta.minString || fieldMeta.minString.length > s.length)
fieldMeta.minString = s;
if (!fieldMeta.maxString || fieldMeta.maxString.length < s.length)
fieldMeta.maxString = s;
} else if (f.isExploreField()) {
const data = row.cell(f) as DataArray;
populateFieldMeta(data, metadata);
}
}
}
};

initFieldMeta(result.data.field);
populateFieldMeta(result.data, metadata);

return metadata;
}
22 changes: 20 additions & 2 deletions packages/malloy-render/src/component/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@
*/

import {Result, Tag} from '@malloydata/malloy';
import {LitElement, html, css} from 'lit';
import {LitElement, html, css, PropertyValues} from 'lit';
import {customElement, property} from 'lit/decorators.js';
import './table';
import {provide} from '@lit/context';
import {resultContext} from './result-context';
import {
RenderResultMetadata,
getResultMetadata,
} from './render-result-metadata';

// Get the first valid theme value or fallback to CSS variable
function getThemeValue(prop: string, ...themes: Array<Tag | undefined>) {
Expand Down Expand Up @@ -57,8 +63,9 @@ export class MalloyRender extends LitElement {
--malloy-theme--table-gutter-size: 15px;
--malloy-theme--table-pinned-background: #f5fafc;
--malloy-theme--table-pinned-border: 1px solid #daedf3;
--malloy-theme--font-family: Inter, system-ui, sans-serif;
font-family: Inter, system-ui, sans-serif;
font-family: var(--malloy-render--font-family);
font-size: var(--malloy-render--table-font-size);
}
Expand All @@ -79,6 +86,15 @@ export class MalloyRender extends LitElement {
@property({attribute: false})
result!: Result;

@provide({context: resultContext})
metadata!: RenderResultMetadata;

willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has('result')) {
this.metadata = getResultMetadata(this.result);
}
}

override render() {
const modelTag = this.result.modelTag;
const {tag: resultTag} = this.result.tagParse();
Expand Down Expand Up @@ -136,12 +152,14 @@ export class MalloyRender extends LitElement {
localTheme,
modelTheme
);
const fontFamily = getThemeValue('fontFamily', localTheme, modelTheme);

const dynamicStyle = html`<style>
:host {
--malloy-render--table-row-height: ${tableRowHeight};
--malloy-render--table-body-color: ${tableBodyColor};
--malloy-render--table-font-size: ${tableFontSize};
--malloy-render--font-family: ${fontFamily};
--malloy-render--table-header-color: ${tableHeaderColor};
--malloy-render--table-header-weight: ${tableHeaderWeight};
--malloy-render--table-body-weight: ${tableBodyWeight};
Expand Down
3 changes: 3 additions & 0 deletions packages/malloy-render/src/component/result-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import {createContext} from '@lit/context';

export const resultContext = createContext<any>('malloy-render-result');
Loading

0 comments on commit 48a4a77

Please sign in to comment.