修改为绝对坐标面板

This commit is contained in:
zqm
2025-10-20 17:03:52 +08:00
parent 7a94d01871
commit 4863237a4d
2 changed files with 506 additions and 567 deletions

View File

@@ -176,13 +176,18 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
function addPanel(panel, minSizes = { panelWidth: 150, panelHeight: 100 }) {
const panelData = {
...panel,
id: panel.id || generateUniqueId(),
collapsed: panel.collapsed || false,
lastPosition: panel.position,
lastSize: panel.lastSize || {
width: panel.width || 300,
height: panel.height || 200
},
width: panel.width || 300
width: panel.width || 300,
height: panel.height || 200,
// 初始化绝对定位坐标
x: 0,
y: 0
}
// 获取全局容器元素只查询一次DOM
@@ -193,7 +198,7 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
const isLeftFirst = leftPanels.value.length === 0
leftPanelArea.value.panels.push(panelData)
resetPanelsSizeRatios('left')
// 使用全局容器元素更新面板尺寸
// 使用全局容器元素更新面板尺寸和绝对位置
if (container) {
updatePanelsSize('left', leftPanelArea.value, container, minSizes);
}
@@ -206,7 +211,7 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
const isRightFirst = rightPanels.value.length === 0
rightPanelArea.value.panels.push(panelData)
resetPanelsSizeRatios('right')
// 使用全局容器元素更新面板尺寸
// 使用全局容器元素更新面板尺寸和绝对位置
if (container) {
updatePanelsSize('right', rightPanelArea.value, container, minSizes);
}
@@ -219,7 +224,7 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
const isTopFirst = topPanels.value.length === 0
topPanelArea.value.panels.push(panelData)
resetPanelsSizeRatios('top')
// 使用全局容器元素更新面板尺寸
// 使用全局容器元素更新面板尺寸和绝对位置
if (container) {
updatePanelsSize('top', topPanelArea.value, container, minSizes);
}
@@ -232,7 +237,7 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
const isBottomFirst = bottomPanels.value.length === 0
bottomPanelArea.value.panels.push(panelData)
resetPanelsSizeRatios('bottom')
// 使用全局容器元素更新面板尺寸
// 使用全局容器元素更新面板尺寸和绝对位置
if (container) {
updatePanelsSize('bottom', bottomPanelArea.value, container, minSizes);
}
@@ -245,7 +250,7 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
default:
centerPanelArea.value.panels.push(panelData)
resetPanelsSizeRatios('center')
// 使用全局容器元素更新中心面板尺寸
// 使用全局容器元素更新中心面板尺寸和绝对位置
if (container) {
updatePanelsSize('center', centerPanelArea.value, container, minSizes);
}
@@ -259,6 +264,12 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
function resetPanelsSizeRatios(position) {
let panelArea
// 支持两种调用方式传入position字符串或直接传入面板数量
if (typeof position === 'number') {
// 当直接传入面板数量时,返回均匀分配的比例数组
return Array(position).fill(1 / position)
}
switch (position) {
case 'top':
panelArea = topPanelArea.value
@@ -616,9 +627,11 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
// 重置所有面板状态
function resetLayout() {
// 重置面板区对象确保每个面板区域都包含widthheight属性
// 重置面板区对象确保每个面板区域都包含widthheight和位置信息
leftPanelArea.value = {
panels: [],
x: 0, // 绝对定位的x坐标
y: 0, // 绝对定位的y坐标
width: 300,
height: 0, // 初始高度为0将在updatePanelsSize中被正确设置
heightRatios: []
@@ -626,6 +639,8 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
rightPanelArea.value = {
panels: [],
x: 0, // 初始x坐标将在updatePanelsSize中被正确设置
y: 0, // 绝对定位的y坐标
width: 250,
height: 0, // 初始高度为0将在updatePanelsSize中被正确设置
heightRatios: []
@@ -633,6 +648,8 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
topPanelArea.value = {
panels: [],
x: 0, // 绝对定位的x坐标
y: 0, // 绝对定位的y坐标
height: 150,
width: 0, // 初始宽度为0将在updatePanelsSize中被正确设置
widthRatios: []
@@ -640,13 +657,24 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
bottomPanelArea.value = {
panels: [],
x: 0, // 绝对定位的x坐标
y: 0, // 初始y坐标将在updatePanelsSize中被正确设置
height: 200,
width: 0, // 初始宽度为0将在updatePanelsSize中被正确设置
widthRatios: []
}
centerPanelArea.value = {
panels: [],
x: 0, // 初始x坐标将在updatePanelsSize中被正确设置
y: 0, // 初始y坐标将在updatePanelsSize中被正确设置
width: 0, // 初始宽度为0将在updatePanelsSize中被正确设置
height: 0, // 初始高度为0将在updatePanelsSize中被正确设置
widthRatios: [],
heightRatios: []
}
// 清空其他面板集合
centerPanelArea.value.panels = []
floatingWindows.value = []
minimizedWindows.value = []
}
@@ -674,26 +702,16 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
// 初始化面板大小影响关系和受影响关系
function initializePanelSizeInfluence() {
// 初始化影响关系数据
['left', 'right', 'top', 'bottom','center'].forEach(position => {
panelSizeInfluence.influence[position].value = []
panelSizeInfluence.influencedBy[position].value = []
})
// 使用LayoutCoordinator初始化面板边界系统
// 在新的绝对定位布局系统中影响关系已内置到calculatePanelBounds方法中
// 这里可以保留接口兼容性但实际工作由LayoutCoordinator处理
const influenceData = layoutCoordinator.initializePanelSizeInfluence();
// 使用LayoutCoordinator初始化影响关系
const influenceData = layoutCoordinator.initializePanelSizeInfluence()
// 应用影响关系数据
if (influenceData && influenceData.influence) {
['left', 'right', 'top', 'bottom','center'].forEach(position => {
if (influenceData.influence[position]) {
panelSizeInfluence.influence[position].value = influenceData.influence[position]
}
if (influenceData.influencedBy && influenceData.influencedBy[position]) {
panelSizeInfluence.influencedBy[position].value = influenceData.influencedBy[position]
}
})
}
// 初始化影响关系数据(为了保持兼容性)
['left', 'right', 'top', 'bottom', 'center'].forEach(position => {
panelSizeInfluence.influence[position].value = influenceData?.influence?.[position] || [];
panelSizeInfluence.influencedBy[position].value = influenceData?.influencedBy?.[position] || [];
});
}
// 处理面板大小变化对其他面板的影响
@@ -714,74 +732,84 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
if (!externalContainer) return;
// 调用布局协调器处理面板大小影响
const updatedPanels = layoutCoordinator.handlePanelSizeInfluence(
// 获取容器尺寸
const containerWidth = externalContainer.clientWidth;
const containerHeight = externalContainer.clientHeight;
// 调用更新后的布局协调器处理面板大小影响
// 现在使用面板边界系统处理影响关系
const updatedBounds = layoutCoordinator.handlePanelSizeInfluence(
position,
{
influence: panelSizeInfluence.influence,
influencedBy: panelSizeInfluence.influencedBy
},
panelData,
externalContainer
containerWidth,
containerHeight
);
// 更新面板数据包括面板区域本身的尺寸和内部的panels数组
// 为每个位置定义对应的面板区域变量
const panelAreaMap = {
left: leftPanelArea.value,
right: rightPanelArea.value,
top: topPanelArea.value,
bottom: bottomPanelArea.value,
center: centerPanelArea.value
};
const positions = ['left', 'right', 'top', 'bottom', 'center'];
positions.forEach(pos => {
if (updatedPanels && updatedPanels[pos]) {
const panelArea = panelAreaMap[pos];
// 首先更新面板区域本身的宽高属性(如果有)
if (updatedPanels[pos].width !== undefined) {
panelArea.width = updatedPanels[pos].width;
}
if (updatedPanels[pos].height !== undefined) {
panelArea.height = updatedPanels[pos].height;
}
// 更新panels数组
if (updatedPanels[pos].panels) {
panelArea.panels = updatedPanels[pos].panels;
}
// 更新比例数据
if (updatedPanels[pos].widthRatios) {
panelArea.widthRatios = updatedPanels[pos].widthRatios;
}
if (updatedPanels[pos].heightRatios) {
panelArea.heightRatios = updatedPanels[pos].heightRatios;
// 更新所有面板区域的边界信息
if (updatedBounds) {
// 为每个位置定义对应的面板区域变量
const panelAreaMap = {
left: leftPanelArea.value,
right: rightPanelArea.value,
top: topPanelArea.value,
bottom: bottomPanelArea.value,
center: centerPanelArea.value
};
const positions = ['left', 'right', 'top', 'bottom', 'center'];
positions.forEach(pos => {
if (updatedBounds[pos]) {
const panelArea = panelAreaMap[pos];
// 更新面板区域的位置和尺寸信息
if (updatedBounds[pos].x !== undefined) {
panelArea.x = updatedBounds[pos].x;
}
if (updatedBounds[pos].y !== undefined) {
panelArea.y = updatedBounds[pos].y;
}
if (updatedBounds[pos].width !== undefined) {
panelArea.width = updatedBounds[pos].width;
}
if (updatedBounds[pos].height !== undefined) {
panelArea.height = updatedBounds[pos].height;
}
}
});
// 触发面板区域的响应式更新
leftPanelArea.value = { ...leftPanelArea.value };
rightPanelArea.value = { ...rightPanelArea.value };
topPanelArea.value = { ...topPanelArea.value };
bottomPanelArea.value = { ...bottomPanelArea.value };
centerPanelArea.value = { ...centerPanelArea.value };
// 显式调用updatePanelsSize来更新所有面板区域的子面板尺寸和位置确保子面板大小随面板区域变化
if (leftPanelArea.value && leftPanelArea.value.panels && leftPanelArea.value.panels.length > 0) {
updatePanelsSize('left', leftPanelArea.value, externalContainer);
}
if (rightPanelArea.value && rightPanelArea.value.panels && rightPanelArea.value.panels.length > 0) {
updatePanelsSize('right', rightPanelArea.value, externalContainer);
}
if (topPanelArea.value && topPanelArea.value.panels && topPanelArea.value.panels.length > 0) {
updatePanelsSize('top', topPanelArea.value, externalContainer);
}
if (bottomPanelArea.value && bottomPanelArea.value.panels && bottomPanelArea.value.panels.length > 0) {
updatePanelsSize('bottom', bottomPanelArea.value, externalContainer);
}
if (centerPanelArea.value && centerPanelArea.value.panels && centerPanelArea.value.panels.length > 0) {
updatePanelsSize('center', centerPanelArea.value, externalContainer);
}
});
// 显式调用updatePanelsSize来更新所有面板区域的子面板尺寸确保子面板大小随面板区域变化
if (leftPanelArea.value && leftPanelArea.value.panels && leftPanelArea.value.panels.length > 0) {
updatePanelsSize('left', leftPanelArea.value, externalContainer);
}
if (rightPanelArea.value && rightPanelArea.value.panels && rightPanelArea.value.panels.length > 0) {
updatePanelsSize('right', rightPanelArea.value, externalContainer);
}
if (topPanelArea.value && topPanelArea.value.panels && topPanelArea.value.panels.length > 0) {
updatePanelsSize('top', topPanelArea.value, externalContainer);
}
if (bottomPanelArea.value && bottomPanelArea.value.panels && bottomPanelArea.value.panels.length > 0) {
updatePanelsSize('bottom', bottomPanelArea.value, externalContainer);
}
if (centerPanelArea.value && centerPanelArea.value.panels && centerPanelArea.value.panels.length > 0) {
updatePanelsSize('center', centerPanelArea.value, externalContainer);
}
}
// 更新面板尺寸
/**
* 更新面板尺寸
* @param {string} position - 面板位置
* @param {Object} panelArea - 面板区域对象
* @param {HTMLElement} container - 容器元素
* @param {Object} minSizes - 最小尺寸配置
*/
function updatePanelsSize(position, panelArea, container, minSizes = { panelWidth: 150, panelHeight: 100 }) {
if (!container) return;
@@ -801,97 +829,75 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
center: centerPanelArea.value
};
// 处理不同位置的面板尺寸更新
if (position === 'top' || position === 'bottom') {
// 顶部和底部面板 - 水平排列
// 更新面板区域的完整宽高信息
panelArea.width = layoutCoordinator.calculateAvailableWidth(
position,
panelSizeInfluence,
panelAreas,
containerWidth,
minSizes
);
// 使用当前面板区域的实际高度(已通过分割条调整后的高度)
panelArea.height = position === 'top' ? topPanelArea.value.height : bottomPanelArea.value.height;
// 使用LayoutCoordinator的updatePanelSize方法更新面板尺寸
const updatedBounds = layoutCoordinator.updatePanelSize(
position,
panelArea,
containerWidth,
containerHeight,
panelAreas,
minSizes
);
// 更新面板区域的位置和尺寸信息
if (updatedBounds) {
// 应用边界信息到面板区域
panelArea.x = updatedBounds.x;
panelArea.y = updatedBounds.y;
panelArea.width = updatedBounds.width;
panelArea.height = updatedBounds.height;
// 确保有宽度比例数组,并且长度与面板数量匹配
if (!panelArea.widthRatios || panelArea.widthRatios.length !== panelArea.panels.length) {
panelArea.widthRatios = resetPanelsSizeRatios(panelArea.panels.length);
// 根据面板位置应用不同的面板排列逻辑
if (position === 'top' || position === 'bottom') {
// 顶部和底部面板 - 水平排列
// 确保有宽度比例数组,并且长度与面板数量匹配
if (!panelArea.widthRatios || panelArea.widthRatios.length !== panelArea.panels.length) {
panelArea.widthRatios = resetPanelsSizeRatios(panelArea.panels.length);
}
// 应用面板宽度比例和绝对位置
panelArea.panels.forEach((panel, index) => {
// 计算面板宽度,确保不小于最小宽度
const calculatedWidth = panelArea.width * panelArea.widthRatios[index];
panel.width = Math.max(minSizes.panelWidth || 150, calculatedWidth);
panel.height = updatedBounds.height;
// 设置面板的绝对位置
panel.x = updatedBounds.x + panelArea.panels.slice(0, index).reduce((sum, p) => {
const pIndex = panelArea.panels.indexOf(p);
return sum + (p.width || (panelArea.widthRatios[pIndex] * panelArea.width));
}, 0);
panel.y = updatedBounds.y;
});
} else if (position === 'left' || position === 'right') {
// 左侧和右侧面板 - 垂直排列
// 确保有高度比例数组,并且长度与面板数量匹配
if (!panelArea.heightRatios || panelArea.heightRatios.length !== panelArea.panels.length) {
panelArea.heightRatios = resetPanelsSizeRatios(panelArea.panels.length);
}
// 应用面板高度比例和绝对位置
panelArea.panels.forEach((panel, index) => {
// 计算面板高度,确保不小于最小高度
const calculatedHeight = panelArea.height * panelArea.heightRatios[index];
panel.height = Math.max(minSizes.panelHeight || 100, calculatedHeight);
panel.width = updatedBounds.width;
// 设置面板的绝对位置
panel.x = updatedBounds.x;
panel.y = updatedBounds.y + panelArea.panels.slice(0, index).reduce((sum, p) => {
const pIndex = panelArea.panels.indexOf(p);
return sum + (p.height || (panelArea.heightRatios[pIndex] * panelArea.height));
}, 0);
});
} else if (position === 'center') {
// 中心面板的尺寸和位置设置
// 应用面板宽高和绝对位置(中心面板通常是标签页形式,所有面板共享相同的宽高)
panelArea.panels.forEach((panel) => {
panel.width = updatedBounds.width;
panel.height = updatedBounds.height;
panel.x = updatedBounds.x;
panel.y = updatedBounds.y;
});
}
// 应用面板宽度比例
panelArea.panels.forEach((panel, index) => {
// 计算面板宽度,确保不小于最小宽度
const calculatedWidth = panelArea.width * panelArea.widthRatios[index]
panel.width = Math.max(minSizes.panelWidth || 150, calculatedWidth)
panel.height = panelArea.height
})
} else if (position === 'left' || position === 'right') {
// 左侧和右侧面板 - 垂直排列
// 计算左侧/右侧面板区域的可用高度(考虑顶底面板占用的空间)
const availableHeight = layoutCoordinator.calculateAvailableHeight(
position,
panelSizeInfluence,
panelAreas,
containerHeight,
minSizes
);
// 更新面板区域的完整宽高信息
panelArea.height = availableHeight; // 设置面板区域高度为可用高度
panelArea.width = position === 'left' ? leftPanelArea.value.width : rightPanelArea.value.width; // 保持原有宽度
// 确保有高度比例数组,并且长度与面板数量匹配
if (!panelArea.heightRatios || panelArea.heightRatios.length !== panelArea.panels.length) {
panelArea.heightRatios = resetPanelsSizeRatios(panelArea.panels.length);
}
// 应用面板高度比例
panelArea.panels.forEach((panel, index) => {
// 计算面板高度,确保不小于最小高度
const calculatedHeight = panelArea.height * panelArea.heightRatios[index]
panel.height = Math.max(minSizes.panelHeight || 100, calculatedHeight)
panel.width = panelArea.width
})
}
// 新增中心面板的处理逻辑
else if (position === 'center') {
// 中心面板的尺寸计算(考虑其他面板占用的空间)
const availableWidth = layoutCoordinator.calculateAvailableWidth(
position,
panelSizeInfluence,
panelAreas,
containerWidth,
minSizes
);
const availableHeight = layoutCoordinator.calculateAvailableHeight(
position,
panelSizeInfluence,
panelAreas,
containerHeight,
minSizes
);
// 更新面板区域的宽高信息
panelArea.width = availableWidth;
panelArea.height = availableHeight;
// 确保有宽高比例数组,并且长度与面板数量匹配
if (!panelArea.widthRatios || panelArea.widthRatios.length !== panelArea.panels.length) {
panelArea.widthRatios = resetPanelsSizeRatios(panelArea.panels.length);
}
if (!panelArea.heightRatios || panelArea.heightRatios.length !== panelArea.panels.length) {
panelArea.heightRatios = resetPanelsSizeRatios(panelArea.panels.length);
}
// 应用面板宽高(中心面板通常是标签页形式,所有面板共享相同的宽高)
panelArea.panels.forEach((panel, index) => {
panel.width = panelArea.width;
panel.height = panelArea.height;
});
}
// 应用更新后的面板数据,触发响应式更新
@@ -942,38 +948,60 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
// 包装LayoutCoordinator的adjustRegionSize方法
function adjustRegionSize(target, delta, container = null) {
if (!container) return;
// 准备面板区域数据
const panelAreas = {
top: topPanelArea.value,
bottom: bottomPanelArea.value,
left: leftPanelArea.value,
right: rightPanelArea.value
}
right: rightPanelArea.value,
center: centerPanelArea.value
};
let containerHeight = null
if (container) {
containerHeight = container.clientHeight
}
// 获取容器尺寸
const containerWidth = container.clientWidth;
const containerHeight = container.clientHeight;
let newSize
switch (target) {
case 'left':
newSize = layoutCoordinator.adjustRegionSize('left', panelAreas.left.width, delta)
panelAreas.left.width = newSize
// 调用更新后的adjustRegionSize方法获取更新后的面板边界
const updatedBounds = layoutCoordinator.adjustRegionSize(
target,
delta,
panelAreas,
containerWidth,
containerHeight
);
break
case 'right':
newSize = layoutCoordinator.adjustRegionSize('right', panelAreas.right.width, -delta)
panelAreas.right.width = newSize
break
case 'top':
newSize = layoutCoordinator.adjustRegionSize('top', panelAreas.top.height, delta, panelAreas, containerHeight)
panelAreas.top.height = newSize
break
case 'bottom':
newSize = layoutCoordinator.adjustRegionSize('bottom', panelAreas.bottom.height, -delta, panelAreas, containerHeight)
panelAreas.bottom.height = newSize
break
// 更新面板区域的位置和尺寸信息
if (updatedBounds) {
// 更新受影响区域的尺寸和位置
Object.keys(updatedBounds).forEach(position => {
const bounds = updatedBounds[position];
const panelArea = panelAreas[position];
if (bounds.x !== undefined) {
panelArea.x = bounds.x;
}
if (bounds.y !== undefined) {
panelArea.y = bounds.y;
}
if (bounds.width !== undefined) {
panelArea.width = bounds.width;
}
if (bounds.height !== undefined) {
panelArea.height = bounds.height;
}
});
// 触发面板区域的响应式更新
leftPanelArea.value = { ...leftPanelArea.value };
rightPanelArea.value = { ...rightPanelArea.value };
topPanelArea.value = { ...topPanelArea.value };
bottomPanelArea.value = { ...bottomPanelArea.value };
centerPanelArea.value = { ...centerPanelArea.value };
// 应用尺寸变化后,处理面板大小对其他面板的影响
handlePanelSizeInfluence(target, container);
}
}
return {