Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hypergrid3 #139

Merged
merged 4 commits into from
Jun 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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