Skip to content

Commit

Permalink
#7335 add image cell renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
Mariusz Jurowicz committed Jul 3, 2018
1 parent 1b69b39 commit c89dbc7
Show file tree
Hide file tree
Showing 14 changed files with 210 additions and 15 deletions.
5 changes: 5 additions & 0 deletions js/notebook/src/tableDisplay/dataGrid/BeakerXDataGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,11 @@ export class BeakerXDataGrid extends DataGrid {
{ dataType: ALL_TYPES[ALL_TYPES.html] },
CellRendererFactory.getRenderer(this, ALL_TYPES.html)
);
this.cellRenderers.set(
'body',
{ dataType: ALL_TYPES[ALL_TYPES.image] },
CellRendererFactory.getRenderer(this, ALL_TYPES.image)
);
this.cellRenderers.set('body', {}, defaultRenderer);
this.cellRenderers.set('column-header', {}, headerCellRenderer);
this.cellRenderers.set('corner-header', {}, headerCellRenderer);
Expand Down
7 changes: 7 additions & 0 deletions js/notebook/src/tableDisplay/dataGrid/DataFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export class DataFormatter {
this.datetime = this.datetime.bind(this);
this.boolean = this.boolean.bind(this);
this.html = this.html.bind(this);
this.rawValue = this.rawValue.bind(this);
}

