forked from fanruan/fineui
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
361 lines
14 KiB
361 lines
14 KiB
/** |
|
* Created By Shichao on 2017/10/17 |
|
* @class BI.CanvasCollectionView |
|
* @extends BI.Widget |
|
*/ |
|
BI.CanvasCollectionView = BI.inherit(BI.Widget, { |
|
_defaultConfig: function () { |
|
return BI.extend(BI.CanvasCollectionView.superclass._defaultConfig.apply(this, arguments), { |
|
baseCls: "bi-canvas-collection", |
|
overflowX: true, |
|
overflowY: true, |
|
cellSizeAndPositionGetter: BI.emptyFn, |
|
horizontalOverscanSize: 0, |
|
verticalOverscanSize: 0, |
|
scrollLeft: 0, |
|
scrollTop: 0, |
|
items: [] |
|
}) |
|
}, |
|
|
|
_init: function () { |
|
BI.CanvasCollectionView.superclass._init.apply(this, arguments); |
|
var self = this, o = this.options; |
|
this.renderedCells = []; |
|
this.renderedKeys = []; |
|
this._scrollLock = false; |
|
this.scrollTop = this.scrollLeft = 0; |
|
this.summaryScrollTop = this.summaryScrollLeft = 0; |
|
this._debounceRelease = BI.debounce(function () { |
|
self._scrollLock = false; |
|
}, 1000 / 60); |
|
this.canvas = BI.createWidget({ |
|
type: "bi.canvas_new" |
|
}); |
|
$(document).keydown(BI.bind(this._onResize, this)); // 防止在使用ctrl + 滚轮调整窗口大小时触发mousewheel事件 |
|
$(document).keyup(BI.bind(this._onResizeRelease, this)) |
|
this.element.mousewheel(BI.bind(this._onMouseWheel, this)) |
|
BI.createWidget({ |
|
type: "bi.vertical", |
|
element: this, |
|
scrollable: false, |
|
scrolly: false, |
|
scrollx: false, |
|
items: [this.canvas] |
|
}); |
|
if (o.items.length > 0) { |
|
this._calculateSizeAndPositionData(); |
|
this._populate(); |
|
} |
|
if (o.scrollLeft !== 0 || o.scrollTop !== 0) { |
|
BI.nextTick(function () { |
|
self.element.scrollTop(o.scrollTop); |
|
self.element.scrollLeft(o.scrollLeft); |
|
}); |
|
} |
|
}, |
|
|
|
_onMouseWheel: function (e) { |
|
var o = this.options; |
|
if (this._scrollLock) { |
|
return; |
|
} |
|
if (!this._isCtrlPressed) { |
|
o.scrollTop += -e.originalEvent.wheelDelta; |
|
o.scrollTop = BI.clamp(o.scrollTop, 0, this.maxScrollTop); |
|
this._calculateChildrenToRender(); |
|
this.fireEvent(BI.CanvasCollectionView.EVENT_SCROLL, { |
|
scrollLeft: o.scrollLeft, |
|
scrollTop: o.scrollTop |
|
}); |
|
} |
|
}, |
|
|
|
_onResize: function (e) { |
|
if (e.ctrlKey) { |
|
this._isCtrlPressed = true; |
|
} else { |
|
this._isCtrlPressed = false; |
|
} |
|
}, |
|
|
|
_onResizeRelease: function (e) { |
|
var Keys = { |
|
CTRL: 17 |
|
}; |
|
var keyCode = e.keyCode; |
|
|
|
if (keyCode === Keys.CTRL) { |
|
this._isCtrlPressed = false; |
|
} |
|
}, |
|
|
|
_getMaxScrollTop: function () { |
|
return this._height - this.options.height |
|
}, |
|
|
|
_calculateSizeAndPositionData: function () { |
|
var o = this.options; |
|
var cellMetadata = []; |
|
var sectionManager = new BI.SectionManager(); |
|
var height = 0; |
|
var width = 0; |
|
|
|
for (var index = 0, len = o.items.length; index < len; index++) { |
|
var cellMetadatum = o.cellSizeAndPositionGetter(index); |
|
|
|
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)) { |
|
throw Error(); |
|
} |
|
|
|
height = Math.max(height, cellMetadatum.y + cellMetadatum.height); |
|
width = Math.max(width, cellMetadatum.x + cellMetadatum.width); |
|
|
|
cellMetadatum.index = index; |
|
cellMetadata[index] = cellMetadatum; |
|
sectionManager.registerCell(cellMetadatum, index); |
|
} |
|
|
|
this._cellMetadata = cellMetadata; |
|
this._sectionManager = sectionManager; |
|
if (this._height === height && this._width === width) { |
|
this._isNeedReset = false; |
|
} else { |
|
this._height = height; |
|
this._width = width; |
|
this._isNeedReset = true; |
|
} |
|
this.maxScrollTop = this._getMaxScrollTop(); |
|
}, |
|
|
|
_cellRenderers: function (height, width, x, y) { |
|
this._lastRenderedCellIndices = this._sectionManager.getCellIndices(height, width, x, y); |
|
return this._cellGroupRenderer(); |
|
}, |
|
|
|
_cellGroupRenderer: function () { |
|
var self = this, o = this.options; |
|
var rendered = []; |
|
BI.each(this._lastRenderedCellIndices, function (i, index) { |
|
var cellMetadata = self._sectionManager.getCellMetadata(index); |
|
rendered.push(cellMetadata); |
|
}); |
|
return rendered; |
|
}, |
|
|
|
_calculateChildrenToRender: function () { |
|
var x, y, cellWidth, cellHeight, cellRow, cellCol, value, self = this, o = this.options; |
|
var scrollLeft = o.scrollLeft; |
|
var scrollTop = o.scrollTop; |
|
var left = Math.max(0, scrollLeft - o.horizontalOverscanSize); |
|
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); |
|
if (right > 0 && bottom > 0) { |
|
var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top); |
|
this.canvas.remove(this.scrollLeft, this.scrollTop, o.width, o.height); |
|
for (var i = 0; i < childrenToDisplay.length; i++) { |
|
var datum = childrenToDisplay[i]; |
|
var index = this.renderedKeys[datum.index] && this.renderedKeys[datum.index][1]; |
|
var rect_tl_x = datum.x, |
|
rect_tl_y = datum.y, |
|
rect_tr_x = rect_tl_x + datum.width, |
|
rect_bl_y = rect_tl_y + datum.height, |
|
cell = o.items[datum.index].cell || o.items[datum.index], |
|
background, color, fontWeight, text; |
|
while (BI.isNull(cell.styles) && !BI.isFunction(cell.styleGetter)) { |
|
cell = cell.cell; |
|
} |
|
if (BI.isNull(cell.styles) && BI.isFunction(cell.styleGetter)) { |
|
background = cell.styleGetter().background; |
|
color = cell.styleGetter().color; |
|
fontWeight = cell.styleGetter().fontWeight; |
|
} else if (!BI.isNull(cell.styles)) { |
|
background = cell.styles.background; |
|
color = cell.styles.color; |
|
fontWeight = cell.styles.fontWeight; |
|
} |
|
if (BI.isNull(cell.text)) { |
|
text = ""; |
|
} else { |
|
text = cell.text; |
|
} |
|
if (!BI.isString(text)) { |
|
text = text.toString(); |
|
} |
|
if (this.scrollLeft !== o.scrollLeft) { |
|
this.canvas.translate(this.scrollLeft - o.scrollLeft, 0); |
|
this.scrollLeft = o.scrollLeft; |
|
} |
|
if (this.scrollTop !== o.scrollTop) { |
|
this.canvas.translate(0, this.scrollTop - o.scrollTop); |
|
this.scrollTop = o.scrollTop; |
|
} |
|
if (datum.x === 0 && datum.y === 0) { |
|
this.canvas.solid(rect_tl_x, rect_tl_y, rect_tl_x, rect_bl_y, rect_tr_x, rect_bl_y, rect_tr_x, rect_tl_y, rect_tl_x, rect_tl_y, { |
|
strokeStyle: "rgb(212, 218, 221)", |
|
fillStyle: background |
|
}); |
|
} else if (datum.x === 0) { |
|
this.canvas.solid(rect_tl_x, rect_tl_y, rect_tl_x, rect_bl_y, rect_tr_x, rect_bl_y, rect_tr_x, rect_tl_y, { |
|
strokeStyle: "rgb(212, 218, 221)", |
|
fillStyle: background |
|
}); |
|
} else if (datum.y === 0) { |
|
this.canvas.solid(rect_tl_x, rect_tl_y, rect_tr_x, rect_tl_y, rect_tr_x, rect_bl_y, rect_tl_x, rect_bl_y, { |
|
strokeStyle: "rgb(212, 218, 221)", |
|
fillStyle: background |
|
}); |
|
} else { |
|
this.canvas.solid(rect_tr_x, rect_tl_y, rect_tl_x, rect_tl_y, rect_tl_x, rect_bl_y, rect_tr_x, rect_bl_y, { |
|
strokeStyle: "rgb(212, 218, 221)", |
|
fillStyle: background |
|
}); |
|
} |
|
this.canvas.setFontWeight(fontWeight); |
|
this.canvas.setFont(); |
|
var font = this.canvas.getContext().font, |
|
textSize = this._getTextPixel(font), |
|
textHeight = textSize, |
|
textWidth = this.canvas.getContext().measureText(text).width, |
|
dotsWidth = this.canvas.getContext().measureText("...").width; |
|
var offsetX = this._calcOffsetX(textWidth, datum.width, "center"), |
|
offsetY = this._calcOffsetY(textHeight, datum.height, "center"); |
|
if (textHeight > datum.height) { |
|
this.canvas.text(datum.x + offsetX, datum.y + offsetY, "...", color); |
|
} else if (textWidth + 4 > datum.width) { |
|
var sliceIndex = Math.floor((datum.width - dotsWidth - 4) / textWidth * text.length); |
|
this.canvas.text(datum.x + offsetX, datum.y + offsetY, text.slice(0, sliceIndex) + "...", color); |
|
} else { |
|
this.canvas.text(datum.x + offsetX, datum.y + offsetY, text, color); |
|
} |
|
this.canvas.stroke(); |
|
} |
|
} |
|
}, |
|
|
|
_getTextPixel: function (font) { |
|
var p = font.split("px")[0], |
|
s = p.split(" "); |
|
for (var c in s) { |
|
var num; |
|
num = BI.parseInt(s[c]); |
|
if (!BI.isNaN(num)) { |
|
return num; |
|
} |
|
} |
|
}, |
|
|
|
_calcOffsetX: function (textWidth, cellWidth, position) { |
|
switch (position) { |
|
case "center": |
|
if (textWidth >= cellWidth) { |
|
return 4; |
|
} else { |
|
return (cellWidth - textWidth) / 2; |
|
} |
|
case "right": |
|
if (textWidth >= cellWidth) { |
|
return 0; |
|
} else { |
|
return cellWidth - textWidth; |
|
} |
|
default: |
|
return 0; |
|
} |
|
}, |
|
|
|
_calcOffsetY: function (textHeight, cellHeight, position) { |
|
switch (position) { |
|
case "center": |
|
if (textHeight >= cellHeight) { |
|
return textHeight; |
|
} else { |
|
return (cellHeight + textHeight) / 2; |
|
} |
|
case "bottom": |
|
if (textHeight >= cellHeight) { |
|
return cellHeight; |
|
} else { |
|
return cellHeight + textHeight; |
|
} |
|
default: |
|
return textHeight; |
|
} |
|
}, |
|
|
|
_populate: function (items) { |
|
var o = this.options; |
|
if (items && items !== this.options.items) { |
|
this.options.items = items; |
|
this._calculateSizeAndPositionData(); |
|
} |
|
if (o.items.length > 0) { |
|
this.canvas.setBlock(); |
|
this.canvas.setWidth(o.width); |
|
this.canvas.setHeight(o.height); |
|
this.restore(); |
|
this._calculateChildrenToRender(); |
|
this.element.scrollTop(o.scrollTop); |
|
this.element.scrollLeft(o.scrollLeft); |
|
} |
|
}, |
|
|
|
populate: function (items) { |
|
if (items && items !== this.options.items) { |
|
this.restore(); |
|
} |
|
this._populate(items); |
|
}, |
|
|
|
setWidth: function (width) { |
|
BI.CanvasCollectionView.superclass.setWidth.apply(this, arguments); |
|
this.options.width = width; |
|
}, |
|
|
|
setHeight: function (height) { |
|
BI.CanvasCollectionView.superclass.setHeight.apply(this, arguments); |
|
this.options.height = height; |
|
}, |
|
|
|
restore: function () { |
|
this.canvas.remove(this.scrollLeft, this.scrollTop, this.options.width, this.options.height); |
|
this.renderedKeys = []; |
|
this._scrollLock = false; |
|
}, |
|
|
|
setScrollLeft: function (scrollLeft) { |
|
if (this.options.scrollLeft === scrollLeft) { |
|
return; |
|
} |
|
this._scrollLock = true; |
|
this.options.scrollLeft = scrollLeft; |
|
this._debounceRelease(); |
|
this._calculateChildrenToRender(); |
|
this.element.scrollLeft(this.options.scrollLeft); |
|
}, |
|
|
|
setScrollTop: function (scrollTop) { |
|
if (this.options.scrollTop === scrollTop) { |
|
return; |
|
} |
|
this._scrollLock = true; |
|
this.options.scrollTop = scrollTop; |
|
this._debounceRelease(); |
|
this._calculateChildrenToRender(); |
|
this.element.scrollTop(this.options.scrollTop); |
|
}, |
|
|
|
getScrollLeft: function () { |
|
return this.options.scrollLeft; |
|
}, |
|
|
|
getScrollTop: function () { |
|
return this.options.scrollTop; |
|
} |
|
}) |
|
BI.CanvasCollectionView.EVENT_SCROLL = "EVENT_SCROLL"; |
|
BI.shortcut("bi.canvas_collection_view", BI.CanvasCollectionView); |