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.
1040 lines
35 KiB
1040 lines
35 KiB
/** |
|
* 布局 |
|
* |
|
* Created by GUY on 2016/2/23. |
|
* @class BI.Arrangement |
|
* @extends BI.Widget |
|
*/ |
|
BI.Arrangement = BI.inherit(BI.Widget, { |
|
|
|
_defaultConfig: function () { |
|
return BI.extend(BI.Arrangement.superclass._defaultConfig.apply(this, arguments), { |
|
baseCls: "bi-arrangement", |
|
layoutType: BI.Arrangement.LAYOUT_TYPE.GRID, |
|
items: [] |
|
}); |
|
}, |
|
|
|
_init: function () { |
|
BI.Arrangement.superclass._init.apply(this, arguments); |
|
var self = this, o = this.options; |
|
this.arrangement = BI.createWidget({ |
|
type: "bi.arrangement_droppable", |
|
cls: "arrangement-block", |
|
invisible: true |
|
}); |
|
this.block = BI.createWidget({ |
|
type: "bi.arrangement_block", |
|
invisible: true |
|
}); |
|
this.container = BI.createWidget({ |
|
type: "bi.absolute", |
|
items: o.items.concat([this.block, this.arrangement]) |
|
}); |
|
|
|
this.scrollContainer = BI.createWidget({ |
|
type: "bi.adaptive", |
|
width: "100%", |
|
height: "100%", |
|
scrollable: true, |
|
items: [this.container] |
|
}); |
|
this.scrollContainer.element.scroll(function () { |
|
self.fireEvent(BI.Arrangement.EVENT_SCROLL, { |
|
scrollLeft: self.scrollContainer.element.scrollLeft(), |
|
scrollTop: self.scrollContainer.element.scrollTop(), |
|
clientWidth: self.scrollContainer.element[0].clientWidth, |
|
clientHeight: self.scrollContainer.element[0].clientHeight |
|
}); |
|
}); |
|
|
|
BI.createWidget({ |
|
type: "bi.adaptive", |
|
element: this, |
|
items: [this.scrollContainer] |
|
}); |
|
this.regions = {}; |
|
if (o.items.length > 0) { |
|
BI.nextTick(function () { |
|
self.populate(o.items); |
|
}); |
|
} |
|
}, |
|
|
|
////初始化操作//// |
|
_calculateRegions: function (items) { |
|
var self = this, o = this.options; |
|
this.regions = {}; |
|
BI.each(items, function (i, item) { |
|
var region = self._createOneRegion(item); |
|
self.regions[region.id] = region; |
|
}); |
|
}, |
|
|
|
_isEqual: function (num1, num2) { |
|
return Math.abs(num1 - num2) < 2; |
|
}, |
|
|
|
_isLessThan: function (num1, num2) { |
|
return num1 < num2 && !this._isEqual(num1, num2); |
|
}, |
|
|
|
_isMoreThan: function (num1, num2) { |
|
return num1 > num2 && !this._isEqual(num1, num2); |
|
}, |
|
|
|
_isLessThanEqual: function (num1, num2) { |
|
return num1 <= num2 || this._isEqual(num1, num2); |
|
}, |
|
|
|
_isMoreThanEqual: function (num1, num2) { |
|
return num1 >= num2 || this._isEqual(num1, num2); |
|
}, |
|
|
|
//获取占有的最大Region |
|
_getRegionOccupied: function (regions) { |
|
var self = this, o = this.options; |
|
if (BI.size(regions || this.regions) <= 0) { |
|
return { |
|
left: 0, |
|
top: 0, |
|
width: 0, |
|
height: 0 |
|
} |
|
} |
|
var minLeft = BI.MAX, maxLeft = BI.MIN, minTop = BI.MAX, maxTop = BI.MIN; |
|
BI.each(regions || this.regions, function (id, region) { |
|
minLeft = Math.min(minLeft, region.left); |
|
maxLeft = Math.max(maxLeft, region.left + region.width); |
|
minTop = Math.min(minTop, region.top); |
|
maxTop = Math.max(maxTop, region.top + region.height); |
|
}); |
|
return { |
|
left: minLeft, |
|
top: minTop, |
|
width: maxLeft - minLeft, |
|
height: maxTop - minTop |
|
} |
|
}, |
|
|
|
//两个区域的交叉面积 |
|
_getCrossArea: function (region1, region2) { |
|
if (region1.left <= region2.left) { |
|
if (region1.top <= region2.top) { |
|
if (region1.top + region1.height > region2.top && region1.left + region1.width > region2.left) { |
|
if (this._isEqual(region1.top + region1.height, region2.top) || this._isEqual(region1.left + region1.width, region2.left)) { |
|
return 0; |
|
} |
|
return (region1.top + region1.height - region2.top) * (region1.left + region1.width - region2.left); |
|
} |
|
} else { |
|
if (region2.top + region2.height > region1.top && region1.left + region1.width > region2.left) { |
|
if (this._isEqual(region2.top + region2.height, region1.top) || this._isEqual(region1.left + region1.width, region2.left)) { |
|
return 0; |
|
} |
|
return (region2.top + region2.height - region1.top) * (region1.left + region1.width - region2.left); |
|
} |
|
} |
|
} else { |
|
if (region1.top <= region2.top) { |
|
if (region1.top + region1.height > region2.top && region2.left + region2.width > region1.left) { |
|
if (this._isEqual(region1.top + region1.height, region2.top) || this._isEqual(region2.left + region2.width, region1.left)) { |
|
return 0; |
|
} |
|
return (region1.top + region1.height - region2.top) * (region2.left + region2.width - region1.left); |
|
} |
|
} else { |
|
if (region2.top + region2.height > region1.top && region2.left + region2.width > region1.left) { |
|
if (this._isEqual(region2.top + region2.height, region1.top) || this._isEqual(region2.left + region2.width, region1.left)) { |
|
return 0; |
|
} |
|
return (region2.top + region2.height - region1.top) * (region2.left + region2.width - region1.left); |
|
} |
|
} |
|
} |
|
return 0; |
|
}, |
|
|
|
//是否有覆盖的组件 |
|
_isRegionOverlay: function (regions) { |
|
var reg = []; |
|
BI.each(regions || this.regions, function (id, region) { |
|
reg.push(new BI.Region(region.left, region.top, region.width, region.height)); |
|
}); |
|
for (var i = 0, len = reg.length; i < len; i++) { |
|
for (var j = i + 1; j < len; j++) { |
|
var area1 = { |
|
left: reg[i].x, |
|
top: reg[i].y, |
|
width: reg[i].w, |
|
height: reg[i].h |
|
}; |
|
var area2 = { |
|
left: reg[j].x, |
|
top: reg[j].y, |
|
width: reg[j].w, |
|
height: reg[j].h |
|
}; |
|
if (reg[i].isIntersects(reg[j]) && this._getCrossArea(area1, area2) > 1) { |
|
return true; |
|
} |
|
} |
|
} |
|
return false; |
|
}, |
|
|
|
//布局是否是优良的 |
|
_isArrangeFine: function (regions) { |
|
switch (this.options.layoutType) { |
|
case BI.Arrangement.LAYOUT_TYPE.FREE: |
|
return true; |
|
case BI.Arrangement.LAYOUT_TYPE.GRID: |
|
if (this._isRegionOverlay()) { |
|
return false; |
|
} |
|
} |
|
return true; |
|
}, |
|
|
|
_getRegionNames: function (regions) { |
|
var names = []; |
|
BI.each(regions || this.regions, function (i, region) { |
|
names.push(region.id || region.attr("id")); |
|
}); |
|
return names; |
|
}, |
|
|
|
_getRegionsByNames: function (names, regions) { |
|
names = BI.isArray(names) ? names : [names]; |
|
regions = regions || this.regions; |
|
if (BI.isArray(regions)) { |
|
var result = []; |
|
BI.each(regions, function (i, region) { |
|
if (names.contains(region.id || region.attr("id"))) { |
|
result.push(region); |
|
} |
|
}); |
|
} else { |
|
var result = {}; |
|
BI.each(names, function (i, name) { |
|
result[name] = regions[name]; |
|
}); |
|
} |
|
return result; |
|
}, |
|
|
|
_cloneRegion: function (regions) { |
|
var clone = {}; |
|
BI.each(regions || this.regions, function (id, region) { |
|
clone[id] = {}; |
|
clone[id].el = region.el; |
|
clone[id].id = region.id; |
|
clone[id].left = region.left; |
|
clone[id].top = region.top; |
|
clone[id].width = region.width; |
|
clone[id].height = region.height; |
|
}); |
|
return clone; |
|
}, |
|
|
|
//测试合法性 |
|
_test: function (regions) { |
|
var self = this; |
|
return !BI.any(regions || this.regions, function (i, region) { |
|
if (BI.isNaN(region.width) || BI.isNaN(region.height) || region.width <= 21 || region.height <= 21) { |
|
return true; |
|
} |
|
}) |
|
}, |
|
|
|
_getScrollOffset: function () { |
|
return { |
|
left: this.scrollContainer.element[0].scrollLeft, |
|
top: this.scrollContainer.element[0].scrollTop |
|
} |
|
}, |
|
|
|
////操作//// |
|
_createOneRegion: function (item) { |
|
var el = BI.createWidget(item.el); |
|
el.setVisible(true); |
|
return { |
|
id: el.attr("id"), |
|
left: item.left, |
|
top: item.top, |
|
width: item.width, |
|
height: item.height, |
|
el: el |
|
} |
|
}, |
|
|
|
_applyRegion: function (regions) { |
|
var self = this, o = this.options; |
|
BI.each(regions || this.regions, function (i, region) { |
|
region.el.element.css({ |
|
left: region.left, |
|
top: region.top, |
|
width: region.width, |
|
height: region.height |
|
}); |
|
}); |
|
this._applyContainer(); |
|
this.ratio = this.getLayoutRatio(); |
|
}, |
|
|
|
_renderRegion: function () { |
|
var self = this; |
|
BI.createWidget({ |
|
type: "bi.absolute", |
|
element: this.container, |
|
items: BI.toArray(this.regions) |
|
}); |
|
}, |
|
|
|
getClientWidth: function () { |
|
return this.scrollContainer.element[0].clientWidth; |
|
}, |
|
|
|
getClientHeight: function () { |
|
return this.scrollContainer.element[0].clientHeight; |
|
}, |
|
|
|
getContainerSize: function () { |
|
return this.container.element.bounds(); |
|
}, |
|
|
|
setContainerSize: function (bounds) { |
|
return this.container.element.bounds(bounds); |
|
}, |
|
|
|
_applyContainer: function () { |
|
//先掩藏后显示能够明确滚动条是否出现 |
|
this.scrollContainer.element.css("overflow", "hidden"); |
|
var occupied = this._getRegionOccupied(); |
|
this.container.element.width(occupied.left + occupied.width).height(occupied.top + occupied.height); |
|
this.scrollContainer.element.css("overflow", "auto"); |
|
return occupied; |
|
}, |
|
|
|
_modifyRegion: function (regions) { |
|
BI.each(this.regions, function (id, region) { |
|
if (regions[id]) { |
|
region.left = regions[id].left; |
|
region.top = regions[id].top; |
|
region.width = regions[id].width; |
|
region.height = regions[id].height; |
|
} |
|
}); |
|
}, |
|
|
|
_addRegion: function (item) { |
|
var region = this._createOneRegion(item); |
|
this.regions[region.id] = region; |
|
BI.createWidget({ |
|
type: "bi.absolute", |
|
element: this.container, |
|
items: [region] |
|
}); |
|
}, |
|
|
|
_deleteRegionByName: function (name) { |
|
this.regions[name].el.setVisible(false); |
|
delete this.regions[name]; |
|
}, |
|
|
|
_setArrangeSize: function (size) { |
|
this.arrangement.element.css({ |
|
left: size.left, |
|
top: size.top, |
|
width: size.width, |
|
height: size.height |
|
}) |
|
}, |
|
|
|
//Grid |
|
_getOneWidthPortion: function () { |
|
return this.getClientWidth() / BI.Arrangement.PORTION; |
|
}, |
|
_getOneHeightPortion: function () { |
|
return this.getClientHeight() / BI.Arrangement.H_PORTION; |
|
}, |
|
|
|
_getGridPositionAndSize: function (position) { |
|
var perWidth = this._getOneWidthPortion(); |
|
var perHeight = this._getOneHeightPortion(); |
|
var widthPortion = Math.round(position.width / perWidth); |
|
var leftPortion = Math.round(position.left / perWidth); |
|
var topPortion = Math.round(position.top / perHeight); |
|
var heightPortion = Math.round(position.height / perHeight); |
|
if (leftPortion > BI.Arrangement.PORTION) { |
|
leftPortion = BI.Arrangement.PORTION; |
|
} |
|
if (widthPortion > BI.Arrangement.PORTION) { |
|
widthPortion = BI.Arrangement.PORTION; |
|
} |
|
if (leftPortion + widthPortion > BI.Arrangement.PORTION) { |
|
leftPortion = BI.Arrangement.PORTION - widthPortion; |
|
} |
|
if (widthPortion === 0) { |
|
widthPortion = 1; |
|
} |
|
if (heightPortion === 0) { |
|
heightPortion = 1; |
|
} |
|
return { |
|
x: leftPortion, |
|
y: topPortion, |
|
w: widthPortion, |
|
h: heightPortion |
|
} |
|
}, |
|
|
|
_getBlockPositionAndSize: function (position) { |
|
var perWidth = this._getOneWidthPortion(); |
|
var perHeight = this._getOneHeightPortion(); |
|
return { |
|
left: position.x * perWidth, |
|
top: position.y * perHeight, |
|
width: position.w * perWidth, |
|
height: position.h * perHeight |
|
}; |
|
}, |
|
|
|
_getLayoutsByRegions: function (regions) { |
|
var self = this; |
|
var result = []; |
|
BI.each(regions || this.regions, function (id, region) { |
|
result.push(BI.extend(self._getGridPositionAndSize(region), { |
|
i: region.id |
|
})) |
|
}); |
|
return result; |
|
}, |
|
|
|
_getLayoutIndexByName: function (layout, name) { |
|
return BI.findIndex(layout, function (i, l) { |
|
return l.i === name; |
|
}); |
|
}, |
|
|
|
_setBlockPositionAndSize: function (size) { |
|
this.block.element.css({ |
|
left: size.left, |
|
top: size.top, |
|
width: size.width, |
|
height: size.height |
|
}); |
|
}, |
|
|
|
_getRegionsByLayout: function (layout) { |
|
var self = this; |
|
var regions = {}; |
|
BI.each(layout, function (i, ly) { |
|
regions[ly.i] = BI.extend(self._getBlockPositionAndSize(ly), { |
|
id: ly.i |
|
}); |
|
}); |
|
return regions; |
|
}, |
|
|
|
_setRegionsByLayout: function (regions, layout) { |
|
var self = this; |
|
regions || (regions = this.regions); |
|
BI.each(layout, function (i, ly) { |
|
if (regions[ly.i]) { |
|
BI.extend(regions[ly.i], self._getBlockPositionAndSize(ly)); |
|
} |
|
}); |
|
return regions; |
|
}, |
|
|
|
_moveElement: function (layout, l, x, y, isUserAction) { |
|
var self = this; |
|
if (l._static) { |
|
return layout; |
|
} |
|
|
|
if (l.y === y && l.x === x) { |
|
return layout; |
|
} |
|
|
|
var movingUp = y && l.y > y; |
|
if (typeof x === 'number') { |
|
l.x = x; |
|
} |
|
if (typeof y === 'number') { |
|
l.y = y; |
|
} |
|
l.moved = true; |
|
|
|
var sorted = this._sortLayoutItemsByRowCol(layout); |
|
if (movingUp) { |
|
sorted = sorted.reverse(); |
|
} |
|
var collisions = getAllCollisions(sorted, l); |
|
|
|
for (var i = 0, len = collisions.length; i < len; i++) { |
|
var collision = collisions[i]; |
|
if (collision.moved) { |
|
continue; |
|
} |
|
|
|
if (l.y > collision.y && l.y - collision.y > collision.h / 4) { |
|
continue; |
|
} |
|
|
|
if (collision._static) { |
|
layout = this._moveElementAwayFromCollision(layout, collision, l, isUserAction); |
|
} else { |
|
layout = this._moveElementAwayFromCollision(layout, l, collision, isUserAction); |
|
} |
|
} |
|
|
|
return layout; |
|
|
|
function getAllCollisions(layout, layoutItem) { |
|
return BI.filter(layout, function (i, l) { |
|
return self._collides(l, layoutItem); |
|
}); |
|
} |
|
}, |
|
|
|
_sortLayoutItemsByRowCol: function (layout) { |
|
return [].concat(layout).sort(function (a, b) { |
|
if (a.y > b.y || (a.y === b.y && a.x > b.x)) { |
|
return 1; |
|
} |
|
return -1; |
|
}); |
|
}, |
|
|
|
_collides: function (l1, l2) { |
|
if (l1 === l2) { |
|
return false; |
|
} // same element |
|
if (l1.x + l1.w <= l2.x) { |
|
return false; |
|
} // l1 is left of l2 |
|
if (l1.x >= l2.x + l2.w) { |
|
return false; |
|
} // l1 is right of l2 |
|
if (l1.y + l1.h <= l2.y) { |
|
return false; |
|
} // l1 is above l2 |
|
if (l1.y >= l2.y + l2.h) { |
|
return false; |
|
} // l1 is below l2 |
|
return true; // boxes overlap |
|
}, |
|
|
|
_getFirstCollision: function (layout, layoutItem) { |
|
for (var i = 0, len = layout.length; i < len; i++) { |
|
if (this._collides(layout[i], layoutItem)) { |
|
return layout[i]; |
|
} |
|
} |
|
}, |
|
|
|
_moveElementAwayFromCollision: function (layout, collidesWith, |
|
itemToMove, isUserAction) { |
|
if (isUserAction) { |
|
var fakeItem = { |
|
x: itemToMove.x, |
|
y: itemToMove.y, |
|
w: itemToMove.w, |
|
h: itemToMove.h, |
|
i: '-1' |
|
}; |
|
fakeItem.y = Math.max(collidesWith.y - itemToMove.h, 0); |
|
if (!this._getFirstCollision(layout, fakeItem)) { |
|
return this._moveElement(layout, itemToMove, undefined, fakeItem.y); |
|
} |
|
} |
|
|
|
return this._moveElement(layout, itemToMove, undefined, itemToMove.y + 1); |
|
}, |
|
|
|
_compactItem: function (compareWith, l, verticalCompact) { |
|
if (verticalCompact) { |
|
while (l.y > 0 && !this._getFirstCollision(compareWith, l)) { |
|
l.y--; |
|
} |
|
} |
|
|
|
var collides; |
|
while ((collides = this._getFirstCollision(compareWith, l))) { |
|
l.y = collides.y + collides.h; |
|
} |
|
return l; |
|
}, |
|
|
|
compact: function (layout, verticalCompact) { |
|
var compareWith = getStatics(layout); |
|
var sorted = this._sortLayoutItemsByRowCol(layout); |
|
var out = []; |
|
|
|
for (var i = 0, len = sorted.length; i < len; i++) { |
|
var l = sorted[i]; |
|
|
|
if (!l._static) { |
|
l = this._compactItem(compareWith, l, verticalCompact); |
|
|
|
compareWith.push(l); |
|
} |
|
|
|
out[layout.indexOf(l)] = l; |
|
|
|
l.moved = false; |
|
} |
|
|
|
return out; |
|
function getStatics(layout) { |
|
return BI.filter(layout, function (i, l) { |
|
return l._static; |
|
}); |
|
} |
|
}, |
|
|
|
////公有方法//// |
|
getRegionByName: function (name) { |
|
var obj = {}; |
|
obj[name] = this.regions[name]; |
|
return this._cloneRegion(obj)[name]; |
|
}, |
|
|
|
getAllRegions: function () { |
|
return BI.toArray(this._cloneRegion()); |
|
}, |
|
|
|
getHelper: function () { |
|
var helper = BI.createWidget({ |
|
type: "bi.layout", |
|
width: 18, |
|
height: 18, |
|
cls: "arrangement-helper bi-border" |
|
}); |
|
BI.createWidget({ |
|
type: "bi.absolute", |
|
element: this, |
|
items: [helper] |
|
}); |
|
return helper; |
|
}, |
|
|
|
_start: function () { |
|
this.arrangement.setVisible(true); |
|
if (this.options.layoutType === BI.Arrangement.LAYOUT_TYPE.GRID) { |
|
this.block.setVisible(true); |
|
} |
|
}, |
|
|
|
_stop: function () { |
|
this.arrangement.setVisible(false); |
|
this.block.setVisible(false); |
|
}, |
|
|
|
////公有操作//// |
|
setLayoutType: function (type) { |
|
var self = this, o = this.options; |
|
if (type !== o.layoutType) { |
|
o.layoutType = type; |
|
switch (o.layoutType) { |
|
case BI.Arrangement.LAYOUT_TYPE.FREE: |
|
break; |
|
case BI.Arrangement.LAYOUT_TYPE.GRID: |
|
this.relayout(); |
|
break; |
|
} |
|
} |
|
}, |
|
|
|
getLayoutType: function () { |
|
return this.options.layoutType; |
|
}, |
|
|
|
getLayoutRatio: function () { |
|
var occupied = this._getRegionOccupied(); |
|
var width = this.getClientWidth(), height = this.getClientHeight(); |
|
return { |
|
x: BI.parseFloat(BI.contentFormat((occupied.left + occupied.width) / width, "#.##;-#.##")), |
|
y: BI.parseFloat(BI.contentFormat((occupied.top + occupied.height) / height, "#.##;-#.##")) |
|
} |
|
}, |
|
|
|
addRegion: function (region, position) { |
|
if (position) { |
|
this.setPosition(position, region); |
|
} |
|
var self = this, o = this.options; |
|
if (!this.position) { |
|
return false; |
|
} |
|
var test = this._cloneRegion(); |
|
BI.each(this.position.regions, function (i, region) { |
|
test[region.id].left = region.left; |
|
test[region.id].top = region.top; |
|
test[region.id].width = region.width; |
|
test[region.id].height = region.height; |
|
|
|
}); |
|
var item = BI.extend({}, region, { |
|
left: this.position.insert.left, |
|
top: this.position.insert.top, |
|
width: this.position.insert.width, |
|
height: this.position.insert.height |
|
}); |
|
var added = this._createOneRegion(item); |
|
test[added.id] = added; |
|
if (this._test(test)) { |
|
delete test[added.id]; |
|
this._modifyRegion(test); |
|
this._addRegion(item); |
|
this._populate(this.getAllRegions()); |
|
return true; |
|
} |
|
return false; |
|
}, |
|
|
|
deleteRegion: function (name) { |
|
if (!this.regions[name]) { |
|
return false; |
|
} |
|
var self = this, o = this.options; |
|
switch (o.layoutType) { |
|
case BI.Arrangement.LAYOUT_TYPE.FREE: |
|
this._deleteRegionByName(name); |
|
this._populate(this.getAllRegions()); |
|
return true; |
|
case BI.Arrangement.LAYOUT_TYPE.GRID: |
|
this._deleteRegionByName(name); |
|
this._populate(this.getAllRegions()); |
|
this.resize(); |
|
return true; |
|
} |
|
return false; |
|
}, |
|
|
|
setRegionSize: function (name, size) { |
|
var self = this, o = this.options; |
|
var flag = false; |
|
switch (o.layoutType) { |
|
case BI.Arrangement.LAYOUT_TYPE.FREE: |
|
var clone = this._cloneRegion(); |
|
BI.extend(clone[name], { |
|
width: size.width, |
|
height: size.height |
|
}); |
|
if (this._test(clone)) { |
|
this._modifyRegion(clone); |
|
flag = true; |
|
} |
|
break; |
|
case BI.Arrangement.LAYOUT_TYPE.GRID: |
|
var clone = this._cloneRegion(); |
|
BI.extend(clone[name], { |
|
width: size.width, |
|
height: size.height |
|
}); |
|
if (this._test(clone)) { |
|
var layout = this._getLayoutsByRegions(clone); |
|
layout = this.compact(layout, true); |
|
var regions = this._getRegionsByLayout(layout); |
|
this._modifyRegion(regions); |
|
flag = true; |
|
} |
|
break; |
|
} |
|
this._applyRegion(); |
|
return flag; |
|
}, |
|
|
|
setPosition: function (position, size) { |
|
var self = this, o = this.options; |
|
var insert, regions = [], cur; |
|
if (position.left < 0 || position.top < 0) { |
|
switch (o.layoutType) { |
|
case BI.Arrangement.LAYOUT_TYPE.FREE: |
|
break; |
|
case BI.Arrangement.LAYOUT_TYPE.GRID: |
|
this.resize(); |
|
break; |
|
} |
|
this._stop(); |
|
this.position = null; |
|
return null; |
|
} |
|
var offset = this._getScrollOffset(); |
|
position = { |
|
left: position.left + offset.left, |
|
top: position.top + offset.top |
|
}; |
|
switch (o.layoutType) { |
|
case BI.Arrangement.LAYOUT_TYPE.FREE: |
|
var insert = { |
|
top: position.top < 0 ? 0 : position.top, |
|
left: position.left < 0 ? 0 : position.left, |
|
width: size.width, |
|
height: size.height |
|
}; |
|
this.position = { |
|
insert: insert |
|
}; |
|
this._setArrangeSize(insert); |
|
this._start(); |
|
break; |
|
case BI.Arrangement.LAYOUT_TYPE.GRID: |
|
var p = { |
|
top: position.top < 0 ? 0 : position.top, |
|
left: position.left < 0 ? 0 : position.left, |
|
width: size.width, |
|
height: size.height |
|
}; |
|
this._setArrangeSize(p); |
|
var cur = this._getGridPositionAndSize(p); |
|
var layout = [{ |
|
x: 0, y: BI.MAX, w: cur.w, h: cur.h, i: cur.i |
|
}].concat(this._getLayoutsByRegions()); |
|
layout = this._moveElement(layout, layout[0], cur.x, cur.y, true); |
|
layout = this.compact(layout, true); |
|
var regions = this._setRegionsByLayout(this._cloneRegion(), layout); |
|
var insert = this._getBlockPositionAndSize(layout[0]); |
|
this.position = { |
|
insert: insert, |
|
regions: regions |
|
}; |
|
this._applyRegion(regions); |
|
this._setBlockPositionAndSize(insert); |
|
this._start(); |
|
break; |
|
} |
|
return this.position; |
|
}, |
|
|
|
setRegionPosition: function (name, position) { |
|
var self = this, o = this.options; |
|
var offset = this._getScrollOffset(); |
|
position = BI.extend(position, { |
|
left: position.left + offset.left, |
|
top: position.top + offset.top |
|
}); |
|
switch (o.layoutType) { |
|
case BI.Arrangement.LAYOUT_TYPE.FREE: |
|
BI.extend(this.regions[name], { |
|
left: position.left < 0 ? 0 : position.left, |
|
top: position.top < 0 ? 0 : position.top |
|
}); |
|
this._applyRegion(); |
|
break; |
|
case BI.Arrangement.LAYOUT_TYPE.GRID: |
|
if (!position.stop) { |
|
BI.extend(this.regions[name], { |
|
left: position.left < 0 ? 0 : position.left, |
|
top: position.top < 0 ? 0 : position.top |
|
}); |
|
var cloned = this._cloneRegion(); |
|
var cur = this._getGridPositionAndSize(BI.extend(cloned[name], { |
|
left: position.left < 0 ? 0 : position.left, |
|
top: position.top < 0 ? 0 : position.top |
|
})); |
|
var x = cur.x, y = cur.y; |
|
cur = BI.extend(cur, { |
|
x: 0, y: BI.MAX, i: -1 |
|
}); |
|
delete cloned[name]; |
|
var layout = this._getLayoutsByRegions(cloned); |
|
layout = this._moveElement([cur].concat(layout), cur, x, y, true); |
|
layout = this.compact(layout, true); |
|
var regions = this._getRegionsByLayout(layout); |
|
this._modifyRegion(regions); |
|
this._applyRegion(); |
|
|
|
this._setBlockPositionAndSize(this._getBlockPositionAndSize(cur)); |
|
this.block.setVisible(true); |
|
} else { |
|
BI.extend(this.regions[name], { |
|
left: position.left < 0 ? 0 : position.left, |
|
top: position.top < 0 ? 0 : position.top |
|
}); |
|
var cloned = this._cloneRegion(); |
|
var layout = this._getLayoutsByRegions(cloned); |
|
layout = this.compact(layout, true); |
|
var regions = this._getRegionsByLayout(layout); |
|
this._modifyRegion(regions); |
|
this._applyRegion(); |
|
this.block.setVisible(false); |
|
} |
|
break; |
|
} |
|
}, |
|
|
|
setDropPosition: function (position, size) { |
|
var self = this; |
|
this.arrangement.setVisible(true); |
|
this._setArrangeSize(BI.extend({}, position, size)); |
|
return function () { |
|
self.arrangement.setVisible(false); |
|
} |
|
}, |
|
|
|
scrollTo: function (scroll) { |
|
this.scrollContainer.element.scrollTop(scroll.top); |
|
this.scrollContainer.element.scrollLeft(scroll.left); |
|
}, |
|
|
|
zoom: function (ratio) { |
|
var self = this, o = this.options; |
|
if (!ratio) { |
|
return; |
|
} |
|
var occupied = this._applyContainer(); |
|
switch (this.getLayoutType()) { |
|
case BI.Arrangement.LAYOUT_TYPE.FREE: |
|
if (this._isArrangeFine()) { |
|
var width = this.getClientWidth(); |
|
var xRatio = (ratio.x || 1) * width / (occupied.left + occupied.width); |
|
//var yRatio = ratio.y * height / (occupied.top + occupied.height); |
|
var regions = this._cloneRegion(); |
|
BI.each(regions, function (i, region) { |
|
region.left = region.left * xRatio; |
|
//region.top = region.top * yRatio; |
|
region.width = region.width * xRatio; |
|
//region.height = region.height * yRatio; |
|
}); |
|
if (this._test(regions)) { |
|
this._modifyRegion(regions); |
|
this._applyRegion(); |
|
} |
|
this.resize(); |
|
// } else { |
|
this.relayout(); |
|
} |
|
break; |
|
case BI.Arrangement.LAYOUT_TYPE.GRID: |
|
if (this._isArrangeFine()) { |
|
var width = this.getClientWidth(), height = this.getClientHeight(); |
|
var xRatio = (ratio.x || 1) * width / (occupied.left + occupied.width); |
|
var yRatio = (ratio.y || 1) * height / (occupied.top + occupied.height); |
|
var regions = this._cloneRegion(); |
|
BI.each(regions, function (i, region) { |
|
region.left = region.left * xRatio; |
|
region.width = region.width * xRatio; |
|
region.top = region.top * yRatio; |
|
region.height = region.height * yRatio; |
|
}); |
|
if (this._test(regions)) { |
|
var layout = this._getLayoutsByRegions(regions); |
|
layout = this.compact(layout, true); |
|
regions = this._getRegionsByLayout(layout); |
|
this._modifyRegion(regions); |
|
this._applyRegion(); |
|
} |
|
} else { |
|
this.relayout(); |
|
} |
|
break; |
|
} |
|
}, |
|
|
|
resize: function () { |
|
var self = this, o = this.options; |
|
var occupied = this._applyContainer(); |
|
switch (o.layoutType) { |
|
case BI.Arrangement.LAYOUT_TYPE.FREE: |
|
break; |
|
case BI.Arrangement.LAYOUT_TYPE.GRID: |
|
this.zoom(this.ratio); |
|
var regions = this._cloneRegion(); |
|
var layout = this._getLayoutsByRegions(regions); |
|
layout = this.compact(layout, true); |
|
regions = this._getRegionsByLayout(layout); |
|
this._modifyRegion(regions); |
|
this._applyRegion(); |
|
break; |
|
} |
|
}, |
|
|
|
relayout: function () { |
|
var self = this, o = this.options; |
|
switch (o.layoutType) { |
|
case BI.Arrangement.LAYOUT_TYPE.FREE: |
|
break; |
|
case BI.Arrangement.LAYOUT_TYPE.GRID: |
|
if (!this._isArrangeFine()) { |
|
var perHeight = this._getOneHeightPortion(); |
|
var width = this.getClientWidth(), height = this.getClientHeight(); |
|
var regions = this._cloneRegion(); |
|
var clone = BI.toArray(regions); |
|
clone.sort(function (r1, r2) { |
|
if (self._isEqual(r1.top, r2.top)) { |
|
return r1.left - r2.left; |
|
} |
|
return r1.top - r2.top; |
|
}); |
|
var count = clone.length; |
|
var cols = 4, rows = Math.floor((count - 1) / 4 + 1); |
|
var w = width / cols, h = height / rows; |
|
var store = {}; |
|
BI.each(clone, function (i, region) { |
|
var row = Math.floor(i / 4), col = i % 4; |
|
BI.extend(region, { |
|
top: row * perHeight * 6, |
|
left: col * w, |
|
width: w, |
|
height: perHeight * 6 |
|
}); |
|
if (!store[row]) { |
|
store[row] = {}; |
|
} |
|
store[row][col] = region; |
|
}); |
|
//非4的倍数 |
|
// if (count % 4 !== 0) { |
|
// var lasts = store[rows - 1]; |
|
// var perWidth = width / (count % 4); |
|
// BI.each(lasts, function (i, region) { |
|
// BI.extend(region, { |
|
// left: BI.parseInt(i) * perWidth, |
|
// width: perWidth |
|
// }); |
|
// }); |
|
// } |
|
if (this._test(clone)) { |
|
var layout = this._getLayoutsByRegions(regions); |
|
layout = this.compact(layout, true); |
|
regions = this._getRegionsByLayout(layout); |
|
this._modifyRegion(regions); |
|
this._populate(clone); |
|
} |
|
} else { |
|
this.resize(); |
|
} |
|
break; |
|
} |
|
}, |
|
|
|
_populate: function (items) { |
|
this._stop(); |
|
this._calculateRegions(items); |
|
this._applyRegion(); |
|
}, |
|
|
|
populate: function (items) { |
|
var self = this; |
|
BI.each(this.regions, function (name, region) { |
|
self.regions[name].el.setVisible(false); |
|
delete self.regions[name]; |
|
}); |
|
this._populate(items); |
|
this._renderRegion(); |
|
} |
|
}); |
|
BI.Arrangement.EVENT_SCROLL = "EVENT_SCROLL"; |
|
BI.extend(BI.Arrangement, { |
|
PORTION: 32, |
|
H_PORTION: 18, |
|
LAYOUT_TYPE: { |
|
GRID: 0, |
|
FREE: 1 |
|
} |
|
}); |
|
BI.shortcut('bi.arrangement', BI.Arrangement); |