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

Lazy hypergrid #5

Merged
merged 18 commits into from
Jan 7, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Fixed cache population to prevent unnecessary updates.
  • Loading branch information
texodus committed Jan 7, 2018
commit 0a024440333e7db72ce0a5221ec6692885eac45b
37 changes: 0 additions & 37 deletions packages/perspective-viewer-hypergrid/src/js/fixes.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,42 +50,6 @@ export function GridUIFixPlugin(grid) {
this.resizeNotification();
this.paintNow();
}

function is_subrange(sub, sup) {
return !sup || (sup[0] <= sub[0] && sup[1] >= sub[1]);
}

function estimate_range(grid) {
let range = Object.keys(grid.renderer.visibleRowsByDataRowIndex);
return [parseInt(range[0]), parseInt(range[range.length - 1])];
}

grid.canvas._tickPaint = grid.canvas.tickPaint;
grid.canvas.tickPaint = async function (t) {
if (this.component.grid._lazy_load) {
let range = estimate_range(this.component.grid);
if (
this.component.grid._cache_update
&& this.dirty
&& !(this._updating_cache && is_subrange(range, this._updating_cache.range))
) {
this._updating_cache = this.component.grid._cache_update(...range);
this._updating_cache.range = range
await this._updating_cache;
let new_range = estimate_range(this.component.grid);
if (!is_subrange(new_range, range)) {
return;
}
this._cached_range = range;
this._updating_cache = undefined;
this.component.grid.canvas._tickPaint(t);
} else if (is_subrange(range, this._cached_range)) {
this.component.grid.canvas._tickPaint(t);
}
} else {
this.component.grid.canvas._tickPaint(t);
}
}

grid._getGridCellFromMousePoint = grid.getGridCellFromMousePoint;
grid.getGridCellFromMousePoint = function(mouse) {
Expand All @@ -101,7 +65,6 @@ export function GridUIFixPlugin(grid) {
}
};


grid.renderer._paintGridlines = grid.renderer.paintGridlines;
grid.renderer.paintGridlines = function(gc) {
var visibleColumns = this.visibleColumns, C = visibleColumns.length,
Expand Down
100 changes: 81 additions & 19 deletions packages/perspective-viewer-hypergrid/src/js/hypergrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,47 @@ function null_formatter(formatter, null_value = '') {
}
return formatter
}

function is_subrange(sub, sup) {
if (!sup) {
return false;
}
return sup[0] <= sub[0] && sup[1] >= sub[1];
}

function estimate_range(grid) {
let range = Object.keys(grid.renderer.visibleRowsByDataRowIndex);
return [parseInt(range[0]), parseInt(range[range.length - 1]) + 2];
}

function CachedRendererPlugin(grid) {
grid.canvas._paintNow = grid.canvas.paintNow;
grid.canvas.paintNow = async function (t) {
if (this.component.grid._lazy_load) {
let range = estimate_range(this.component.grid);
if (
this.component.grid._cache_update
&& (
(this.component.grid._updating_cache && !is_subrange(range, this.component.grid._updating_cache.range))
|| (!this.component.grid._updating_cache && !is_subrange(range, this.component.grid._cached_range))
)
) {
this.component.grid._updating_cache = this.component.grid._cache_update(...range);
this.component.grid._updating_cache.range = range
let updated = await this.component.grid._updating_cache;
if (updated) {
this.component.grid._updating_cache = undefined;
this.component.grid._cached_range = range;
this.component.grid.canvas._paintNow(t);
}
} else if (is_subrange(range, this.component.grid._cached_range)) {
this.component.grid.canvas._paintNow(t);
}
} else {
this.component.grid.canvas._paintNow(t);
}
}
}

