Skip to content

Commit

Permalink
Merge pull request #139 from jpmorganchase/hypergrid3
Browse files Browse the repository at this point in the history
Hypergrid 3
  • Loading branch information
texodus authored Jun 30, 2018
2 parents 0d95d6a + 497c026 commit 922f152
Show file tree
Hide file tree
Showing 16 changed files with 725 additions and 1,445 deletions.
35 changes: 22 additions & 13 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ auto-save-list
tramp
.\#*

# npm lock file
package-lock.json

# Intellij/WebStorm IDE
/.idea

# Visual Studio Code configuration
/jsconfig.json

# Org-mode
.org-id-locations
*_archive
Expand Down Expand Up @@ -91,16 +100,16 @@ ftpsync.settings
Gemfile
Gemfile.lock
Vagrantfile
packages/sigma
packages/perspective/obj
package-lock.json
jsconfig.json

\.DS_Store

website/translated_docs
website/build/
website/yarn.lock
website/node_modules
website/i18n/*
!website/i18n/en.json
/packages/sigma
/packages/perspective/obj
/packages/perspective/src/include/boost
/packages/fin-hypergrid

.DS_Store

website/translated_docs
website/build/
website/yarn.lock
website/node_modules
website/i18n/*
!website/i18n/en.json
3 changes: 2 additions & 1 deletion packages/perspective-viewer-highcharts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"build": "npm run highcharts",
"build_test": "cp test/html/* build && webpack --config test/config/highcharts.config.js",
"test": "jest --silent --runInBand 2>&1",
"clean": "find build -mindepth 1 -delete"
"clean": "find build -mindepth 1 -delete",
"clean:screenshots": "find screenshots/ -name *.diff.png -o -name *.failed.png -mindepth 1 -delete"
},
"jest": {
"roots": [
Expand Down
8 changes: 6 additions & 2 deletions packages/perspective-viewer-hypergrid/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"build": "npm run hypergrid",
"build_test": "cp test/html/* build && webpack --config test/config/hypergrid.config.js",
"test": "jest --silent --runInBand 2>&1",
"clean": "find build -mindepth 1 -delete"
"clean": "find build -mindepth 1 -delete",
"clean:screenshots": "find screenshots/ -name *.diff.png -o -name *.failed.png -mindepth 1 -delete"
},
"jest": {
"roots": [
Expand All @@ -37,7 +38,10 @@
"@jpmorganchase/perspective-viewer": "^0.1.15",
"babel-polyfill": "^6.26.0",
"babel-runtime": "^6.26.0",
"fin-hypergrid": "2.0.2",
"datasaur-local": "github:fin-hypergrid/datasaur-local#3.0.0",
"fin-hypergrid": "github:fin-hypergrid/core#alpha",
"fin-hypergrid-grouped-header-plugin": "^1.1.2",
"rectangular": "1.0.1",
"underscore": "^1.8.3"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/******************************************************************************
*
* Copyright (c) 2017, the Perspective Authors.
*
* This file is part of the Perspective library, distributed under the terms of
* the Apache License 2.0. The full license can be found in the LICENSE file.
*
*/

'use strict';

const rectangular = require('rectangular');

const Range = require('./Range');

function getSubrects() {
let range = Range.estimate(this.grid);
range.end_row = Math.min(range.end_row, this.grid.behavior.dataModel.getRowCount());
if (!this.dataWindow) {
return []
}
var dw = this.dataWindow;
var rect = this.grid.newRectangle(dw.left, Math.min(dw.top, range.start_row), dw.width, Math.max(dw.height, range.end_row)); // convert from InclusiveRect
return [rect];
}

function CachedRendererPlugin(grid) {

async function update_cache() {
return await new Promise(resolve => {
const rects = getSubrects.call(grid.renderer)
grid.behavior.dataModel.fetchData(rects, val => resolve(!val));
});
}

grid.canvas._paintNow = grid.canvas.paintNow;

grid.canvas.resize = async function() {
var box = this.size = this.getDivBoundingClientRect(),
width = this.width = Math.round(box.width),
height = this.height = Math.round(box.height),
ratio = 1,
isHIDPI = window.devicePixelRatio && this.component.properties.useHiDPI;

if (isHIDPI) {
var devicePixelRatio = window.devicePixelRatio || 1;
var backingStoreRatio = this.gc.webkitBackingStorePixelRatio ||
this.gc.mozBackingStorePixelRatio ||
this.gc.msBackingStorePixelRatio ||
this.gc.oBackingStorePixelRatio ||
this.gc.backingStorePixelRatio || 1;

ratio = devicePixelRatio / backingStoreRatio;
}

this.bounds = new rectangular.Rectangle(0, 0, width, height);
this.component.setBounds(this.bounds);
this.resizeNotification();

let render = await update_cache();

if (render) {
this.buffer.width = this.canvas.width = width * ratio;
this.buffer.height = this.canvas.height = height * ratio;

this.canvas.style.width = this.buffer.style.width = width + 'px';
this.canvas.style.height = this.buffer.style.height = height + 'px';

this.bc.scale(ratio, ratio);
if (isHIDPI && !this.component.properties.useBitBlit) {
this.gc.scale(ratio, ratio);
}

grid.canvas._paintNow();
}
};

grid.canvas.paintNow = async function() {
let render = await update_cache();
if (render) {
grid.canvas._paintNow();
}
};

}


module.exports = CachedRendererPlugin;
105 changes: 105 additions & 0 deletions packages/perspective-viewer-hypergrid/src/js/PerspectiveDataModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/******************************************************************************
*
* Copyright (c) 2017, the Perspective Authors.
*
* This file is part of the Perspective library, distributed under the terms of
* the Apache License 2.0. The full license can be found in the LICENSE file.
*
*/

