UNPKG

@revolist/revogrid

Version:

Virtual reactive data grid spreadsheet component - RevoGrid.

159 lines (158 loc) 6.3 kB
/*! * Built by Revolist OU ❤️ */ import { getScrollDimension } from "./scroll.dimension.helpers"; const initialParams = { contentSize: 0, clientSize: 0, virtualSize: 0, maxSize: 0, }; const NO_COORDINATE = -1; /** * Based on content size, client size and virtual size * return full size */ export function getContentSize(contentSize, clientSize, virtualSize = 0) { return getScrollDimension({ contentSize, clientSize, virtualSize, }).physicalContentSize; } export default class LocalScrollService { constructor(cfg) { this.cfg = cfg; this.preventArtificialScroll = { rgRow: null, rgCol: null, }; // to check if scroll changed this.previousScroll = { rgRow: NO_COORDINATE, rgCol: NO_COORDINATE, }; this.previousLogicalScroll = { rgRow: 0, rgCol: 0, }; this.params = { rgRow: Object.assign({}, initialParams), rgCol: Object.assign({}, initialParams), }; } setParams(params, dimension) { const scrollDimension = getScrollDimension(params); const virtualContentSize = scrollDimension.physicalContentSize; this.params[dimension] = Object.assign(Object.assign({}, params), { maxSize: virtualContentSize - params.clientSize, virtualContentSize, scrollDimension }); } // apply scroll values after scroll done async setScroll(e) { this.cancelScroll(e.dimension); // start frame animation const frameAnimation = new Promise((resolve, reject) => { // for example safari desktop has issues with animation frame if (this.cfg.skipAnimationFrame) { return resolve(); } const animationId = window.requestAnimationFrame(() => { resolve(); }); this.preventArtificialScroll[e.dimension] = reject.bind(null, animationId); }); try { await frameAnimation; const params = this.getParams(e.dimension); e.coordinate = Math.ceil(e.coordinate); this.previousLogicalScroll[e.dimension] = this.wrapLogicalCoordinate(e.coordinate, params); const physicalCoordinate = this.toPhysicalCoordinate(e.coordinate, params); this.previousScroll[e.dimension] = this.wrapPhysicalCoordinate(physicalCoordinate, params); this.preventArtificialScroll[e.dimension] = null; this.cfg.applyScroll(Object.assign(Object.assign({}, e), { coordinate: physicalCoordinate })); } catch (id) { window.cancelAnimationFrame(id); } } async setScrollByDelta(e, currentPhysicalCoordinate) { var _a; const params = this.getParams(e.dimension); const baseCoordinate = this.previousScroll[e.dimension] === NO_COORDINATE ? this.toLogicalCoordinate(currentPhysicalCoordinate, params) : this.previousLogicalScroll[e.dimension]; const coordinate = this.wrapLogicalCoordinate(baseCoordinate + ((_a = e.delta) !== null && _a !== void 0 ? _a : 0), params); const nextEvent = Object.assign(Object.assign({}, e), { coordinate }); await this.setScroll(nextEvent); return nextEvent; } /** * On scroll event started */ scroll(coordinate, dimension, force = false, delta, outside = false) { // cancel all previous scrolls for same dimension this.cancelScroll(dimension); // drop if no change if (!force && this.previousScroll[dimension] === coordinate) { this.previousScroll[dimension] = NO_COORDINATE; return; } const param = this.getParams(dimension); const logicalCoordinate = this.toLogicalScrollCoordinate(coordinate, dimension, param, delta); // let component know about scroll event started this.cfg.runScroll({ dimension: dimension, coordinate: logicalCoordinate, delta, outside, }); this.previousLogicalScroll[dimension] = logicalCoordinate; } getParams(dimension) { return this.params[dimension]; } // check if scroll outside of region to avoid looping wrapPhysicalCoordinate(c, param) { if (c < 0) { return NO_COORDINATE; } if (typeof param.maxSize === 'number' && c > param.maxSize) { return param.maxSize; } return c; } wrapLogicalCoordinate(c, param) { var _a, _b; if (c < 0) { return 0; } return Math.min(c, (_b = (_a = param.scrollDimension) === null || _a === void 0 ? void 0 : _a.logicalScrollSize) !== null && _b !== void 0 ? _b : c); } // prevent already started scroll, performance optimization cancelScroll(dimension) { var _a, _b; (_b = (_a = this.preventArtificialScroll)[dimension]) === null || _b === void 0 ? void 0 : _b.call(_a); this.preventArtificialScroll[dimension] = null; } toLogicalScrollCoordinate(coordinate, dimension, param, delta) { const scrollDimension = param.scrollDimension; if (!scrollDimension) { return coordinate; } if (typeof delta === 'number' && scrollDimension.isCompressed) { const base = this.previousScroll[dimension] === NO_COORDINATE ? scrollDimension.toLogicalCoordinate(coordinate - delta) : this.previousLogicalScroll[dimension]; return scrollDimension.toLogicalCoordinate(scrollDimension.toPhysicalCoordinate(base + delta)); } return scrollDimension.toLogicalCoordinate(coordinate); } toPhysicalCoordinate(coordinate, param) { var _a, _b; return (_b = (_a = param.scrollDimension) === null || _a === void 0 ? void 0 : _a.toPhysicalCoordinate(coordinate)) !== null && _b !== void 0 ? _b : coordinate; } toLogicalCoordinate(coordinate, param) { var _a, _b; return (_b = (_a = param.scrollDimension) === null || _a === void 0 ? void 0 : _a.toLogicalCoordinate(coordinate)) !== null && _b !== void 0 ? _b : coordinate; } }