destroy(): void {
Expand Down Expand Up @@ -107,6 +108,8 @@ export class DataFormatter {
return this.boolean;
case 10:
return this.html;
case 11:
return this.rawValue;

default:
return this.string;
Expand All @@ -127,6 +130,10 @@ export class DataFormatter {
}
}

private rawValue(config: CellRenderer.ICellConfig) {
return config.value;
}

private value(config: CellRenderer.ICellConfig): string {
let columnName = this.columnNames[config.column];

Expand Down
5 changes: 5 additions & 0 deletions js/notebook/src/tableDisplay/dataGrid/DataGridResize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import ColumnRegion = DataModel.ColumnRegion;
import {DataGridHelpers} from "./dataGridHelpers";
import {selectColumnWidth} from "./column/selectors";
import getStringSize = DataGridHelpers.getStringSize;
import {ALL_TYPES} from "./dataTypes";

const DEFAULT_RESIZE_SECTION_SIZE_IN_PX = 6;
const DEFAULT_ROW_PADDING = 4;
Expand Down Expand Up @@ -331,6 +332,10 @@ export class DataGridResize {
}

private getSectionWidth(column): number {
if(column.getDisplayType() === ALL_TYPES.image) {
return selectColumnWidth(this.dataGrid.store.state, column);
}

const position = column.getPosition();
const value = String(column.formatFn(this.dataGrid.cellManager.createCellConfig({
region: position.region,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ export default abstract class BeakerXCellRenderer extends TextRenderer {
this.textColor = this.getTextColor.bind(this);
}

abstract drawText(gc: GraphicsContext, config: CellRenderer.ICellConfig): void

drawBackground(gc: GraphicsContext, config: CellRenderer.ICellConfig) {
super.drawBackground(gc, config);

Expand Down
2 changes: 1 addition & 1 deletion js/notebook/src/tableDisplay/dataGrid/cell/CellManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export default class CellManager {
queryCommandEnabled = false;
}

if (bkUtils.isElectron || !queryCommandEnabled) {
if (!queryCommandEnabled) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ import {ALL_TYPES} from "../dataTypes";
import HTMLCellRenderer from "./HTMLCellRenderer";
import HeaderCellRenderer from "./HeaderCellRenderer";
import DefaultCellRenderer from "./DefaultCellRenderer";
import ImageCellRenderer from "./ImageCellRenderer";

export class CellRendererFactory {
static getRenderer(dataGrid: BeakerXDataGrid, dataType?: ALL_TYPES) {
switch (dataType) {
case ALL_TYPES.html:
return new HTMLCellRenderer(dataGrid);
case ALL_TYPES.image:
return new ImageCellRenderer(dataGrid);
default:
return new DefaultCellRenderer(dataGrid);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,13 @@

import {CellRenderer, GraphicsContext, TextRenderer} from "@phosphor/datagrid";
import BeakerXCellRenderer from "./BeakerXCellRenderer";
import {BeakerXDataGrid} from "../BeakerXDataGrid";

import LatoRegular from '../../../shared/fonts/lato/Lato-Regular.woff';
import LatoBlack from '../../../shared/fonts/lato/Lato-Black.woff';

export default class HTMLCellRenderer extends BeakerXCellRenderer {
dataCache = new Map<string, string>();

constructor(dataGrid: BeakerXDataGrid, options?: TextRenderer.IOptions) {
super(dataGrid, options);
}

drawText(gc: GraphicsContext, config: CellRenderer.ICellConfig): void {
const font = CellRenderer.resolveOption(this.font, config);

Expand Down
100 changes: 100 additions & 0 deletions js/notebook/src/tableDisplay/dataGrid/cell/ImageCellRenderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright 2018 TWO SIGMA OPEN SOURCE, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {CellRenderer, GraphicsContext} from "@phosphor/datagrid";
import {BeakerXDataGrid} from "../BeakerXDataGrid";
import {BeakerXDataStore} from "../store/BeakerXDataStore";
import {DataGridHelpers} from "../dataGridHelpers";
import getBackgroundColor = DataGridHelpers.getBackgroundColor;
import ICellConfig = CellRenderer.ICellConfig;
import ColumnManager from "../column/ColumnManager";
import {selectColumnWidth} from "../column/selectors";

export default class ImageCellRenderer extends CellRenderer {
store: BeakerXDataStore;
dataGrid: BeakerXDataGrid;
backgroundColor: CellRenderer.ConfigOption<string>;

constructor(dataGrid: BeakerXDataGrid) {
super();

this.store = dataGrid.store;
this.dataGrid = dataGrid;
this.backgroundColor = (config: ICellConfig) => getBackgroundColor(this.dataGrid, config);
}

drawBackground(gc: GraphicsContext, config: CellRenderer.ICellConfig): void {
let color = CellRenderer.resolveOption(this.backgroundColor, config);

if (!color) {
return;
}

gc.fillStyle = color;
gc.fillRect(config.x, config.y, config.width, config.height);
}

paint(gc: GraphicsContext, config: CellRenderer.ICellConfig): void {
this.drawBackground(gc, config);
this.drawImage(gc, config);
}

drawImage(gc: GraphicsContext, config: CellRenderer.ICellConfig): void {
if (!config.value) {
return;
}

const img = new Image();
const dpiRatio = this.dataGrid['_dpiRatio'];
const x = config.x * dpiRatio;
const y = config.y * dpiRatio;
const width = config.width * dpiRatio;
const height = config.height * dpiRatio;

gc.setTransform(1, 0, 0, 1, 0, 0);
gc.beginPath();
gc.rect(x, y, width, height - 1);
gc.clip();

img.src = `${config.value}`;

if (!img.complete) {
img.onload = () => {
this.dataGrid.repaint(x, y, img.width, img.height);
}
} else {
this.resizeCell({ ...config }, img.width, img.height);

gc.drawImage(img, x, y);
}
}

resizeCell(config, width, height) {
setTimeout(() => {
const column = this.dataGrid.columnManager.getColumnByPosition(
ColumnManager.createPositionFromCell(config)
);

if (this.dataGrid.sectionSize('row', config.row) < height) {
this.dataGrid.resizeSection('row', config.row, height);
}

if (selectColumnWidth(this.dataGrid.store.state, column) < width) {
column.setWidth(width);
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export default class DataGridColumn {

const position = this.getPosition();

this.setWidth(1);
this.assignFormatFn();
this.recalculateLongestStringValue(displayType);
this.dataGrid.dataGridResize.setInitialSectionWidth({ index: position.value }, position.region);
Expand Down Expand Up @@ -404,7 +405,10 @@ export default class DataGridColumn {
}

recalculateLongestStringValue(displayType: ALL_TYPES|string) {
if (displayType !== ALL_TYPES.string && displayType !== ALL_TYPES.html ) {
if (
displayType !== ALL_TYPES.string
&& displayType !== ALL_TYPES.html
) {
return;
}

Expand Down
6 changes: 4 additions & 2 deletions js/notebook/src/tableDisplay/dataGrid/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
export const scopeData = {
allStringTypes: [
{type: 0, name: 'string'},
{type: 10, name: 'html'}
{type: 10, name: 'html'},
{type: 13, name: 'image'}
],
allTimeTypes: [
{type: 8, name: 'datetime'},
Expand Down Expand Up @@ -50,7 +51,8 @@ export const scopeData = {
{type: 7, name: 'exponential 15'},
{type: 8, name: 'datetime'},
{type: 9, name: 'boolean'},
{type: 10, name: 'html'}
{type: 10, name: 'html'},
{type: 11, name: 'image'}
],
rowsToDisplayMenu: [
[10, 25, 50, 100, -1],
Expand Down
23 changes: 20 additions & 3 deletions js/notebook/src/tableDisplay/dataGrid/dataGridHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
*/

import {SectionList} from "@phosphor/datagrid/lib/sectionlist";
import {DEFAULT_DATA_FONT_SIZE} from "./style/dataGridStyle";
import {darken, DEFAULT_DATA_FONT_SIZE} from "./style/dataGridStyle";
import {KEYBOARD_KEYS} from "./event/enums";
import DataGridColumn from "./column/DataGridColumn";
import * as moment from 'moment-timezone/builds/moment-timezone-with-data';
import {sanitizeHTML} from "../../plot/plotSanitize";
import BeakerXThemeHelper from "../../BeakerXThemeHelper";
import {CellRenderer} from "@phosphor/datagrid";
import {BeakerXDataGrid} from "./BeakerXDataGrid";

export namespace DataGridHelpers {
const urlRegex = /((https?|ftp|file):\/\/)(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[A-Z0-9+&@#/%=~_|$])/i;
Expand Down Expand Up @@ -117,7 +120,7 @@ export namespace DataGridHelpers {
func: Function,
limit: number,
context = this,
controllObject?: { timerId: number }
controllObject?: { timerId: any }
): (T) => U|undefined {
let controll = controllObject || { timerId: undefined };
let lastRan;
Expand All @@ -143,7 +146,7 @@ export namespace DataGridHelpers {
}

export function debounce<A>(f:(a:A) => void, delay: number, controllObject?: { timerId: number }) {
let controll: { timerId: number } = controllObject || { timerId: undefined };
let controll: { timerId: any } = controllObject || { timerId: undefined };

return (a: A) => {
clearTimeout(controll.timerId);
Expand Down Expand Up @@ -211,4 +214,18 @@ export namespace DataGridHelpers {
export function hasUpperCaseLetter(value: string) {
return /[A-Z]+/gm.test(value);
}

export function getBackgroundColor(dataGrid: BeakerXDataGrid, config: CellRenderer.ICellConfig): string {
let selectionColor = dataGrid.cellSelectionManager.getBackgroundColor(config);
let highlighterColor = dataGrid.highlighterManager.getCellBackground(config);
let focusedColor = dataGrid.cellFocusManager.getFocussedCellBackground(config);
let initialColor = selectionColor && highlighterColor && darken(highlighterColor);

return focusedColor && initialColor && darken(initialColor) ||
focusedColor ||
initialColor ||
highlighterColor ||
selectionColor ||
BeakerXThemeHelper.DEFAULT_CELL_BACKGROUND;
}
}
3 changes: 2 additions & 1 deletion js/notebook/src/tableDisplay/dataGrid/dataTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export enum ALL_TYPES {
'boolean',
'html',
'int64',
'time'
'time',
'image',
}

const DEFAULT_DOUBLE_WITH_PRECISION_TYPE = '4.3';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2017 TWO SIGMA OPEN SOURCE, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { expect } from 'chai';
import { BeakerXDataGrid } from "@beakerx/tableDisplay/dataGrid/BeakerXDataGrid";
import {GraphicsContext, CellRenderer} from "@phosphor/datagrid";
import modelStateMock from "../mock/modelStateMock";
import createStore from "@beakerx/tableDisplay/dataGrid/store/BeakerXDataStore";
import ImageCellRenderer from "@beakerx/tableDisplay/dataGrid/cell/ImageCellRenderer";

describe('ImageCellRenderer', () => {
let dataGrid;
let cellRenderer;
let dataStore;
let gc: GraphicsContext;

before(() => {
dataStore = createStore(modelStateMock);
dataGrid = new BeakerXDataGrid({}, dataStore);

gc = new GraphicsContext(dataGrid['_canvasGC']);

gc['_context'].drawImage = () => {};
cellRenderer = new ImageCellRenderer(dataGrid);
});

after(() => {
dataGrid.destroy();
});

it('should be an instance of CellRenderer', () => {
expect(cellRenderer).to.be.an.instanceof(CellRenderer);
});

it('should implement drawImage method', () => {
expect(cellRenderer).to.have.property('drawImage');
expect(cellRenderer.drawImage).to.be.a('Function');
});

it('should implement resizeCell method', () => {
expect(cellRenderer).to.have.property('resizeCell');
expect(cellRenderer.resizeCell).to.be.a('Function');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ describe('dataTypes', () => {
expect(getTypeByName('html')).to.equal(10);
expect(getTypeByName('int64')).to.equal(11);
expect(getTypeByName('time')).to.equal(12);
expect(getTypeByName('image')).to.equal(13);
});
});

Expand Down

0 comments on commit c89dbc7

Please sign in to comment.