registerElement(TEMPLATE, {

Expand Down Expand Up @@ -530,7 +571,13 @@ registerElement(TEMPLATE, {
host.setAttribute('hidden', true);
this.grid = new Hypergrid(host, { Behavior: Behaviors.JSON });
host.removeAttribute('hidden');
this.grid.installPlugins([GridUIFixPlugin, PerspectiveDataModel, CheckboxTrackingPlugin ]);

this.grid.installPlugins([
GridUIFixPlugin,
PerspectiveDataModel,
CheckboxTrackingPlugin,
CachedRendererPlugin
]);

var grid_properties = generateGridProperties(light_theme_overrides);
grid_properties['showRowNumbers'] = grid_properties['showCheckboxes'] || grid_properties['showRowNumbers'];
Expand Down Expand Up @@ -599,50 +646,65 @@ async function fill_page(view, json, hidden, start_row, end_row) {

const LAZY_THRESHOLD = 10000;

async function grid(div, view, hidden) {
async function grid(div, view, hidden, redraw, task) {

let [nrows, json, schema] = await Promise.all([
view.num_rows(),
view.to_json({end_row: 1}),
view.schema()
]);
let visible_rows = [];

let visible_rows;

if (!this.grid) {
this.grid = document.createElement('perspective-hypergrid');
visible_rows = [0, 0, 100];
} else if (this.grid.grid) {
visible_rows = this.grid.grid.getVisibleRows();
}

json.length = nrows;

let lazy_load = nrows > LAZY_THRESHOLD;
if (lazy_load) {
json = await fill_page(view, json, hidden, visible_rows[1], visible_rows[visible_rows.length - 1] + 2);
} else if (visible_rows.length > 0) {
json = await view.to_json();
json = filter_hidden(hidden, json);

if (!lazy_load) {
json = view.to_json().then(json => filter_hidden(hidden, json));
} else {
json = Promise.resolve(json);
}

if (!(document.contains ? document.contains(this.grid) : false)) {
div.innerHTML = "";
div.appendChild(this.grid);
await new Promise(resolve => setTimeout(resolve));
}

await Promise.resolve();
json = await json;
if (task.cancelled) {
return;
}

this.grid.grid._lazy_load = false;

this.grid.grid._lazy_load = lazy_load;
this.grid.grid._cached_range = undefined;

this.grid.grid._cache_update = async (s, e) => {
json = await fill_page(view, json, hidden, s, e + 10);
let rows = psp2hypergrid(json, schema, s, Math.min(e + 10, nrows), nrows).rows;
rows[0] = this.grid.grid.behavior.dataModel.viewData[0];
this.grid.grid.setData({data: rows});
json = await fill_page(view, json, hidden, s, e);
let new_range = estimate_range(this.grid.grid);
if (is_subrange(new_range, [s, e])) {
let rows = psp2hypergrid(json, schema, s, Math.min(e, nrows), nrows).rows;
rows[0] = this.grid.grid.behavior.dataModel.viewData[0];
this.grid.grid.setData({data: rows});
return true;
} else {
return false;
}
}

this.grid.set_data(json, schema);
this.grid.grid.canvas.resize();
this.grid.grid.canvas.resize();

this.grid.grid._lazy_load = lazy_load;
if (this._updating_cache) {
await this._updating_cache;
}
}

global.registerPlugin("hypergrid", {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ utils.with_server({}, () => {
await page.evaluate(element => element.setAttribute('row-pivots', '["City"]'), viewer);
});

test.capture("resets viewable area when the physical size expands.", async page => {
await set_lazy(page);
await page.click('#config_button');
const viewer = await page.$('perspective-viewer');
await page.evaluate(element => element.setAttribute('row-pivots', '["Category"]'), viewer);
await page.waitForSelector('perspective-viewer:not([updating])');
await page.evaluate(element => element.setAttribute('row-pivots', '[]'), viewer);
await page.click('#config_button');
});
});

});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"superstore.html/sorts by a numeric column.": "2eb4a45b85bedbdd2cef8bb8c712ed5c",
"superstore.html/sorts by an alpha column.": "f99960fb04d633f96a190df6f55ed000",
"superstore.html/displays visible columns.": "95ea7a90e503ed69e4cc87b9f71adbb4",
"superstore.html/resets viewable area when the logical size expands.": "a7933b107656467730a115cec818d625",
"superstore.html/selecting a column does not log a context deleted error.": "2563581d3556c4576745443c8498bea9"
"superstore.html/resets viewable area when the logical size expands.": "6b8f4fa0dc02fe60f6fc14c4c648a66d",
"superstore.html/selecting a column does not log a context deleted error.": "2563581d3556c4576745443c8498bea9",
"superstore.html/resets viewable area when the physical size expands.": "60689232fd5405439ef4d3f2e8dc68e2"
}