Browse Source

表格滚动性能优化

es6
guy 8 years ago
parent
commit
3c9175eb65
  1. 221
      bi/base.js
  2. 23
      bi/core.js
  3. 221
      docs/base.js
  4. 23
      docs/core.js
  5. 193
      src/base/collection/collection.js
  6. 28
      src/base/grid/grid.js
  7. 23
      src/core/base.js

221
bi/base.js

@ -2539,6 +2539,7 @@ BI.Collection = BI.inherit(BI.Widget, {
var self = this, o = this.options; var self = this, o = this.options;
this.renderedCells = []; this.renderedCells = [];
this.renderedKeys = []; this.renderedKeys = [];
this.renderRange = {};
this._scrollLock = false; this._scrollLock = false;
this._debounceRelease = BI.debounce(function () { this._debounceRelease = BI.debounce(function () {
self._scrollLock = false; self._scrollLock = false;
@ -2588,12 +2589,10 @@ BI.Collection = BI.inherit(BI.Widget, {
for (var index = 0, len = o.items.length; index < len; index++) { for (var index = 0, len = o.items.length; index < len; index++) {
var cellMetadatum = o.cellSizeAndPositionGetter(index); var cellMetadatum = o.cellSizeAndPositionGetter(index);
if ( if (cellMetadatum.height == null || isNaN(cellMetadatum.height) ||
cellMetadatum.height == null || isNaN(cellMetadatum.height) ||
cellMetadatum.width == null || isNaN(cellMetadatum.width) || cellMetadatum.width == null || isNaN(cellMetadatum.width) ||
cellMetadatum.x == null || isNaN(cellMetadatum.x) || cellMetadatum.x == null || isNaN(cellMetadatum.x) ||
cellMetadatum.y == null || isNaN(cellMetadatum.y) cellMetadatum.y == null || isNaN(cellMetadatum.y)) {
) {
throw Error(); throw Error();
} }
@ -2634,75 +2633,134 @@ BI.Collection = BI.inherit(BI.Widget, {
var top = Math.max(0, scrollTop - o.verticalOverscanSize); var top = Math.max(0, scrollTop - o.verticalOverscanSize);
var right = Math.min(this._width, scrollLeft + o.width + o.horizontalOverscanSize); var right = Math.min(this._width, scrollLeft + o.width + o.horizontalOverscanSize);
var bottom = Math.min(this._height, scrollTop + o.height + o.verticalOverscanSize); var bottom = Math.min(this._height, scrollTop + o.height + o.verticalOverscanSize);
var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top); if (right > 0 && bottom > 0) {
var renderedCells = [], renderedKeys = []; //如果滚动的区间并没有超出渲染的范围
for (var i = 0, len = childrenToDisplay.length; i < len; i++) { if (top >= this.renderRange.minY && bottom <= this.renderRange.maxY && left >= this.renderRange.minX && right <= this.renderRange.maxX) {
var datum = childrenToDisplay[i]; return;
var index = BI.deepIndexOf(this.renderedKeys, datum.index); }
if (index > -1) { var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top);
if (datum.width !== this.renderedCells[index]._width) { var renderedCells = [], renderedKeys = [];
this.renderedCells[index]._width = datum.width; //存储所有的left和top
this.renderedCells[index].el.setWidth(datum.width); 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; for (var i = 0, len = childrenToDisplay.length; i < len; i++) {
this.renderedCells[index].el.setHeight(datum.height); 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) { var startTopIndex = topMap[datum.y] | 0;
this.renderedCells[index].el.element.css("left", datum.x + "px"); 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) { var startLeftIndex = leftMap[datum.x] | 0;
this.renderedCells[index].el.element.css("top", datum.y + "px"); 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 { renderedKeys.push(datum.index);
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); //已存在的, 需要添加的和需要删除的
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 () { _getMaxScrollLeft: function () {
@ -2789,6 +2847,7 @@ BI.Collection = BI.inherit(BI.Widget, {
}); });
this.renderedCells = []; this.renderedCells = [];
this.renderedKeys = []; this.renderedKeys = [];
this.renderRange = {};
this._scrollLock = false; this._scrollLock = false;
}, },
@ -14613,6 +14672,7 @@ BI.Grid = BI.inherit(BI.Widget, {
var self = this, o = this.options; var self = this, o = this.options;
this.renderedCells = []; this.renderedCells = [];
this.renderedKeys = []; this.renderedKeys = [];
this.renderRange = {};
this._scrollLock = false; this._scrollLock = false;
this._debounceRelease = BI.debounce(function () { this._debounceRelease = BI.debounce(function () {
self._scrollLock = false; self._scrollLock = false;
@ -14661,13 +14721,17 @@ BI.Grid = BI.inherit(BI.Widget, {
_calculateChildrenToRender: function () { _calculateChildrenToRender: function () {
var self = this, o = this.options; 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; overscanColumnCount = o.overscanColumnCount, overscanRowCount = o.overscanRowCount;
if (height > 0 && width > 0) { if (height > 0 && width > 0) {
var visibleColumnIndices = this._columnSizeAndPositionManager.getVisibleCellRange(width, scrollLeft); var visibleColumnIndices = this._columnSizeAndPositionManager.getVisibleCellRange(width, scrollLeft);
var visibleRowIndices = this._rowSizeAndPositionManager.getVisibleCellRange(height, scrollTop); var visibleRowIndices = this._rowSizeAndPositionManager.getVisibleCellRange(height, scrollTop);
if (BI.isEmpty(visibleColumnIndices) || BI.isEmpty(visibleRowIndices)) {
return;
}
var horizontalOffsetAdjustment = this._columnSizeAndPositionManager.getOffsetAdjustment(width, scrollLeft); var horizontalOffsetAdjustment = this._columnSizeAndPositionManager.getOffsetAdjustment(width, scrollLeft);
var verticalOffsetAdjustment = this._rowSizeAndPositionManager.getOffsetAdjustment(height, scrollTop); var verticalOffsetAdjustment = this._rowSizeAndPositionManager.getOffsetAdjustment(height, scrollTop);
@ -14685,8 +14749,22 @@ BI.Grid = BI.inherit(BI.Widget, {
var rowStartIndex = overscanRowIndices.overscanStartIndex; var rowStartIndex = overscanRowIndices.overscanStartIndex;
var rowStopIndex = overscanRowIndices.overscanStopIndex; 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++) { for (var rowIndex = rowStartIndex; rowIndex <= rowStopIndex; rowIndex++) {
var rowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowIndex); var rowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowIndex);
@ -14731,6 +14809,10 @@ BI.Grid = BI.inherit(BI.Widget, {
_height: rowDatum.size _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); renderedKeys.push(key);
} }
} }
@ -14762,6 +14844,7 @@ BI.Grid = BI.inherit(BI.Widget, {
this.container.addItems(addedItems); this.container.addItems(addedItems);
this.renderedCells = renderedCells; this.renderedCells = renderedCells;
this.renderedKeys = renderedKeys; this.renderedKeys = renderedKeys;
this.renderRange = {minX: minX, minY: minY, maxX: maxX, maxY: maxY};
} }
}, },

23
bi/core.js

@ -2163,6 +2163,29 @@ if (!window.BI) {
return true; 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) { remove: function (obj, target, context) {
var isFunction = BI.isFunction(target); var isFunction = BI.isFunction(target);
target = isFunction || BI.isArray(target) ? target : [target]; target = isFunction || BI.isArray(target) ? target : [target];

221
docs/base.js

@ -2539,6 +2539,7 @@ BI.Collection = BI.inherit(BI.Widget, {
var self = this, o = this.options; var self = this, o = this.options;
this.renderedCells = []; this.renderedCells = [];
this.renderedKeys = []; this.renderedKeys = [];
this.renderRange = {};
this._scrollLock = false; this._scrollLock = false;
this._debounceRelease = BI.debounce(function () { this._debounceRelease = BI.debounce(function () {
self._scrollLock = false; self._scrollLock = false;
@ -2588,12 +2589,10 @@ BI.Collection = BI.inherit(BI.Widget, {
for (var index = 0, len = o.items.length; index < len; index++) { for (var index = 0, len = o.items.length; index < len; index++) {
var cellMetadatum = o.cellSizeAndPositionGetter(index); var cellMetadatum = o.cellSizeAndPositionGetter(index);
if ( if (cellMetadatum.height == null || isNaN(cellMetadatum.height) ||
cellMetadatum.height == null || isNaN(cellMetadatum.height) ||
cellMetadatum.width == null || isNaN(cellMetadatum.width) || cellMetadatum.width == null || isNaN(cellMetadatum.width) ||
cellMetadatum.x == null || isNaN(cellMetadatum.x) || cellMetadatum.x == null || isNaN(cellMetadatum.x) ||
cellMetadatum.y == null || isNaN(cellMetadatum.y) cellMetadatum.y == null || isNaN(cellMetadatum.y)) {
) {
throw Error(); throw Error();
} }
@ -2634,75 +2633,134 @@ BI.Collection = BI.inherit(BI.Widget, {
var top = Math.max(0, scrollTop - o.verticalOverscanSize); var top = Math.max(0, scrollTop - o.verticalOverscanSize);
var right = Math.min(this._width, scrollLeft + o.width + o.horizontalOverscanSize); var right = Math.min(this._width, scrollLeft + o.width + o.horizontalOverscanSize);
var bottom = Math.min(this._height, scrollTop + o.height + o.verticalOverscanSize); var bottom = Math.min(this._height, scrollTop + o.height + o.verticalOverscanSize);
var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top); if (right > 0 && bottom > 0) {
var renderedCells = [], renderedKeys = []; //如果滚动的区间并没有超出渲染的范围
for (var i = 0, len = childrenToDisplay.length; i < len; i++) { if (top >= this.renderRange.minY && bottom <= this.renderRange.maxY && left >= this.renderRange.minX && right <= this.renderRange.maxX) {
var datum = childrenToDisplay[i]; return;
var index = BI.deepIndexOf(this.renderedKeys, datum.index); }
if (index > -1) { var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top);
if (datum.width !== this.renderedCells[index]._width) { var renderedCells = [], renderedKeys = [];
this.renderedCells[index]._width = datum.width; //存储所有的left和top
this.renderedCells[index].el.setWidth(datum.width); 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; for (var i = 0, len = childrenToDisplay.length; i < len; i++) {
this.renderedCells[index].el.setHeight(datum.height); 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) { var startTopIndex = topMap[datum.y] | 0;
this.renderedCells[index].el.element.css("left", datum.x + "px"); 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) { var startLeftIndex = leftMap[datum.x] | 0;
this.renderedCells[index].el.element.css("top", datum.y + "px"); 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 { renderedKeys.push(datum.index);
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); //已存在的, 需要添加的和需要删除的
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 () { _getMaxScrollLeft: function () {
@ -2789,6 +2847,7 @@ BI.Collection = BI.inherit(BI.Widget, {
}); });
this.renderedCells = []; this.renderedCells = [];
this.renderedKeys = []; this.renderedKeys = [];
this.renderRange = {};
this._scrollLock = false; this._scrollLock = false;
}, },
@ -14613,6 +14672,7 @@ BI.Grid = BI.inherit(BI.Widget, {
var self = this, o = this.options; var self = this, o = this.options;
this.renderedCells = []; this.renderedCells = [];
this.renderedKeys = []; this.renderedKeys = [];
this.renderRange = {};
this._scrollLock = false; this._scrollLock = false;
this._debounceRelease = BI.debounce(function () { this._debounceRelease = BI.debounce(function () {
self._scrollLock = false; self._scrollLock = false;
@ -14661,13 +14721,17 @@ BI.Grid = BI.inherit(BI.Widget, {
_calculateChildrenToRender: function () { _calculateChildrenToRender: function () {
var self = this, o = this.options; 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; overscanColumnCount = o.overscanColumnCount, overscanRowCount = o.overscanRowCount;
if (height > 0 && width > 0) { if (height > 0 && width > 0) {
var visibleColumnIndices = this._columnSizeAndPositionManager.getVisibleCellRange(width, scrollLeft); var visibleColumnIndices = this._columnSizeAndPositionManager.getVisibleCellRange(width, scrollLeft);
var visibleRowIndices = this._rowSizeAndPositionManager.getVisibleCellRange(height, scrollTop); var visibleRowIndices = this._rowSizeAndPositionManager.getVisibleCellRange(height, scrollTop);
if (BI.isEmpty(visibleColumnIndices) || BI.isEmpty(visibleRowIndices)) {
return;
}
var horizontalOffsetAdjustment = this._columnSizeAndPositionManager.getOffsetAdjustment(width, scrollLeft); var horizontalOffsetAdjustment = this._columnSizeAndPositionManager.getOffsetAdjustment(width, scrollLeft);
var verticalOffsetAdjustment = this._rowSizeAndPositionManager.getOffsetAdjustment(height, scrollTop); var verticalOffsetAdjustment = this._rowSizeAndPositionManager.getOffsetAdjustment(height, scrollTop);
@ -14685,8 +14749,22 @@ BI.Grid = BI.inherit(BI.Widget, {
var rowStartIndex = overscanRowIndices.overscanStartIndex; var rowStartIndex = overscanRowIndices.overscanStartIndex;
var rowStopIndex = overscanRowIndices.overscanStopIndex; 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++) { for (var rowIndex = rowStartIndex; rowIndex <= rowStopIndex; rowIndex++) {
var rowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowIndex); var rowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowIndex);
@ -14731,6 +14809,10 @@ BI.Grid = BI.inherit(BI.Widget, {
_height: rowDatum.size _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); renderedKeys.push(key);
} }
} }
@ -14762,6 +14844,7 @@ BI.Grid = BI.inherit(BI.Widget, {
this.container.addItems(addedItems); this.container.addItems(addedItems);
this.renderedCells = renderedCells; this.renderedCells = renderedCells;
this.renderedKeys = renderedKeys; this.renderedKeys = renderedKeys;
this.renderRange = {minX: minX, minY: minY, maxX: maxX, maxY: maxY};
} }
}, },

23
docs/core.js

@ -13305,6 +13305,29 @@ if (!window.BI) {
return true; 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) { remove: function (obj, target, context) {
var isFunction = BI.isFunction(target); var isFunction = BI.isFunction(target);
target = isFunction || BI.isArray(target) ? target : [target]; target = isFunction || BI.isArray(target) ? target : [target];

193
src/base/collection/collection.js

@ -27,6 +27,7 @@ BI.Collection = BI.inherit(BI.Widget, {
var self = this, o = this.options; var self = this, o = this.options;
this.renderedCells = []; this.renderedCells = [];
this.renderedKeys = []; this.renderedKeys = [];
this.renderRange = {};
this._scrollLock = false; this._scrollLock = false;
this._debounceRelease = BI.debounce(function () { this._debounceRelease = BI.debounce(function () {
self._scrollLock = false; self._scrollLock = false;
@ -76,12 +77,10 @@ BI.Collection = BI.inherit(BI.Widget, {
for (var index = 0, len = o.items.length; index < len; index++) { for (var index = 0, len = o.items.length; index < len; index++) {
var cellMetadatum = o.cellSizeAndPositionGetter(index); var cellMetadatum = o.cellSizeAndPositionGetter(index);
if ( if (cellMetadatum.height == null || isNaN(cellMetadatum.height) ||
cellMetadatum.height == null || isNaN(cellMetadatum.height) ||
cellMetadatum.width == null || isNaN(cellMetadatum.width) || cellMetadatum.width == null || isNaN(cellMetadatum.width) ||
cellMetadatum.x == null || isNaN(cellMetadatum.x) || cellMetadatum.x == null || isNaN(cellMetadatum.x) ||
cellMetadatum.y == null || isNaN(cellMetadatum.y) cellMetadatum.y == null || isNaN(cellMetadatum.y)) {
) {
throw Error(); throw Error();
} }
@ -122,75 +121,134 @@ BI.Collection = BI.inherit(BI.Widget, {
var top = Math.max(0, scrollTop - o.verticalOverscanSize); var top = Math.max(0, scrollTop - o.verticalOverscanSize);
var right = Math.min(this._width, scrollLeft + o.width + o.horizontalOverscanSize); var right = Math.min(this._width, scrollLeft + o.width + o.horizontalOverscanSize);
var bottom = Math.min(this._height, scrollTop + o.height + o.verticalOverscanSize); var bottom = Math.min(this._height, scrollTop + o.height + o.verticalOverscanSize);
var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top); if (right > 0 && bottom > 0) {
var renderedCells = [], renderedKeys = []; //如果滚动的区间并没有超出渲染的范围
for (var i = 0, len = childrenToDisplay.length; i < len; i++) { if (top >= this.renderRange.minY && bottom <= this.renderRange.maxY && left >= this.renderRange.minX && right <= this.renderRange.maxX) {
var datum = childrenToDisplay[i]; return;
var index = BI.deepIndexOf(this.renderedKeys, datum.index); }
if (index > -1) { var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top);
if (datum.width !== this.renderedCells[index]._width) { var renderedCells = [], renderedKeys = [];
this.renderedCells[index]._width = datum.width; //存储所有的left和top
this.renderedCells[index].el.setWidth(datum.width); 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; var assertMaxBorder = function (border, offset) {
this.renderedCells[index].el.setHeight(datum.height); 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) { var startTopIndex = topMap[datum.y] | 0;
this.renderedCells[index].el.element.css("top", datum.y + "px"); 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]); var startLeftIndex = leftMap[datum.x] | 0;
} else { var endLeftIndex = leftMap[datum.x + datum.width] | 0;
var child = BI.createWidget(BI.extend({ for (var k = startLeftIndex; k <= endLeftIndex; k++) {
type: "bi.label", var l = lefts[k];
width: datum.width, assertMinBorder(topBorder, l);
height: datum.height assertMaxBorder(bottomBorder, l);
}, o.items[datum.index], { topBorder[l] = Math.min(topBorder[l], datum.y);
cls: (o.items[datum.index].cls || "") + " container-cell" + (datum.y === 0 ? " first-row" : "") + (datum.x === 0 ? " first-col" : ""), bottomBorder[l] = Math.max(bottomBorder[l], datum.y + datum.height);
_left: datum.x, }
_top: datum.y
})); renderedKeys.push(datum.index);
renderedCells.push({
el: child,
left: datum.x,
top: datum.y,
_width: datum.width,
_height: datum.height
});
} }
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 () { _getMaxScrollLeft: function () {
@ -277,6 +335,7 @@ BI.Collection = BI.inherit(BI.Widget, {
}); });
this.renderedCells = []; this.renderedCells = [];
this.renderedKeys = []; this.renderedKeys = [];
this.renderRange = {};
this._scrollLock = false; this._scrollLock = false;
}, },

28
src/base/grid/grid.js

@ -30,6 +30,7 @@ BI.Grid = BI.inherit(BI.Widget, {
var self = this, o = this.options; var self = this, o = this.options;
this.renderedCells = []; this.renderedCells = [];
this.renderedKeys = []; this.renderedKeys = [];
this.renderRange = {};
this._scrollLock = false; this._scrollLock = false;
this._debounceRelease = BI.debounce(function () { this._debounceRelease = BI.debounce(function () {
self._scrollLock = false; self._scrollLock = false;
@ -78,13 +79,17 @@ BI.Grid = BI.inherit(BI.Widget, {
_calculateChildrenToRender: function () { _calculateChildrenToRender: function () {
var self = this, o = this.options; 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; overscanColumnCount = o.overscanColumnCount, overscanRowCount = o.overscanRowCount;
if (height > 0 && width > 0) { if (height > 0 && width > 0) {
var visibleColumnIndices = this._columnSizeAndPositionManager.getVisibleCellRange(width, scrollLeft); var visibleColumnIndices = this._columnSizeAndPositionManager.getVisibleCellRange(width, scrollLeft);
var visibleRowIndices = this._rowSizeAndPositionManager.getVisibleCellRange(height, scrollTop); var visibleRowIndices = this._rowSizeAndPositionManager.getVisibleCellRange(height, scrollTop);
if (BI.isEmpty(visibleColumnIndices) || BI.isEmpty(visibleRowIndices)) {
return;
}
var horizontalOffsetAdjustment = this._columnSizeAndPositionManager.getOffsetAdjustment(width, scrollLeft); var horizontalOffsetAdjustment = this._columnSizeAndPositionManager.getOffsetAdjustment(width, scrollLeft);
var verticalOffsetAdjustment = this._rowSizeAndPositionManager.getOffsetAdjustment(height, scrollTop); var verticalOffsetAdjustment = this._rowSizeAndPositionManager.getOffsetAdjustment(height, scrollTop);
@ -102,8 +107,22 @@ BI.Grid = BI.inherit(BI.Widget, {
var rowStartIndex = overscanRowIndices.overscanStartIndex; var rowStartIndex = overscanRowIndices.overscanStartIndex;
var rowStopIndex = overscanRowIndices.overscanStopIndex; 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++) { for (var rowIndex = rowStartIndex; rowIndex <= rowStopIndex; rowIndex++) {
var rowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowIndex); var rowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowIndex);
@ -148,6 +167,10 @@ BI.Grid = BI.inherit(BI.Widget, {
_height: rowDatum.size _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); renderedKeys.push(key);
} }
} }
@ -179,6 +202,7 @@ BI.Grid = BI.inherit(BI.Widget, {
this.container.addItems(addedItems); this.container.addItems(addedItems);
this.renderedCells = renderedCells; this.renderedCells = renderedCells;
this.renderedKeys = renderedKeys; this.renderedKeys = renderedKeys;
this.renderRange = {minX: minX, minY: minY, maxX: maxX, maxY: maxY};
} }
}, },

23
src/core/base.js

@ -268,6 +268,29 @@ if (!window.BI) {
return true; 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) { remove: function (obj, target, context) {
var isFunction = BI.isFunction(target); var isFunction = BI.isFunction(target);
target = isFunction || BI.isArray(target) ? target : [target]; target = isFunction || BI.isArray(target) ? target : [target];

Loading…
Cancel
Save