@visactor/vchart
Version:
charts lib based @visactor/VGrammar
331 lines (326 loc) • 16.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: !0
}), exports.Layout = void 0;
const vutils_1 = require("@visactor/vutils"), debug_1 = require("../util/debug"), util_1 = require("./util");
class Layout {
constructor(_spec, ctx) {
this.leftCurrent = 0, this.topCurrent = 0, this.rightCurrent = 0, this.bottomCurrent = 0,
this.recomputeWidth = !1, this.recomputeHeight = !1, this._onError = null == ctx ? void 0 : ctx.onError;
}
_layoutInit(_chart, items, chartLayoutRect, chartViewBox) {
this._chartLayoutRect = chartLayoutRect, this._chartViewBox = chartViewBox, this.leftCurrent = chartLayoutRect.x,
this.topCurrent = chartLayoutRect.y, this.rightCurrent = chartLayoutRect.x + chartLayoutRect.width,
this.bottomCurrent = chartLayoutRect.height + chartLayoutRect.y, this.recomputeWidth = !1,
this.recomputeHeight = !1, items.sort(((a, b) => b.layoutLevel - a.layoutLevel));
}
_layoutNormalItems(items, recompute) {
this.layoutNormalInlineItems(items.filter((x => "normal-inline" === x.layoutType)), recompute),
this.layoutNormalItems(items.filter((x => "normal" === x.layoutType)), recompute);
}
_groupItems(items) {
const regionItems = items.filter((x => "region" === x.layoutType)), relativeItems = items.filter((x => "region-relative" === x.layoutType)), relativeOverlapItems = items.filter((x => "region-relative-overlap" === x.layoutType)), allRelatives = relativeItems.concat(relativeOverlapItems), overlapItems = {
left: {
items: [],
rect: {
width: 0,
height: 0
}
},
right: {
items: [],
rect: {
width: 0,
height: 0
}
},
top: {
items: [],
rect: {
width: 0,
height: 0
}
},
bottom: {
items: [],
rect: {
width: 0,
height: 0
}
},
z: {
items: [],
rect: {
width: 0,
height: 0
}
}
};
return relativeOverlapItems.forEach((i => {
overlapItems[i.layoutOrient].items.push(i);
})), {
regionItems: regionItems,
relativeItems: relativeItems,
relativeOverlapItems: relativeOverlapItems,
allRelatives: allRelatives,
overlapItems: overlapItems
};
}
layoutItems(_chart, items, chartLayoutRect, chartViewBox) {
this._layoutInit(_chart, items, chartLayoutRect, chartViewBox);
const recompute = {
recomputeWidth: this.recomputeWidth,
recomputeHeight: this.recomputeHeight
};
this._layoutNormalItems(items, recompute);
const layoutTemp = {
left: this.leftCurrent,
top: this.topCurrent,
right: this.rightCurrent,
bottom: this.bottomCurrent
}, {regionItems: regionItems, relativeItems: relativeItems, relativeOverlapItems: relativeOverlapItems, allRelatives: allRelatives, overlapItems: overlapItems} = this._groupItems(items);
this.layoutRegionItems(regionItems, relativeItems, relativeOverlapItems, overlapItems, recompute),
this._processAutoIndent(regionItems, relativeItems, relativeOverlapItems, overlapItems, allRelatives, layoutTemp, recompute),
this.layoutAbsoluteItems(items.filter((x => "absolute" === x.layoutType))), items.forEach((item => {
item.clearWillLayoutTag();
}));
}
_processAutoIndent(regionItems, relativeItems, relativeOverlapItems, overlapItems = {
left: {
items: [],
rect: {
width: 0,
height: 0
}
},
right: {
items: [],
rect: {
width: 0,
height: 0
}
},
top: {
items: [],
rect: {
width: 0,
height: 0
}
},
bottom: {
items: [],
rect: {
width: 0,
height: 0
}
},
z: {
items: [],
rect: {
width: 0,
height: 0
}
}
}, allRelatives, layoutTemp, recompute) {
if (allRelatives.some((i => i.autoIndent))) {
const {top: top, bottom: bottom, left: left, right: right} = this._checkAutoIndent(allRelatives, layoutTemp);
(top || bottom || left || right) && (this.topCurrent = layoutTemp.top + top, this.bottomCurrent = layoutTemp.bottom - bottom,
this.leftCurrent = layoutTemp.left + left, this.rightCurrent = layoutTemp.right - right,
this.layoutRegionItems(regionItems, relativeItems, relativeOverlapItems, overlapItems, recompute));
}
}
layoutNormalItems(normalItems, recompute) {
normalItems.forEach((item => {
const {rect: rect} = (0, util_1.getItemLayoutWithTag)(item, this, recompute);
"left" === item.layoutOrient ? (item.setLayoutStartPosition({
x: this.leftCurrent + item.layoutOffsetX + item.layoutPaddingLeft,
y: this.topCurrent + item.layoutOffsetY + item.layoutPaddingTop
}), this.leftCurrent += rect.width + item.layoutPaddingLeft + item.layoutPaddingRight) : "top" === item.layoutOrient ? (item.setLayoutStartPosition({
x: this.leftCurrent + item.layoutOffsetX + item.layoutPaddingLeft,
y: this.topCurrent + item.layoutOffsetY + item.layoutPaddingTop
}), this.topCurrent += rect.height + item.layoutPaddingTop + item.layoutPaddingBottom) : "right" === item.layoutOrient ? (item.setLayoutStartPosition({
x: this.rightCurrent + item.layoutOffsetX - rect.width - item.layoutPaddingRight,
y: this.topCurrent + item.layoutOffsetY + item.layoutPaddingTop
}), this.rightCurrent -= rect.width + item.layoutPaddingLeft + item.layoutPaddingRight) : "bottom" === item.layoutOrient && (item.setLayoutStartPosition({
x: this.leftCurrent + item.layoutOffsetX + item.layoutPaddingRight,
y: this.bottomCurrent + item.layoutOffsetY - rect.height - item.layoutPaddingBottom
}), this.bottomCurrent -= rect.height + item.layoutPaddingTop + item.layoutPaddingBottom);
}));
}
layoutNormalInlineItems(normalItems, recompute) {
const leftItems = normalItems.filter((item => "left" === item.layoutOrient)), rightItems = normalItems.filter((item => "right" === item.layoutOrient)), topItems = normalItems.filter((item => "top" === item.layoutOrient)), bottomItems = normalItems.filter((item => "bottom" === item.layoutOrient)), limitWidth = this._chartLayoutRect.width + this._chartLayoutRect.x, limitHeight = this._chartLayoutRect.height + this._chartLayoutRect.y;
return leftItems.length && (0, util_1.layoutLeftInlineItems)(leftItems, this, limitHeight, recompute),
topItems.length && (0, util_1.layoutTopInlineItems)(topItems, this, limitWidth, recompute),
rightItems.length && (0, util_1.layoutRightInlineItems)(rightItems, this, limitHeight, recompute),
bottomItems.length && (0, util_1.layoutBottomInlineItems)(bottomItems, this, limitWidth, recompute),
!0;
}
_layoutRelativeOverlap(orient, info, recompute) {
info.items.forEach((item => {
const {rect: rect} = (0, util_1.getItemLayoutWithTag)(item, this, recompute);
info.rect.width = Math.max(rect.width + item.layoutPaddingLeft + item.layoutPaddingRight, info.rect.width),
info.rect.height = Math.max(rect.height + item.layoutPaddingTop + item.layoutPaddingBottom, info.rect.height);
})), info.items.forEach((item => {
(0, vutils_1.isEqual)(item.getLayoutRect(), info.rect) || item.setLayoutRect(info.rect),
"left" === orient ? item.setLayoutStartPosition({
x: this.leftCurrent + item.layoutOffsetX
}) : "right" === orient ? item.setLayoutStartPosition({
x: this.rightCurrent - info.rect.width + item.layoutOffsetX
}) : "top" === orient ? item.setLayoutStartPosition({
x: this.topCurrent + item.layoutOffsetY
}) : item.setLayoutStartPosition({
x: this.bottomCurrent - info.rect.height + item.layoutOffsetY
});
})), "left" === orient ? this.leftCurrent += info.rect.width : "right" === orient ? this.rightCurrent -= info.rect.width : "top" === orient ? this.topCurrent += info.rect.height : this.bottomCurrent -= info.rect.height;
}
_layoutRelativeItem(item, recompute) {
const {rect: rect} = (0, util_1.getItemLayoutWithTag)(item, this, recompute, !1);
"left" === item.layoutOrient || "right" === item.layoutOrient ? item.setLayoutRect({
width: rect.width
}) : item.setLayoutRect({
height: rect.height
}), "left" === item.layoutOrient ? (item.setLayoutStartPosition({
x: this.leftCurrent + item.layoutOffsetX + item.layoutPaddingLeft
}), this.leftCurrent += rect.width + item.layoutPaddingLeft + item.layoutPaddingRight) : "right" === item.layoutOrient ? (this.rightCurrent -= rect.width + item.layoutPaddingLeft + item.layoutPaddingRight,
item.setLayoutStartPosition({
x: this.rightCurrent + item.layoutOffsetX + item.layoutPaddingLeft
})) : "top" === item.layoutOrient ? (item.setLayoutStartPosition({
y: this.topCurrent + item.layoutOffsetY + item.layoutPaddingTop
}), this.topCurrent += rect.height + item.layoutPaddingTop + item.layoutPaddingBottom) : "bottom" === item.layoutOrient && (this.bottomCurrent -= rect.height + item.layoutPaddingTop + item.layoutPaddingBottom,
item.setLayoutStartPosition({
y: this.bottomCurrent + item.layoutOffsetY + item.layoutPaddingTop
}));
}
_layoutRegionItem(regionItems, regionRelativeTotalWidth, regionRelativeTotalHeight) {
const regionWidth = Math.max(Math.min(regionRelativeTotalWidth, ...regionItems.map((region => {
var _a;
return null !== (_a = region.maxWidth) && void 0 !== _a ? _a : Number.MAX_VALUE;
}))), 0), regionHeight = Math.max(Math.min(regionRelativeTotalHeight, ...regionItems.map((region => {
var _a;
return null !== (_a = region.maxHeight) && void 0 !== _a ? _a : Number.MAX_VALUE;
}))), 0);
return regionItems.forEach((region => {
const width = regionWidth - region.layoutPaddingLeft - region.layoutPaddingRight, height = regionHeight - region.layoutPaddingTop - region.layoutPaddingBottom;
region.setLayoutRect({
width: width,
height: height
}), region.setLayoutStartPosition({
x: this.leftCurrent + region.layoutOffsetX + region.layoutPaddingLeft,
y: this.topCurrent + region.layoutOffsetY + region.layoutPaddingTop
});
})), {
regionHeight: regionHeight,
regionWidth: regionWidth
};
}
layoutRegionItems(regionItems, regionRelativeItems, regionRelativeOverlapItems, overlapItems = {
left: {
items: [],
rect: {
width: 0,
height: 0
}
},
right: {
items: [],
rect: {
width: 0,
height: 0
}
},
top: {
items: [],
rect: {
width: 0,
height: 0
}
},
bottom: {
items: [],
rect: {
width: 0,
height: 0
}
},
z: {
items: [],
rect: {
width: 0,
height: 0
}
}
}, recompute) {
let regionRelativeTotalWidth = this.rightCurrent - this.leftCurrent, regionRelativeTotalHeight = this.bottomCurrent - this.topCurrent;
regionRelativeItems.filter((x => "left" === x.layoutOrient || "right" === x.layoutOrient)).forEach((item => {
this._layoutRelativeItem(item, recompute);
})), this._layoutRelativeOverlap("left", overlapItems.left, recompute), this._layoutRelativeOverlap("right", overlapItems.right, recompute),
regionRelativeTotalWidth = this.rightCurrent - this.leftCurrent, regionRelativeItems.filter((x => "top" === x.layoutOrient || "bottom" === x.layoutOrient)).forEach((item => {
this._layoutRelativeItem(item, recompute);
})), this._layoutRelativeOverlap("top", overlapItems.top, recompute), this._layoutRelativeOverlap("bottom", overlapItems.bottom, recompute),
regionRelativeTotalHeight = this.bottomCurrent - this.topCurrent;
const {regionWidth: regionWidth, regionHeight: regionHeight} = this._layoutRegionItem(regionItems, regionRelativeTotalWidth, regionRelativeTotalHeight);
regionRelativeItems.concat(regionRelativeOverlapItems).forEach((item => {
if ([ "left", "right" ].includes(item.layoutOrient)) {
const relativeRegion = this.filterRegionsWithID(regionItems, item.layoutBindRegionID[0]);
item.setLayoutRect({
height: relativeRegion.getLayoutRect().height
}), item.setLayoutStartPosition({
y: relativeRegion.getLayoutStartPoint().y + item.layoutOffsetY + item.layoutPaddingTop
}), "right" === item.layoutOrient && item.setLayoutStartPosition({
x: item.getLayoutStartPoint().x + regionWidth - regionRelativeTotalWidth
});
} else if ([ "top", "bottom" ].includes(item.layoutOrient)) {
const relativeRegion = this.filterRegionsWithID(regionItems, item.layoutBindRegionID[0]);
item.setLayoutRect({
width: relativeRegion.getLayoutRect().width
}), item.setLayoutStartPosition({
x: relativeRegion.getLayoutStartPoint().x + item.layoutOffsetX + item.layoutPaddingLeft
}), "bottom" === item.layoutOrient && item.setLayoutStartPosition({
y: item.getLayoutStartPoint().y + regionHeight - regionRelativeTotalHeight
});
}
}));
}
layoutAbsoluteItems(absoluteItems) {
absoluteItems.forEach((item => {
item.willLayoutTag && item.absoluteLayoutInRect(this._chartLayoutRect);
}));
}
filterRegionsWithID(items, id) {
var _a;
const target = items.find((x => x.getModelId() === id));
return target || (null !== (_a = this._onError) && void 0 !== _a ? _a : debug_1.error)("can not find target region item, invalid id"),
target;
}
getItemComputeLayoutRect(item) {
return {
width: this.rightCurrent - this.leftCurrent - item.layoutPaddingLeft - item.layoutPaddingRight,
height: this.bottomCurrent - this.topCurrent - item.layoutPaddingTop - item.layoutPaddingBottom
};
}
_checkAutoIndent(items, layoutTemp) {
const result = {
top: 0,
left: 0,
bottom: 0,
right: 0
};
return items.forEach((i => {
if (!i.getModelVisible() || !i.autoIndent) return;
const vOrH = "left" === i.layoutOrient || "right" === i.layoutOrient, itemOuter = i.getLastComputeOutBounds(), outer = this._getOutInLayout(itemOuter, i, layoutTemp);
vOrH ? (result.top = Math.max(result.top, outer.top), result.bottom = Math.max(result.bottom, outer.bottom)) : (result.left = Math.max(result.left, outer.left),
result.right = Math.max(result.right, outer.right));
})), result;
}
_getOutInLayout(itemOuter, i, tempBorder) {
const {x: x, y: y} = i.getLayoutStartPoint(), {width: width, height: height} = i.getLayoutRect();
return {
left: tempBorder.left - (x - itemOuter.x1),
right: x + width + itemOuter.x2 - tempBorder.right,
top: tempBorder.top - (y - itemOuter.y1),
bottom: y + height + itemOuter.y2 - tempBorder.bottom
};
}
}
exports.Layout = Layout, Layout.type = "base";
//# sourceMappingURL=base-layout.js.map