From 3c9175eb659991d0af98d82f55ab2b7c18fb16ed Mon Sep 17 00:00:00 2001 From: guy Date: Sat, 13 May 2017 19:43:53 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E6=BB=9A=E5=8A=A8=E6=80=A7?= =?UTF-8?q?=E8=83=BD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bi/base.js | 221 ++++++++++++++++++++---------- bi/core.js | 23 ++++ docs/base.js | 221 ++++++++++++++++++++---------- docs/core.js | 23 ++++ src/base/collection/collection.js | 193 +++++++++++++++++--------- src/base/grid/grid.js | 28 +++- src/core/base.js | 23 ++++ 7 files changed, 525 insertions(+), 207 deletions(-) diff --git a/bi/base.js b/bi/base.js index 39be28e36..ebf369c81 100644 --- a/bi/base.js +++ b/bi/base.js @@ -2539,6 +2539,7 @@ BI.Collection = BI.inherit(BI.Widget, { var self = this, o = this.options; this.renderedCells = []; this.renderedKeys = []; + this.renderRange = {}; this._scrollLock = false; this._debounceRelease = BI.debounce(function () { self._scrollLock = false; @@ -2588,12 +2589,10 @@ BI.Collection = BI.inherit(BI.Widget, { for (var index = 0, len = o.items.length; index < len; index++) { var cellMetadatum = o.cellSizeAndPositionGetter(index); - if ( - cellMetadatum.height == null || isNaN(cellMetadatum.height) || + if (cellMetadatum.height == null || isNaN(cellMetadatum.height) || cellMetadatum.width == null || isNaN(cellMetadatum.width) || cellMetadatum.x == null || isNaN(cellMetadatum.x) || - cellMetadatum.y == null || isNaN(cellMetadatum.y) - ) { + cellMetadatum.y == null || isNaN(cellMetadatum.y)) { throw Error(); } @@ -2634,75 +2633,134 @@ BI.Collection = BI.inherit(BI.Widget, { var top = Math.max(0, scrollTop - o.verticalOverscanSize); var right = Math.min(this._width, scrollLeft + o.width + o.horizontalOverscanSize); var bottom = Math.min(this._height, scrollTop + o.height + o.verticalOverscanSize); - var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top); - var renderedCells = [], renderedKeys = []; - for (var i = 0, len = childrenToDisplay.length; i < len; i++) { - var datum = childrenToDisplay[i]; - var index = BI.deepIndexOf(this.renderedKeys, datum.index); - if (index > -1) { - if (datum.width !== this.renderedCells[index]._width) { - this.renderedCells[index]._width = datum.width; - this.renderedCells[index].el.setWidth(datum.width); + if (right > 0 && bottom > 0) { + //如果滚动的区间并没有超出渲染的范围 + if (top >= this.renderRange.minY && bottom <= this.renderRange.maxY && left >= this.renderRange.minX && right <= this.renderRange.maxX) { + return; + } + var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top); + var renderedCells = [], renderedKeys = []; + //存储所有的left和top + var lefts = {}, tops = {}; + for (var i = 0, len = childrenToDisplay.length; i < len; i++) { + var datum = childrenToDisplay[i]; + lefts[datum.x] = datum.x; + lefts[datum.x + datum.width] = datum.x + datum.width; + tops[datum.y] = datum.y; + tops[datum.y + datum.height] = datum.y + datum.height; + } + lefts = BI.toArray(lefts); + tops = BI.toArray(tops); + var leftMap = BI.invert(lefts); + var topMap = BI.invert(tops); + //存储上下左右四个边界 + var leftBorder = {}, rightBorder = {}, topBorder = {}, bottomBorder = {}; + var assertMinBorder = function (border, offset) { + if (border[offset] == null) { + border[offset] = Number.MAX_VALUE; + } + }; + var assertMaxBorder = function (border, offset) { + if (border[offset] == null) { + border[offset] = 0; } - if (datum.height !== this.renderedCells[index]._height) { - this.renderedCells[index]._height = datum.height; - this.renderedCells[index].el.setHeight(datum.height); + }; + for (var i = 0, len = childrenToDisplay.length; i < len; i++) { + var datum = childrenToDisplay[i]; + var index = BI.deepIndexOf(this.renderedKeys, datum.index); + if (index > -1) { + if (datum.width !== this.renderedCells[index]._width) { + this.renderedCells[index]._width = datum.width; + this.renderedCells[index].el.setWidth(datum.width); + } + if (datum.height !== this.renderedCells[index]._height) { + this.renderedCells[index]._height = datum.height; + this.renderedCells[index].el.setHeight(datum.height); + } + if (this.renderedCells[index].left !== datum.x) { + this.renderedCells[index].el.element.css("left", datum.x + "px"); + } + if (this.renderedCells[index].top !== datum.y) { + this.renderedCells[index].el.element.css("top", datum.y + "px"); + } + renderedCells.push(this.renderedCells[index]); + } else { + var child = BI.createWidget(BI.extend({ + type: "bi.label", + width: datum.width, + height: datum.height + }, o.items[datum.index], { + cls: (o.items[datum.index].cls || "") + " container-cell" + (datum.y === 0 ? " first-row" : "") + (datum.x === 0 ? " first-col" : ""), + _left: datum.x, + _top: datum.y + })); + renderedCells.push({ + el: child, + left: datum.x, + top: datum.y, + _width: datum.width, + _height: datum.height + }); } - if (this.renderedCells[index].left !== datum.x) { - this.renderedCells[index].el.element.css("left", datum.x + "px"); + var startTopIndex = topMap[datum.y] | 0; + var endTopIndex = topMap[datum.y + datum.height] | 0; + for (var k = startTopIndex; k <= endTopIndex; k++) { + var t = tops[k]; + assertMinBorder(leftBorder, t); + assertMaxBorder(rightBorder, t); + leftBorder[t] = Math.min(leftBorder[t], datum.x); + rightBorder[t] = Math.max(rightBorder[t], datum.x + datum.width); } - if (this.renderedCells[index].top !== datum.y) { - this.renderedCells[index].el.element.css("top", datum.y + "px"); + var startLeftIndex = leftMap[datum.x] | 0; + var endLeftIndex = leftMap[datum.x + datum.width] | 0; + for (var k = startLeftIndex; k <= endLeftIndex; k++) { + var l = lefts[k]; + assertMinBorder(topBorder, l); + assertMaxBorder(bottomBorder, l); + topBorder[l] = Math.min(topBorder[l], datum.y); + bottomBorder[l] = Math.max(bottomBorder[l], datum.y + datum.height); } - renderedCells.push(this.renderedCells[index]); - } else { - var child = BI.createWidget(BI.extend({ - type: "bi.label", - width: datum.width, - height: datum.height - }, o.items[datum.index], { - cls: (o.items[datum.index].cls || "") + " container-cell" + (datum.y === 0 ? " first-row" : "") + (datum.x === 0 ? " first-col" : ""), - _left: datum.x, - _top: datum.y - })); - renderedCells.push({ - el: child, - left: datum.x, - top: datum.y, - _width: datum.width, - _height: datum.height - }); + + renderedKeys.push(datum.index); } - renderedKeys.push(datum.index); + //已存在的, 需要添加的和需要删除的 + var existSet = {}, addSet = {}, deleteArray = []; + BI.each(renderedKeys, function (i, key) { + if (BI.deepContains(self.renderedKeys, key)) { + existSet[i] = key; + } else { + addSet[i] = key; + } + }); + BI.each(this.renderedKeys, function (i, key) { + if (BI.deepContains(existSet, key)) { + return; + } + if (BI.deepContains(addSet, key)) { + return; + } + deleteArray.push(i); + }); + BI.each(deleteArray, function (i, index) { + self.renderedCells[index].el.destroy(); + }); + var addedItems = []; + BI.each(addSet, function (index) { + addedItems.push(renderedCells[index]) + }); + this.container.addItems(addedItems); + this.renderedCells = renderedCells; + this.renderedKeys = renderedKeys; + + //Todo 左右比较特殊 + var minX = BI.min(leftBorder); + var maxX = BI.max(rightBorder); + + var minY = BI.max(topBorder); + var maxY = BI.min(bottomBorder); + + this.renderRange = {minX: minX, minY: minY, maxX: maxX, maxY: maxY}; } - //已存在的, 需要添加的和需要删除的 - var existSet = {}, addSet = {}, deleteArray = []; - BI.each(renderedKeys, function (i, key) { - if (BI.deepContains(self.renderedKeys, key)) { - existSet[i] = key; - } else { - addSet[i] = key; - } - }); - BI.each(this.renderedKeys, function (i, key) { - if (BI.deepContains(existSet, key)) { - return; - } - if (BI.deepContains(addSet, key)) { - return; - } - deleteArray.push(i); - }); - BI.each(deleteArray, function (i, index) { - self.renderedCells[index].el.destroy(); - }); - var addedItems = []; - BI.each(addSet, function (index) { - addedItems.push(renderedCells[index]) - }); - this.container.addItems(addedItems); - this.renderedCells = renderedCells; - this.renderedKeys = renderedKeys; }, _getMaxScrollLeft: function () { @@ -2789,6 +2847,7 @@ BI.Collection = BI.inherit(BI.Widget, { }); this.renderedCells = []; this.renderedKeys = []; + this.renderRange = {}; this._scrollLock = false; }, @@ -14613,6 +14672,7 @@ BI.Grid = BI.inherit(BI.Widget, { var self = this, o = this.options; this.renderedCells = []; this.renderedKeys = []; + this.renderRange = {}; this._scrollLock = false; this._debounceRelease = BI.debounce(function () { self._scrollLock = false; @@ -14661,13 +14721,17 @@ BI.Grid = BI.inherit(BI.Widget, { _calculateChildrenToRender: function () { var self = this, o = this.options; - var width = o.width, height = o.height, scrollLeft = BI.clamp(o.scrollLeft, 0, this._getMaxScrollLeft()), scrollTop = BI.clamp(o.scrollTop, 0, this._getMaxScrollTop()), + var width = o.width, height = o.height, scrollLeft = BI.clamp(o.scrollLeft, 0, this._getMaxScrollLeft()), + scrollTop = BI.clamp(o.scrollTop, 0, this._getMaxScrollTop()), overscanColumnCount = o.overscanColumnCount, overscanRowCount = o.overscanRowCount; if (height > 0 && width > 0) { var visibleColumnIndices = this._columnSizeAndPositionManager.getVisibleCellRange(width, scrollLeft); var visibleRowIndices = this._rowSizeAndPositionManager.getVisibleCellRange(height, scrollTop); + if (BI.isEmpty(visibleColumnIndices) || BI.isEmpty(visibleRowIndices)) { + return; + } var horizontalOffsetAdjustment = this._columnSizeAndPositionManager.getOffsetAdjustment(width, scrollLeft); var verticalOffsetAdjustment = this._rowSizeAndPositionManager.getOffsetAdjustment(height, scrollTop); @@ -14685,8 +14749,22 @@ BI.Grid = BI.inherit(BI.Widget, { var rowStartIndex = overscanRowIndices.overscanStartIndex; var rowStopIndex = overscanRowIndices.overscanStopIndex; - var renderedCells = [], renderedKeys = []; + //算区间size + var minRowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowStartIndex); + var minColumnDatum = this._columnSizeAndPositionManager.getSizeAndPositionOfCell(columnStartIndex); + var maxRowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowStopIndex); + var maxColumnDatum = this._columnSizeAndPositionManager.getSizeAndPositionOfCell(columnStopIndex); + var top = minRowDatum.offset + verticalOffsetAdjustment; + var left = minColumnDatum.offset + horizontalOffsetAdjustment; + var bottom = maxRowDatum.offset + verticalOffsetAdjustment + maxRowDatum.size; + var right = maxColumnDatum.offset + horizontalOffsetAdjustment + maxColumnDatum.size; + //如果滚动的区间并没有超出渲染的范围 + if (top >= this.renderRange.minY && bottom <= this.renderRange.maxY && left >= this.renderRange.minX && right <= this.renderRange.maxX) { + return; + } + var renderedCells = [], renderedKeys = []; + var minX = this._getMaxScrollLeft(), minY = this._getMaxScrollTop(), maxX = 0, maxY = 0; for (var rowIndex = rowStartIndex; rowIndex <= rowStopIndex; rowIndex++) { var rowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowIndex); @@ -14731,6 +14809,10 @@ BI.Grid = BI.inherit(BI.Widget, { _height: rowDatum.size }); } + minX = Math.min(minX, columnDatum.offset + horizontalOffsetAdjustment); + maxX = Math.max(maxX, columnDatum.offset + horizontalOffsetAdjustment + columnDatum.size); + minY = Math.min(minY, rowDatum.offset + verticalOffsetAdjustment); + maxY = Math.max(maxY, rowDatum.offset + verticalOffsetAdjustment + rowDatum.size); renderedKeys.push(key); } } @@ -14762,6 +14844,7 @@ BI.Grid = BI.inherit(BI.Widget, { this.container.addItems(addedItems); this.renderedCells = renderedCells; this.renderedKeys = renderedKeys; + this.renderRange = {minX: minX, minY: minY, maxX: maxX, maxY: maxY}; } }, diff --git a/bi/core.js b/bi/core.js index 494b9d052..5de694e03 100644 --- a/bi/core.js +++ b/bi/core.js @@ -2163,6 +2163,29 @@ if (!window.BI) { return true; }, + backFindKey: function (obj, predicate, context) { + predicate = BI.iteratee(predicate, context); + var keys = _.keys(obj), key; + for (var i = keys.length - 1; i >= 0; i--) { + key = keys[i]; + if (predicate(obj[key], key, obj)) { + return key; + } + } + }, + + backFind: function (obj, predicate, context) { + var key; + if (BI.isArray(obj)) { + key = BI.findLastIndex(obj, predicate, context); + } else { + key = BI.backFindKey(obj, predicate, context); + } + if (key !== void 0 && key !== -1) { + return obj[key]; + } + }, + remove: function (obj, target, context) { var isFunction = BI.isFunction(target); target = isFunction || BI.isArray(target) ? target : [target]; diff --git a/docs/base.js b/docs/base.js index 39be28e36..ebf369c81 100644 --- a/docs/base.js +++ b/docs/base.js @@ -2539,6 +2539,7 @@ BI.Collection = BI.inherit(BI.Widget, { var self = this, o = this.options; this.renderedCells = []; this.renderedKeys = []; + this.renderRange = {}; this._scrollLock = false; this._debounceRelease = BI.debounce(function () { self._scrollLock = false; @@ -2588,12 +2589,10 @@ BI.Collection = BI.inherit(BI.Widget, { for (var index = 0, len = o.items.length; index < len; index++) { var cellMetadatum = o.cellSizeAndPositionGetter(index); - if ( - cellMetadatum.height == null || isNaN(cellMetadatum.height) || + if (cellMetadatum.height == null || isNaN(cellMetadatum.height) || cellMetadatum.width == null || isNaN(cellMetadatum.width) || cellMetadatum.x == null || isNaN(cellMetadatum.x) || - cellMetadatum.y == null || isNaN(cellMetadatum.y) - ) { + cellMetadatum.y == null || isNaN(cellMetadatum.y)) { throw Error(); } @@ -2634,75 +2633,134 @@ BI.Collection = BI.inherit(BI.Widget, { var top = Math.max(0, scrollTop - o.verticalOverscanSize); var right = Math.min(this._width, scrollLeft + o.width + o.horizontalOverscanSize); var bottom = Math.min(this._height, scrollTop + o.height + o.verticalOverscanSize); - var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top); - var renderedCells = [], renderedKeys = []; - for (var i = 0, len = childrenToDisplay.length; i < len; i++) { - var datum = childrenToDisplay[i]; - var index = BI.deepIndexOf(this.renderedKeys, datum.index); - if (index > -1) { - if (datum.width !== this.renderedCells[index]._width) { - this.renderedCells[index]._width = datum.width; - this.renderedCells[index].el.setWidth(datum.width); + if (right > 0 && bottom > 0) { + //如果滚动的区间并没有超出渲染的范围 + if (top >= this.renderRange.minY && bottom <= this.renderRange.maxY && left >= this.renderRange.minX && right <= this.renderRange.maxX) { + return; + } + var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top); + var renderedCells = [], renderedKeys = []; + //存储所有的left和top + var lefts = {}, tops = {}; + for (var i = 0, len = childrenToDisplay.length; i < len; i++) { + var datum = childrenToDisplay[i]; + lefts[datum.x] = datum.x; + lefts[datum.x + datum.width] = datum.x + datum.width; + tops[datum.y] = datum.y; + tops[datum.y + datum.height] = datum.y + datum.height; + } + lefts = BI.toArray(lefts); + tops = BI.toArray(tops); + var leftMap = BI.invert(lefts); + var topMap = BI.invert(tops); + //存储上下左右四个边界 + var leftBorder = {}, rightBorder = {}, topBorder = {}, bottomBorder = {}; + var assertMinBorder = function (border, offset) { + if (border[offset] == null) { + border[offset] = Number.MAX_VALUE; + } + }; + var assertMaxBorder = function (border, offset) { + if (border[offset] == null) { + border[offset] = 0; } - if (datum.height !== this.renderedCells[index]._height) { - this.renderedCells[index]._height = datum.height; - this.renderedCells[index].el.setHeight(datum.height); + }; + for (var i = 0, len = childrenToDisplay.length; i < len; i++) { + var datum = childrenToDisplay[i]; + var index = BI.deepIndexOf(this.renderedKeys, datum.index); + if (index > -1) { + if (datum.width !== this.renderedCells[index]._width) { + this.renderedCells[index]._width = datum.width; + this.renderedCells[index].el.setWidth(datum.width); + } + if (datum.height !== this.renderedCells[index]._height) { + this.renderedCells[index]._height = datum.height; + this.renderedCells[index].el.setHeight(datum.height); + } + if (this.renderedCells[index].left !== datum.x) { + this.renderedCells[index].el.element.css("left", datum.x + "px"); + } + if (this.renderedCells[index].top !== datum.y) { + this.renderedCells[index].el.element.css("top", datum.y + "px"); + } + renderedCells.push(this.renderedCells[index]); + } else { + var child = BI.createWidget(BI.extend({ + type: "bi.label", + width: datum.width, + height: datum.height + }, o.items[datum.index], { + cls: (o.items[datum.index].cls || "") + " container-cell" + (datum.y === 0 ? " first-row" : "") + (datum.x === 0 ? " first-col" : ""), + _left: datum.x, + _top: datum.y + })); + renderedCells.push({ + el: child, + left: datum.x, + top: datum.y, + _width: datum.width, + _height: datum.height + }); } - if (this.renderedCells[index].left !== datum.x) { - this.renderedCells[index].el.element.css("left", datum.x + "px"); + var startTopIndex = topMap[datum.y] | 0; + var endTopIndex = topMap[datum.y + datum.height] | 0; + for (var k = startTopIndex; k <= endTopIndex; k++) { + var t = tops[k]; + assertMinBorder(leftBorder, t); + assertMaxBorder(rightBorder, t); + leftBorder[t] = Math.min(leftBorder[t], datum.x); + rightBorder[t] = Math.max(rightBorder[t], datum.x + datum.width); } - if (this.renderedCells[index].top !== datum.y) { - this.renderedCells[index].el.element.css("top", datum.y + "px"); + var startLeftIndex = leftMap[datum.x] | 0; + var endLeftIndex = leftMap[datum.x + datum.width] | 0; + for (var k = startLeftIndex; k <= endLeftIndex; k++) { + var l = lefts[k]; + assertMinBorder(topBorder, l); + assertMaxBorder(bottomBorder, l); + topBorder[l] = Math.min(topBorder[l], datum.y); + bottomBorder[l] = Math.max(bottomBorder[l], datum.y + datum.height); } - renderedCells.push(this.renderedCells[index]); - } else { - var child = BI.createWidget(BI.extend({ - type: "bi.label", - width: datum.width, - height: datum.height - }, o.items[datum.index], { - cls: (o.items[datum.index].cls || "") + " container-cell" + (datum.y === 0 ? " first-row" : "") + (datum.x === 0 ? " first-col" : ""), - _left: datum.x, - _top: datum.y - })); - renderedCells.push({ - el: child, - left: datum.x, - top: datum.y, - _width: datum.width, - _height: datum.height - }); + + renderedKeys.push(datum.index); } - renderedKeys.push(datum.index); + //已存在的, 需要添加的和需要删除的 + var existSet = {}, addSet = {}, deleteArray = []; + BI.each(renderedKeys, function (i, key) { + if (BI.deepContains(self.renderedKeys, key)) { + existSet[i] = key; + } else { + addSet[i] = key; + } + }); + BI.each(this.renderedKeys, function (i, key) { + if (BI.deepContains(existSet, key)) { + return; + } + if (BI.deepContains(addSet, key)) { + return; + } + deleteArray.push(i); + }); + BI.each(deleteArray, function (i, index) { + self.renderedCells[index].el.destroy(); + }); + var addedItems = []; + BI.each(addSet, function (index) { + addedItems.push(renderedCells[index]) + }); + this.container.addItems(addedItems); + this.renderedCells = renderedCells; + this.renderedKeys = renderedKeys; + + //Todo 左右比较特殊 + var minX = BI.min(leftBorder); + var maxX = BI.max(rightBorder); + + var minY = BI.max(topBorder); + var maxY = BI.min(bottomBorder); + + this.renderRange = {minX: minX, minY: minY, maxX: maxX, maxY: maxY}; } - //已存在的, 需要添加的和需要删除的 - var existSet = {}, addSet = {}, deleteArray = []; - BI.each(renderedKeys, function (i, key) { - if (BI.deepContains(self.renderedKeys, key)) { - existSet[i] = key; - } else { - addSet[i] = key; - } - }); - BI.each(this.renderedKeys, function (i, key) { - if (BI.deepContains(existSet, key)) { - return; - } - if (BI.deepContains(addSet, key)) { - return; - } - deleteArray.push(i); - }); - BI.each(deleteArray, function (i, index) { - self.renderedCells[index].el.destroy(); - }); - var addedItems = []; - BI.each(addSet, function (index) { - addedItems.push(renderedCells[index]) - }); - this.container.addItems(addedItems); - this.renderedCells = renderedCells; - this.renderedKeys = renderedKeys; }, _getMaxScrollLeft: function () { @@ -2789,6 +2847,7 @@ BI.Collection = BI.inherit(BI.Widget, { }); this.renderedCells = []; this.renderedKeys = []; + this.renderRange = {}; this._scrollLock = false; }, @@ -14613,6 +14672,7 @@ BI.Grid = BI.inherit(BI.Widget, { var self = this, o = this.options; this.renderedCells = []; this.renderedKeys = []; + this.renderRange = {}; this._scrollLock = false; this._debounceRelease = BI.debounce(function () { self._scrollLock = false; @@ -14661,13 +14721,17 @@ BI.Grid = BI.inherit(BI.Widget, { _calculateChildrenToRender: function () { var self = this, o = this.options; - var width = o.width, height = o.height, scrollLeft = BI.clamp(o.scrollLeft, 0, this._getMaxScrollLeft()), scrollTop = BI.clamp(o.scrollTop, 0, this._getMaxScrollTop()), + var width = o.width, height = o.height, scrollLeft = BI.clamp(o.scrollLeft, 0, this._getMaxScrollLeft()), + scrollTop = BI.clamp(o.scrollTop, 0, this._getMaxScrollTop()), overscanColumnCount = o.overscanColumnCount, overscanRowCount = o.overscanRowCount; if (height > 0 && width > 0) { var visibleColumnIndices = this._columnSizeAndPositionManager.getVisibleCellRange(width, scrollLeft); var visibleRowIndices = this._rowSizeAndPositionManager.getVisibleCellRange(height, scrollTop); + if (BI.isEmpty(visibleColumnIndices) || BI.isEmpty(visibleRowIndices)) { + return; + } var horizontalOffsetAdjustment = this._columnSizeAndPositionManager.getOffsetAdjustment(width, scrollLeft); var verticalOffsetAdjustment = this._rowSizeAndPositionManager.getOffsetAdjustment(height, scrollTop); @@ -14685,8 +14749,22 @@ BI.Grid = BI.inherit(BI.Widget, { var rowStartIndex = overscanRowIndices.overscanStartIndex; var rowStopIndex = overscanRowIndices.overscanStopIndex; - var renderedCells = [], renderedKeys = []; + //算区间size + var minRowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowStartIndex); + var minColumnDatum = this._columnSizeAndPositionManager.getSizeAndPositionOfCell(columnStartIndex); + var maxRowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowStopIndex); + var maxColumnDatum = this._columnSizeAndPositionManager.getSizeAndPositionOfCell(columnStopIndex); + var top = minRowDatum.offset + verticalOffsetAdjustment; + var left = minColumnDatum.offset + horizontalOffsetAdjustment; + var bottom = maxRowDatum.offset + verticalOffsetAdjustment + maxRowDatum.size; + var right = maxColumnDatum.offset + horizontalOffsetAdjustment + maxColumnDatum.size; + //如果滚动的区间并没有超出渲染的范围 + if (top >= this.renderRange.minY && bottom <= this.renderRange.maxY && left >= this.renderRange.minX && right <= this.renderRange.maxX) { + return; + } + var renderedCells = [], renderedKeys = []; + var minX = this._getMaxScrollLeft(), minY = this._getMaxScrollTop(), maxX = 0, maxY = 0; for (var rowIndex = rowStartIndex; rowIndex <= rowStopIndex; rowIndex++) { var rowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowIndex); @@ -14731,6 +14809,10 @@ BI.Grid = BI.inherit(BI.Widget, { _height: rowDatum.size }); } + minX = Math.min(minX, columnDatum.offset + horizontalOffsetAdjustment); + maxX = Math.max(maxX, columnDatum.offset + horizontalOffsetAdjustment + columnDatum.size); + minY = Math.min(minY, rowDatum.offset + verticalOffsetAdjustment); + maxY = Math.max(maxY, rowDatum.offset + verticalOffsetAdjustment + rowDatum.size); renderedKeys.push(key); } } @@ -14762,6 +14844,7 @@ BI.Grid = BI.inherit(BI.Widget, { this.container.addItems(addedItems); this.renderedCells = renderedCells; this.renderedKeys = renderedKeys; + this.renderRange = {minX: minX, minY: minY, maxX: maxX, maxY: maxY}; } }, diff --git a/docs/core.js b/docs/core.js index 0bd912d24..49809986e 100644 --- a/docs/core.js +++ b/docs/core.js @@ -13305,6 +13305,29 @@ if (!window.BI) { return true; }, + backFindKey: function (obj, predicate, context) { + predicate = BI.iteratee(predicate, context); + var keys = _.keys(obj), key; + for (var i = keys.length - 1; i >= 0; i--) { + key = keys[i]; + if (predicate(obj[key], key, obj)) { + return key; + } + } + }, + + backFind: function (obj, predicate, context) { + var key; + if (BI.isArray(obj)) { + key = BI.findLastIndex(obj, predicate, context); + } else { + key = BI.backFindKey(obj, predicate, context); + } + if (key !== void 0 && key !== -1) { + return obj[key]; + } + }, + remove: function (obj, target, context) { var isFunction = BI.isFunction(target); target = isFunction || BI.isArray(target) ? target : [target]; diff --git a/src/base/collection/collection.js b/src/base/collection/collection.js index b9e358175..f830cb050 100644 --- a/src/base/collection/collection.js +++ b/src/base/collection/collection.js @@ -27,6 +27,7 @@ BI.Collection = BI.inherit(BI.Widget, { var self = this, o = this.options; this.renderedCells = []; this.renderedKeys = []; + this.renderRange = {}; this._scrollLock = false; this._debounceRelease = BI.debounce(function () { self._scrollLock = false; @@ -76,12 +77,10 @@ BI.Collection = BI.inherit(BI.Widget, { for (var index = 0, len = o.items.length; index < len; index++) { var cellMetadatum = o.cellSizeAndPositionGetter(index); - if ( - cellMetadatum.height == null || isNaN(cellMetadatum.height) || + if (cellMetadatum.height == null || isNaN(cellMetadatum.height) || cellMetadatum.width == null || isNaN(cellMetadatum.width) || cellMetadatum.x == null || isNaN(cellMetadatum.x) || - cellMetadatum.y == null || isNaN(cellMetadatum.y) - ) { + cellMetadatum.y == null || isNaN(cellMetadatum.y)) { throw Error(); } @@ -122,75 +121,134 @@ BI.Collection = BI.inherit(BI.Widget, { var top = Math.max(0, scrollTop - o.verticalOverscanSize); var right = Math.min(this._width, scrollLeft + o.width + o.horizontalOverscanSize); var bottom = Math.min(this._height, scrollTop + o.height + o.verticalOverscanSize); - var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top); - var renderedCells = [], renderedKeys = []; - for (var i = 0, len = childrenToDisplay.length; i < len; i++) { - var datum = childrenToDisplay[i]; - var index = BI.deepIndexOf(this.renderedKeys, datum.index); - if (index > -1) { - if (datum.width !== this.renderedCells[index]._width) { - this.renderedCells[index]._width = datum.width; - this.renderedCells[index].el.setWidth(datum.width); + if (right > 0 && bottom > 0) { + //如果滚动的区间并没有超出渲染的范围 + if (top >= this.renderRange.minY && bottom <= this.renderRange.maxY && left >= this.renderRange.minX && right <= this.renderRange.maxX) { + return; + } + var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top); + var renderedCells = [], renderedKeys = []; + //存储所有的left和top + var lefts = {}, tops = {}; + for (var i = 0, len = childrenToDisplay.length; i < len; i++) { + var datum = childrenToDisplay[i]; + lefts[datum.x] = datum.x; + lefts[datum.x + datum.width] = datum.x + datum.width; + tops[datum.y] = datum.y; + tops[datum.y + datum.height] = datum.y + datum.height; + } + lefts = BI.toArray(lefts); + tops = BI.toArray(tops); + var leftMap = BI.invert(lefts); + var topMap = BI.invert(tops); + //存储上下左右四个边界 + var leftBorder = {}, rightBorder = {}, topBorder = {}, bottomBorder = {}; + var assertMinBorder = function (border, offset) { + if (border[offset] == null) { + border[offset] = Number.MAX_VALUE; } - if (datum.height !== this.renderedCells[index]._height) { - this.renderedCells[index]._height = datum.height; - this.renderedCells[index].el.setHeight(datum.height); + }; + var assertMaxBorder = function (border, offset) { + if (border[offset] == null) { + border[offset] = 0; } - if (this.renderedCells[index].left !== datum.x) { - this.renderedCells[index].el.element.css("left", datum.x + "px"); + }; + for (var i = 0, len = childrenToDisplay.length; i < len; i++) { + var datum = childrenToDisplay[i]; + var index = BI.deepIndexOf(this.renderedKeys, datum.index); + if (index > -1) { + if (datum.width !== this.renderedCells[index]._width) { + this.renderedCells[index]._width = datum.width; + this.renderedCells[index].el.setWidth(datum.width); + } + if (datum.height !== this.renderedCells[index]._height) { + this.renderedCells[index]._height = datum.height; + this.renderedCells[index].el.setHeight(datum.height); + } + if (this.renderedCells[index].left !== datum.x) { + this.renderedCells[index].el.element.css("left", datum.x + "px"); + } + if (this.renderedCells[index].top !== datum.y) { + this.renderedCells[index].el.element.css("top", datum.y + "px"); + } + renderedCells.push(this.renderedCells[index]); + } else { + var child = BI.createWidget(BI.extend({ + type: "bi.label", + width: datum.width, + height: datum.height + }, o.items[datum.index], { + cls: (o.items[datum.index].cls || "") + " container-cell" + (datum.y === 0 ? " first-row" : "") + (datum.x === 0 ? " first-col" : ""), + _left: datum.x, + _top: datum.y + })); + renderedCells.push({ + el: child, + left: datum.x, + top: datum.y, + _width: datum.width, + _height: datum.height + }); } - if (this.renderedCells[index].top !== datum.y) { - this.renderedCells[index].el.element.css("top", datum.y + "px"); + var startTopIndex = topMap[datum.y] | 0; + var endTopIndex = topMap[datum.y + datum.height] | 0; + for (var k = startTopIndex; k <= endTopIndex; k++) { + var t = tops[k]; + assertMinBorder(leftBorder, t); + assertMaxBorder(rightBorder, t); + leftBorder[t] = Math.min(leftBorder[t], datum.x); + rightBorder[t] = Math.max(rightBorder[t], datum.x + datum.width); } - renderedCells.push(this.renderedCells[index]); - } else { - var child = BI.createWidget(BI.extend({ - type: "bi.label", - width: datum.width, - height: datum.height - }, o.items[datum.index], { - cls: (o.items[datum.index].cls || "") + " container-cell" + (datum.y === 0 ? " first-row" : "") + (datum.x === 0 ? " first-col" : ""), - _left: datum.x, - _top: datum.y - })); - renderedCells.push({ - el: child, - left: datum.x, - top: datum.y, - _width: datum.width, - _height: datum.height - }); + var startLeftIndex = leftMap[datum.x] | 0; + var endLeftIndex = leftMap[datum.x + datum.width] | 0; + for (var k = startLeftIndex; k <= endLeftIndex; k++) { + var l = lefts[k]; + assertMinBorder(topBorder, l); + assertMaxBorder(bottomBorder, l); + topBorder[l] = Math.min(topBorder[l], datum.y); + bottomBorder[l] = Math.max(bottomBorder[l], datum.y + datum.height); + } + + renderedKeys.push(datum.index); } - renderedKeys.push(datum.index); + //已存在的, 需要添加的和需要删除的 + var existSet = {}, addSet = {}, deleteArray = []; + BI.each(renderedKeys, function (i, key) { + if (BI.deepContains(self.renderedKeys, key)) { + existSet[i] = key; + } else { + addSet[i] = key; + } + }); + BI.each(this.renderedKeys, function (i, key) { + if (BI.deepContains(existSet, key)) { + return; + } + if (BI.deepContains(addSet, key)) { + return; + } + deleteArray.push(i); + }); + BI.each(deleteArray, function (i, index) { + self.renderedCells[index].el.destroy(); + }); + var addedItems = []; + BI.each(addSet, function (index) { + addedItems.push(renderedCells[index]) + }); + this.container.addItems(addedItems); + this.renderedCells = renderedCells; + this.renderedKeys = renderedKeys; + + //Todo 左右比较特殊 + var minX = BI.min(leftBorder); + var maxX = BI.max(rightBorder); + + var minY = BI.max(topBorder); + var maxY = BI.min(bottomBorder); + + this.renderRange = {minX: minX, minY: minY, maxX: maxX, maxY: maxY}; } - //已存在的, 需要添加的和需要删除的 - var existSet = {}, addSet = {}, deleteArray = []; - BI.each(renderedKeys, function (i, key) { - if (BI.deepContains(self.renderedKeys, key)) { - existSet[i] = key; - } else { - addSet[i] = key; - } - }); - BI.each(this.renderedKeys, function (i, key) { - if (BI.deepContains(existSet, key)) { - return; - } - if (BI.deepContains(addSet, key)) { - return; - } - deleteArray.push(i); - }); - BI.each(deleteArray, function (i, index) { - self.renderedCells[index].el.destroy(); - }); - var addedItems = []; - BI.each(addSet, function (index) { - addedItems.push(renderedCells[index]) - }); - this.container.addItems(addedItems); - this.renderedCells = renderedCells; - this.renderedKeys = renderedKeys; }, _getMaxScrollLeft: function () { @@ -277,6 +335,7 @@ BI.Collection = BI.inherit(BI.Widget, { }); this.renderedCells = []; this.renderedKeys = []; + this.renderRange = {}; this._scrollLock = false; }, diff --git a/src/base/grid/grid.js b/src/base/grid/grid.js index e138e6622..ce9d7c1ae 100644 --- a/src/base/grid/grid.js +++ b/src/base/grid/grid.js @@ -30,6 +30,7 @@ BI.Grid = BI.inherit(BI.Widget, { var self = this, o = this.options; this.renderedCells = []; this.renderedKeys = []; + this.renderRange = {}; this._scrollLock = false; this._debounceRelease = BI.debounce(function () { self._scrollLock = false; @@ -78,13 +79,17 @@ BI.Grid = BI.inherit(BI.Widget, { _calculateChildrenToRender: function () { var self = this, o = this.options; - var width = o.width, height = o.height, scrollLeft = BI.clamp(o.scrollLeft, 0, this._getMaxScrollLeft()), scrollTop = BI.clamp(o.scrollTop, 0, this._getMaxScrollTop()), + var width = o.width, height = o.height, scrollLeft = BI.clamp(o.scrollLeft, 0, this._getMaxScrollLeft()), + scrollTop = BI.clamp(o.scrollTop, 0, this._getMaxScrollTop()), overscanColumnCount = o.overscanColumnCount, overscanRowCount = o.overscanRowCount; if (height > 0 && width > 0) { var visibleColumnIndices = this._columnSizeAndPositionManager.getVisibleCellRange(width, scrollLeft); var visibleRowIndices = this._rowSizeAndPositionManager.getVisibleCellRange(height, scrollTop); + if (BI.isEmpty(visibleColumnIndices) || BI.isEmpty(visibleRowIndices)) { + return; + } var horizontalOffsetAdjustment = this._columnSizeAndPositionManager.getOffsetAdjustment(width, scrollLeft); var verticalOffsetAdjustment = this._rowSizeAndPositionManager.getOffsetAdjustment(height, scrollTop); @@ -102,8 +107,22 @@ BI.Grid = BI.inherit(BI.Widget, { var rowStartIndex = overscanRowIndices.overscanStartIndex; var rowStopIndex = overscanRowIndices.overscanStopIndex; - var renderedCells = [], renderedKeys = []; + //算区间size + var minRowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowStartIndex); + var minColumnDatum = this._columnSizeAndPositionManager.getSizeAndPositionOfCell(columnStartIndex); + var maxRowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowStopIndex); + var maxColumnDatum = this._columnSizeAndPositionManager.getSizeAndPositionOfCell(columnStopIndex); + var top = minRowDatum.offset + verticalOffsetAdjustment; + var left = minColumnDatum.offset + horizontalOffsetAdjustment; + var bottom = maxRowDatum.offset + verticalOffsetAdjustment + maxRowDatum.size; + var right = maxColumnDatum.offset + horizontalOffsetAdjustment + maxColumnDatum.size; + //如果滚动的区间并没有超出渲染的范围 + if (top >= this.renderRange.minY && bottom <= this.renderRange.maxY && left >= this.renderRange.minX && right <= this.renderRange.maxX) { + return; + } + var renderedCells = [], renderedKeys = []; + var minX = this._getMaxScrollLeft(), minY = this._getMaxScrollTop(), maxX = 0, maxY = 0; for (var rowIndex = rowStartIndex; rowIndex <= rowStopIndex; rowIndex++) { var rowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowIndex); @@ -148,6 +167,10 @@ BI.Grid = BI.inherit(BI.Widget, { _height: rowDatum.size }); } + minX = Math.min(minX, columnDatum.offset + horizontalOffsetAdjustment); + maxX = Math.max(maxX, columnDatum.offset + horizontalOffsetAdjustment + columnDatum.size); + minY = Math.min(minY, rowDatum.offset + verticalOffsetAdjustment); + maxY = Math.max(maxY, rowDatum.offset + verticalOffsetAdjustment + rowDatum.size); renderedKeys.push(key); } } @@ -179,6 +202,7 @@ BI.Grid = BI.inherit(BI.Widget, { this.container.addItems(addedItems); this.renderedCells = renderedCells; this.renderedKeys = renderedKeys; + this.renderRange = {minX: minX, minY: minY, maxX: maxX, maxY: maxY}; } }, diff --git a/src/core/base.js b/src/core/base.js index d291ca5c7..96438a27e 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -268,6 +268,29 @@ if (!window.BI) { return true; }, + backFindKey: function (obj, predicate, context) { + predicate = BI.iteratee(predicate, context); + var keys = _.keys(obj), key; + for (var i = keys.length - 1; i >= 0; i--) { + key = keys[i]; + if (predicate(obj[key], key, obj)) { + return key; + } + } + }, + + backFind: function (obj, predicate, context) { + var key; + if (BI.isArray(obj)) { + key = BI.findLastIndex(obj, predicate, context); + } else { + key = BI.backFindKey(obj, predicate, context); + } + if (key !== void 0 && key !== -1) { + return obj[key]; + } + }, + remove: function (obj, target, context) { var isFunction = BI.isFunction(target); target = isFunction || BI.isArray(target) ? target : [target];