diff --git a/beakerx/beakerx/tabledisplay/tableitems.py b/beakerx/beakerx/tabledisplay/tableitems.py index a216a91504..f858098cf2 100644 --- a/beakerx/beakerx/tabledisplay/tableitems.py +++ b/beakerx/beakerx/tabledisplay/tableitems.py @@ -57,21 +57,27 @@ def __init__(self, x): class DecimalStringFormat: type = "decimal" - minDecimals = 4 - maxDecimals = 4 - def __init__(self, min=4, max=4): - self.minDecimals = min - self.maxDecimals = max + def __init__(self, **kwargs): + self.minDecimals = kwargs.get('min', 4) + self.maxDecimals = kwargs.get('max', 4) class ImageFormat: type = "image" + def __init__(self, **kwargs): + if 'width' in kwargs: + self.width = kwargs.get('width') + class HTMLFormat: type = "html" + def __init__(self, **kwargs): + if 'width' in kwargs: + self.width = kwargs.get('width') + class HighlightStyle(Enum): FULL_ROW = 1 @@ -80,6 +86,7 @@ class HighlightStyle(Enum): class HeatmapHighlighter: type = "HeatmapHighlighter" + def __init__(self, colName, style, minVal, maxVal, minColor, maxColor): self.colName = colName self.style = style.name @@ -98,16 +105,16 @@ def getDataBarsRenderer(include_text=True): class TableDisplayStringFormat: @staticmethod - def getDecimalFormat(min, max): - return DecimalStringFormat(min, max) + def getDecimalFormat(**kwargs): + return DecimalStringFormat(**kwargs) @staticmethod - def getHTMLFormat(): - return HTMLFormat() + def getHTMLFormat(**kwargs): + return HTMLFormat(**kwargs) @staticmethod - def getImageFormat(): - return ImageFormat() + def getImageFormat(**kwargs): + return ImageFormat(**kwargs) class TableDisplayCellHighlighter: FULL_ROW = HighlightStyle.FULL_ROW diff --git a/js/notebook/src/tableDisplay/dataGrid/DataGridResize.ts b/js/notebook/src/tableDisplay/dataGrid/DataGridResize.ts index 3cde906bdd..5eecda46ae 100644 --- a/js/notebook/src/tableDisplay/dataGrid/DataGridResize.ts +++ b/js/notebook/src/tableDisplay/dataGrid/DataGridResize.ts @@ -28,9 +28,11 @@ import {DataGridHelpers} from "./dataGridHelpers"; import {selectColumnWidth} from "./column/selectors"; import getStringSize = DataGridHelpers.getStringSize; import {ALL_TYPES} from "./dataTypes"; +import throttle = DataGridHelpers.throttle; const DEFAULT_RESIZE_SECTION_SIZE_IN_PX = 6; const DEFAULT_ROW_PADDING = 4; +const SCROLLBAR_WIDTH = 16; export class DataGridResize { dataGrid: BeakerXDataGrid; @@ -49,6 +51,7 @@ export class DataGridResize { this.handleMouseMove = this.handleMouseMove.bind(this); this.handleMouseUp = this.handleMouseUp.bind(this); this.fillEmptySpaceResizeFn = this.fillEmptySpaceResizeFn.bind(this); + this.fitVieport = throttle(this.fitVieport, 100, this); this.installMessageHook(); } @@ -76,6 +79,7 @@ export class DataGridResize { updateWidgetHeight(): void { this.dataGrid.node.style.minHeight = `${this.getWidgetHeight()}px`; + this.fitVieport(); } updateWidgetWidth(): void { @@ -83,17 +87,17 @@ export class DataGridResize { const hasVScroll = ( this.dataGrid.rowManager.rowsToShow !== -1 && this.dataGrid.rowManager.rowsToShow <= this.dataGrid.model.rowCount('body') ); - const vScrollWidth = hasVScroll ? this.dataGrid['_vScrollBarMinWidth'] + 1 : 0; + const vScrollWidth = hasVScroll ? SCROLLBAR_WIDTH : 0; const width = this.dataGrid.totalWidth + spacing + vScrollWidth; if (this.resizedHorizontally && width >= this.dataGrid.node.clientWidth) { - this.dataGrid.fit(); + this.fitVieport(); return; } this.dataGrid.node.style.width = `${width}px`; - this.dataGrid.fit(); + this.fitVieport(); } setInitialSectionWidths(): void { @@ -119,6 +123,8 @@ export class DataGridResize { this.dataGrid.columnSections['_sections'].forEach(this.fillEmptySpaceResizeFn('body', value)); this.dataGrid.rowHeaderSections['_sections'].forEach(this.fillEmptySpaceResizeFn('row-header', value)); + + this.fitVieport(); } updateColumnWidth(region: ColumnRegion): Function { @@ -147,7 +153,6 @@ export class DataGridResize { stopResizing() { this.resizing = false; - this.resizeMode = null; this.dataGrid.node.parentElement.removeEventListener('mouseup', this.handleMouseUp, true); document.body.removeEventListener('mousemove', this.handleMouseMove, true); @@ -201,6 +206,10 @@ export class DataGridResize { column.setWidth(value); } + fitVieport() { + this.dataGrid && this.dataGrid.fit(); + } + private fillEmptySpaceResizeFn(region: ColumnRegion, value: number) { return (section) => { let column = this.dataGrid.columnManager.getColumnByPosition({ @@ -337,10 +346,21 @@ export class DataGridResize { } private getSectionWidth(column): number { - if(column.getDisplayType() === ALL_TYPES.image) { - return selectColumnWidth(this.dataGrid.store.state, column); + const fixedWidth = selectColumnWidth(this.dataGrid.store.state, column); + const displayType = column.getDisplayType(); + + if (displayType === ALL_TYPES.image) { + return fixedWidth || 1; } + if (displayType === ALL_TYPES.html && fixedWidth) { + return fixedWidth; + } + + return this.calculateSectionWidth(column); + } + + private calculateSectionWidth(column: DataGridColumn) { const position = column.getPosition(); const value = String(column.formatFn(this.dataGrid.cellManager.createCellConfig({ region: position.region, diff --git a/js/notebook/src/tableDisplay/dataGrid/cell/ImageCellRenderer.ts b/js/notebook/src/tableDisplay/dataGrid/cell/ImageCellRenderer.ts index 0368294633..670c3fbe05 100644 --- a/js/notebook/src/tableDisplay/dataGrid/cell/ImageCellRenderer.ts +++ b/js/notebook/src/tableDisplay/dataGrid/cell/ImageCellRenderer.ts @@ -94,9 +94,10 @@ export default class ImageCellRenderer extends CellRenderer { if (selectColumnWidth(this.dataGrid.store.state, column) < width) { column.dataGrid.dataGridResize.setSectionWidth("column", column, width); - column.dataGrid.dataGridResize.updateWidgetHeight(); column.dataGrid.dataGridResize.updateWidgetWidth(); } + + column.dataGrid.dataGridResize.updateWidgetHeight(); }); } } diff --git a/js/notebook/src/tableDisplay/dataGrid/dataGridHelpers.ts b/js/notebook/src/tableDisplay/dataGrid/dataGridHelpers.ts index df6674ff63..ff2382f8be 100644 --- a/js/notebook/src/tableDisplay/dataGrid/dataGridHelpers.ts +++ b/js/notebook/src/tableDisplay/dataGrid/dataGridHelpers.ts @@ -121,7 +121,7 @@ export namespace DataGridHelpers { limit: number, context = this, controllObject?: { timerId: any } - ): (T) => U|undefined { + ): (T?) => U|undefined { let controll = controllObject || { timerId: undefined }; let lastRan; diff --git a/js/notebook/src/tableDisplay/dataGrid/model/selectors/column.ts b/js/notebook/src/tableDisplay/dataGrid/model/selectors/column.ts index bfc2baa479..7f053308cf 100644 --- a/js/notebook/src/tableDisplay/dataGrid/model/selectors/column.ts +++ b/js/notebook/src/tableDisplay/dataGrid/model/selectors/column.ts @@ -18,10 +18,19 @@ import {createSelector} from "reselect"; import {DataModel} from "@phosphor/datagrid"; import { selectAlignmentByType, - selectAlignmentForColumn, selectAlignmentForType, selectCellHighlighters, + selectAlignmentForColumn, + selectAlignmentForType, + selectCellHighlighters, selectColumnOrder, - selectColumnsFrozen, selectColumnsVisible, selectColumnTypes, selectHasIndex, - selectRawColumnNames, selectRendererForColumn, selectRendererForType + selectColumnsFrozen, + selectColumnsVisible, + selectColumnTypes, + selectHasIndex, + selectRawColumnNames, + selectRendererForColumn, + selectRendererForType, + selectStringFormatForColumn, + selectStringFormatForType } from "./model"; import {getAlignmentByChar} from "../../column/columnAlignment"; import {IColumnPosition} from "../../interface/IColumn"; @@ -191,3 +200,22 @@ export const selectColumnHighlighters = createSelector( highlighter => highlighter.colName === columnName && highlighter.type === highlighterType ) ); + +export const selectColumnFixedWidth: (state, columnName, typeName) => number|null = createSelector([ + selectStringFormatForColumn, + selectStringFormatForType, + (state, columnName) => columnName, + (state, columnName, typeName) => typeName, + ], + (formatForColumns, formatForTypes, columnName, typeName) => { + if (formatForColumns[columnName] && formatForColumns[columnName].width) { + return formatForColumns[columnName].width; + } + + if (formatForTypes[typeName] && formatForTypes[typeName].width) { + return formatForTypes[typeName].width; + } + + return null; + } +); diff --git a/js/notebook/src/tableDisplay/dataGrid/store/BeakerXDataStore.ts b/js/notebook/src/tableDisplay/dataGrid/store/BeakerXDataStore.ts index 7f4d0e6ce6..996c065f4a 100644 --- a/js/notebook/src/tableDisplay/dataGrid/store/BeakerXDataStore.ts +++ b/js/notebook/src/tableDisplay/dataGrid/store/BeakerXDataStore.ts @@ -25,7 +25,10 @@ import { selectHasIndex, selectInitialColumnPositions, selectStringFormatForColumn, - selectStringFormatForType, selectFormatForTimes, DEFAULT_INDEX_COLUMN_NAME, + selectStringFormatForType, + selectFormatForTimes, + DEFAULT_INDEX_COLUMN_NAME, + selectColumnFixedWidth, } from "../model/selectors"; import {BeakerXDataGridModel} from "../model/BeakerXDataGridModel"; import {getDisplayType, getTypeByName} from "../dataTypes"; @@ -69,7 +72,7 @@ export function createInitialColumnsState(initialState: IDataModelState): IColum keepTrigger: columnType === COLUMN_TYPES.index, position: positions[columnType][index], dataTypeName: types[columnType][index], - width: 20, + width: selectColumnFixedWidth(state, name, types[columnType][index]), displayType: getDisplayType( dataType, selectStringFormatForType(state), diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/table/format/HTMLStringFormat.java b/kernel/base/src/main/java/com/twosigma/beakerx/table/format/HTMLStringFormat.java index 04a9ad806f..ffc4febd48 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/table/format/HTMLStringFormat.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/table/format/HTMLStringFormat.java @@ -17,7 +17,20 @@ public class HTMLStringFormat extends TableDisplayStringFormat { + private Integer width; + public HTMLStringFormat() { } + public HTMLStringFormat(Integer width) { + this.width = width; + } + + public Integer getWidth() { + return width; + } + + public void setWidth(Integer width) { + this.width = width; + } } diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/table/format/ImageStringFormat.java b/kernel/base/src/main/java/com/twosigma/beakerx/table/format/ImageStringFormat.java index 0725c8df10..1229e1febb 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/table/format/ImageStringFormat.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/table/format/ImageStringFormat.java @@ -17,6 +17,20 @@ public class ImageStringFormat extends TableDisplayStringFormat { + private Integer width; + public ImageStringFormat() { } + + public ImageStringFormat(Integer width) { + this.width = width; + } + + public Integer getWidth() { + return width; + } + + public void setWidth(Integer width) { + this.width = width; + } } diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/table/format/TableDisplayStringFormat.java b/kernel/base/src/main/java/com/twosigma/beakerx/table/format/TableDisplayStringFormat.java index 4297de95ea..35d7366cd3 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/table/format/TableDisplayStringFormat.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/table/format/TableDisplayStringFormat.java @@ -29,6 +29,11 @@ public static TableDisplayStringFormat getHTMLFormat() { return new HTMLStringFormat(); } + // Get a formatter that shows strings as formatted HTML with specified width + public static TableDisplayStringFormat getHTMLFormat(int width) { + return new HTMLStringFormat(width); + } + // Get a formatter that will show Date in a timestamp format with millisecond precision public static TableDisplayStringFormat getTimeFormat() { return new TimeStringFormat(); @@ -54,4 +59,9 @@ public static TableDisplayStringFormat getImageFormat() { return new ImageStringFormat(); } + // Get a formatter that will show derived source as an image with specified width + public static TableDisplayStringFormat getImageFormat(int width) { + return new ImageStringFormat(width); + } + } diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/table/serializer/HTMLStringFormatSerializer.java b/kernel/base/src/main/java/com/twosigma/beakerx/table/serializer/HTMLStringFormatSerializer.java index 54c53232c8..35af9915db 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/table/serializer/HTMLStringFormatSerializer.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/table/serializer/HTMLStringFormatSerializer.java @@ -27,6 +27,7 @@ public class HTMLStringFormatSerializer extends JsonSerializer public static final String TYPE = "type"; public static final String VALUE_HTML = "html"; + public static final String WIDTH = "width"; @Override public void serialize(HTMLStringFormat value, @@ -37,6 +38,9 @@ public void serialize(HTMLStringFormat value, synchronized (value) { jgen.writeStartObject(); jgen.writeObjectField(TYPE, VALUE_HTML); + if (value.getWidth() != null) { + jgen.writeObjectField(WIDTH, value.getWidth()); + } jgen.writeEndObject(); } } diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/table/serializer/ImageStringFormatSerializer.java b/kernel/base/src/main/java/com/twosigma/beakerx/table/serializer/ImageStringFormatSerializer.java index 225891d381..3967a1fa5f 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/table/serializer/ImageStringFormatSerializer.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/table/serializer/ImageStringFormatSerializer.java @@ -27,6 +27,7 @@ public class ImageStringFormatSerializer extends JsonSerializer