@revolist/revogrid
Version:
Virtual reactive data grid spreadsheet component - RevoGrid.
235 lines (234 loc) • 9.64 kB
JavaScript
/*!
* Built by Revolist OU ❤️
*/
import { columnTypes, getSourceItem, getVisibleSourceItem, rowTypes } from "../../store/index";
import { CONTENT_SLOT, FOOTER_SLOT, HEADER_SLOT, viewportDataPartition } from "./viewport.helpers";
/** Collect Column data */
function gatherColumnData(data) {
const colDimension = data.dimensions[data.colType].store;
const realWidth = colDimension.get('realSize');
const prop = {
contentWidth: realWidth,
class: data.colType,
contentHeight: data.contentHeight,
key: data.colType,
colType: data.colType,
noHorizontalScrollTransfer: data.noHorizontalScrollTransfer,
onResizeviewport: data.onResizeviewport,
// set viewport size to real size
style: data.fixWidth ? { minWidth: `${realWidth}px` } : undefined,
};
const headerProp = {
colData: getVisibleSourceItem(data.colStore),
dimensionCol: colDimension,
type: data.colType,
groups: data.colStore.get('groups'),
groupingDepth: data.colStore.get('groupingDepth'),
resizeHandler: data.colType === 'colPinEnd' ? ['l'] : undefined,
onHeaderresize: data.onHeaderresize,
};
return {
prop,
type: data.colType,
position: data.position,
headerProp,
viewportCol: data.viewports[data.colType].store,
};
}
export default class ViewportService {
constructor(config, contentHeight) {
// ----------- Handle columns ----------- //
var _a;
this.config = config;
// Transform data from stores and apply it to different components
const columns = [];
let x = 0; // we increase x only if column present
columnTypes.forEach(val => {
const colStore = config.columnProvider.stores[val].store;
// only columns that have data show
if (!colStore.get('items').length) {
return;
}
const column = {
colType: val,
position: { x, y: 1 },
contentHeight,
// only central column has dynamic width
fixWidth: val !== 'rgCol',
viewports: config.viewportProvider.stores,
dimensions: config.dimensionProvider.stores,
rowStores: config.dataProvider.stores,
noHorizontalScrollTransfer: config.noHorizontalScrollTransfer,
colStore,
onHeaderresize: e => this.onColumnResize(val, e, colStore),
};
if (val === 'rgCol') {
column.onResizeviewport = (e) => {
var _a;
const vpState = {
clientSize: e.detail.size,
};
// virtual size will be handled by dimension provider if disabled
if ((e.detail.dimension === 'rgRow' && !config.disableVirtualY)
|| (e.detail.dimension === 'rgCol' && !config.disableVirtualX)) {
vpState.virtualSize = e.detail.size;
}
(_a = config.viewportProvider) === null || _a === void 0 ? void 0 : _a.setViewport(e.detail.dimension, vpState);
};
}
const colData = gatherColumnData(column);
const columnSelectionStore = this.registerCol(colData.position.x, val);
// render per each column data collections vertically
const dataPorts = this.dataViewPort(column).reduce((r, rgRow) => {
// register selection store for Segment
const segmentSelection = this.registerSegment(rgRow.position, rgRow.lastCell);
// register selection store for Row
const rowSelectionStore = this.registerRow(rgRow.position.y, rgRow.type);
const rowDef = Object.assign(Object.assign({ colType: val }, rgRow), { rowSelectionStore, selectionStore: segmentSelection.store, onSetrange: e => {
segmentSelection.setRangeArea(e.detail);
}, onSettemprange: e => segmentSelection.setTempArea(e.detail), onFocuscell: e => {
// todo: multi focus
segmentSelection.clearFocus();
config.selectionStoreConnector.focus(segmentSelection, e.detail);
} });
r.push(rowDef);
return r;
}, []);
columns.push(Object.assign(Object.assign({}, colData), { columnSelectionStore,
dataPorts }));
x++;
});
this.columns = columns;
// ----------- Handle columns end ----------- //
(_a = this.config.scrollingService) === null || _a === void 0 ? void 0 : _a.unregister();
}
onColumnResize(type, { detail }, store) {
var _a;
// apply to dimension provider
(_a = this.config.dimensionProvider) === null || _a === void 0 ? void 0 : _a.setCustomSizes(type, detail, true);
// set resize event
const changedItems = {};
for (const i of Object.keys(detail || {})) {
const size = detail[i];
const virtualIndex = parseInt(i, 10);
const item = getSourceItem(store, virtualIndex);
if (item) {
changedItems[virtualIndex] = Object.assign(Object.assign({}, item), { size });
}
}
this.config.resize(changedItems);
}
/** register selection store for Segment */
registerSegment(position, lastCell) {
const store = this.config.selectionStoreConnector.register(position);
store.setLastCell(lastCell);
return store;
}
/** register selection store for Row */
registerRow(y, type) {
return this.config.selectionStoreConnector.registerRow(y, type).store;
}
/** register selection store for Column */
registerCol(x, type) {
return this.config.selectionStoreConnector.registerColumn(x, type).store;
}
/** Collect Row data */
dataViewPort(data) {
const slots = {
rowPinStart: HEADER_SLOT,
rgRow: CONTENT_SLOT,
rowPinEnd: FOOTER_SLOT,
};
// y position for selection
let y = 0;
return rowTypes.reduce((result, type) => {
const rgCol = Object.assign(Object.assign({}, data), { position: Object.assign(Object.assign({}, data.position), { y }) });
const partition = viewportDataPartition(rgCol, type, slots[type], type !== 'rgRow');
result.push(partition);
y++;
return result;
}, []);
}
scrollToCell(cell) {
for (let key in cell) {
const coordinate = cell[key];
if (typeof coordinate === 'number') {
this.config.scrollingService.proxyScroll({
dimension: key === 'x' ? 'rgCol' : 'rgRow',
coordinate,
});
}
}
}
/**
* Clear current grid focus
*/
clearFocused() {
this.config.selectionStoreConnector.clearAll();
}
clearEdit() {
this.config.selectionStoreConnector.setEdit(false);
}
/**
* Collect focused element data
*/
getFocused() {
const focused = this.config.selectionStoreConnector.focusedStore;
if (!focused) {
return null;
}
// get column data
const colType = this.config.selectionStoreConnector.storesXToType[focused.position.x];
const column = this.config.columnProvider.getColumn(focused.cell.x, colType);
// get row data
const rowType = this.config.selectionStoreConnector.storesYToType[focused.position.y];
const model = this.config.dataProvider.getModel(focused.cell.y, rowType);
return {
column,
model,
cell: focused.cell,
colType,
rowType,
};
}
getStoreCoordinateByType(colType, rowType) {
const stores = this.config.selectionStoreConnector.storesByType;
if (typeof stores[colType] === 'undefined' || typeof stores[rowType] === 'undefined') {
return;
}
return {
x: stores[colType],
y: stores[rowType],
};
}
setFocus(colType, rowType, start, end) {
var _a;
const coordinate = this.getStoreCoordinateByType(colType, rowType);
if (coordinate) {
(_a = this.config.selectionStoreConnector) === null || _a === void 0 ? void 0 : _a.focusByCell(coordinate, start, end);
}
}
getSelectedRange() {
const focused = this.config.selectionStoreConnector.focusedStore;
if (!focused) {
return null;
}
// get column data
const colType = this.config.selectionStoreConnector.storesXToType[focused.position.x];
// get row data
const rowType = this.config.selectionStoreConnector.storesYToType[focused.position.y];
const range = focused.entity.store.get('range');
if (!range) {
return null;
}
return Object.assign(Object.assign({}, range), { colType,
rowType });
}
setEdit(rowIndex, colIndex, colType, rowType) {
var _a;
const coordinate = this.getStoreCoordinateByType(colType, rowType);
if (coordinate) {
(_a = this.config.selectionStoreConnector) === null || _a === void 0 ? void 0 : _a.setEditByCell(coordinate, { x: colIndex, y: rowIndex });
}
}
}