const Range = require('./Range');

const TREE_COLUMN_INDEX = require('fin-hypergrid/src/behaviors/Behavior').prototype.treeColumnIndex;

module.exports = require('datasaur-local').extend('PerspectiveDataModel', {

isTreeCol: function (x) {
return x === TREE_COLUMN_INDEX && this.isTree();
},

getValue: function (x, y) {
var row = this.data[y];
return row ? row[x] : null;
},

getRowCount: function () {
return this._nrows || 0;
},

setRowCount: function (count) {
this._nrows = count || 0;
},

isTree: function () {
return this._isTree;
},

setIsTree: function (isTree) {
this._isTree = isTree;
},


fetchData: function (rectangles, resolve) {
if (!rectangles.find(uncachedRow, this)) {
resolve(false);
return;
}

this.data.length = 0;

const promises = rectangles.map(
rect => this.pspFetch(Range.create(rect.origin.y, rect.corner.y + 2))
);

Promise.all(promises).then(() => {
resolve(false);
}).catch(() => {
resolve(true);
});
},

getCell: function (config, rendererName) {
var nextRow, depthDelta;
if (config.isUserDataArea) {
cellStyle.call(this, config, rendererName);
} else if (config.dataCell.x === TREE_COLUMN_INDEX) {
nextRow = this.getRow(config.dataCell.y + 1);
depthDelta = nextRow ? config.value.rowPath.length - nextRow[TREE_COLUMN_INDEX].rowPath.length : -1;
config.last = depthDelta !== 0;
config.expanded = depthDelta < 0;
config._type = this.schema[-1].type[config.value.rowPath.length - 2];
}
return config.grid.cellRenderers.get(rendererName);
},

pspFetch: async function() {}
});

function uncachedRow(rect) {
for (var r = rect.origin.y, R = Math.min(rect.corner.y + 2, this.getRowCount()); r < R; ++r) {
if (!this.data[r]) {
return true;
}
}
}

function cellStyle(gridCellConfig) {
if (gridCellConfig.value === null || gridCellConfig.value === undefined) {
gridCellConfig.value = '-';
} else {
const type = this.schema[gridCellConfig.dataCell.x].type;
if (['number', 'float', 'integer'].indexOf(type) > -1) {
if (gridCellConfig.value === 0) {
gridCellConfig.value = type === 'float' ? '0.00' : '0';
} else if (isNaN(gridCellConfig.value)) {
gridCellConfig.value = '-';
} else {
gridCellConfig.color = gridCellConfig.value >= 0
? (gridCellConfig.columnHeaderBackgroundNumberPositive || 'rgb(160,207,255)')
: (gridCellConfig.columnHeaderBackgroundNumberNegative || 'rgb(255,136,136)');
}
} else if (type === 'boolean') {
gridCellConfig.value = String(gridCellConfig.value);
}
}
}
103 changes: 103 additions & 0 deletions packages/perspective-viewer-hypergrid/src/js/Range.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/******************************************************************************
*
* Copyright (c) 2017, the Perspective Authors.
*
* This file is part of the Perspective library, distributed under the terms of
* the Apache License 2.0. The full license can be found in the LICENSE file.
*
*/

/**
* @constructor
* @returns
*/
function Range() {}

/**
* Creates a new {@link Range} and sets it's start and end rows.
* @param start_row
* @param end_row
*/
Range.create = function(start_row, end_row) {
var range = new Range;
range.reset(start_row, end_row);
return range;
};

/**
* Creates a new {@link Range} and sets it to the estimated range of the given `grid` + `padding`.
* @param grid
* @param padding
*/
Range.estimate = function(grid) {
var range = new Range;
range.estimatedGridRange(grid);
return range;
};

/**
* How many rows to pad the cache by.
* @todo This should really be calculated from the parameters of the theme.
*/
Range.padding = 5;

/**
* @constructor
* @param {number} start_row
* @param {number} end_row
* @returns
*/
Range.prototype.reset = function(start_row, end_row) {
this.start_row = start_row;
this.end_row = end_row;
};

/**
* Estimate the visible range of rows of a Hypergrid based on:
* * Index of top visible row; and
* * Number of rows that can fit in the canvas based at its current height
*
* This calculation assumes all rows have the default row height.
* If any of the rows are taller than the default, this will be an overestimate, which is fine.
* (If on the other hand the average row height of the visible rows is _less_ than the default,
* this will be an underestimate, which would be a problem.)
* @param {Hypergrid} grid
* @returns
*/
Range.prototype.estimatedGridRange = function(grid) {
var start_row = grid.renderer.getScrollTop(),
row_count = Math.ceil(grid.canvas.height / grid.properties.defaultRowHeight),
end_row = start_row + row_count + Range.padding;

this.reset(start_row, end_row);
};

/**
* @returns {boolean} Range is invalid.
*/
Range.prototype.isInvalid = function() {
return Number.isNaN(this.start_row) || Number.isNaN(this.end_row);
};

/**
* The estimated range is within the given range.
* @param {number[]} [range]
* @returns {boolean}
*/
Range.prototype.within = function(range) {
return range instanceof Range &&
range.start_row <= this.start_row &&
this.end_row <= range.end_row;
};

/**
* The estimated range contains the given range.
* @param {number[]} [range]
* @returns {boolean}
*/
Range.prototype.contains = function(range) {
return range instanceof Range && range.within(this);
};


module.exports = Range;
Loading

0 comments on commit 922f152

Please sign in to comment.