478 lines
24 KiB
JavaScript
478 lines
24 KiB
JavaScript
const alignBottomSvg = `<svg t="1725534360155" class="icon" viewBox="0 0 1170 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1662" width="100%"><path d="M1170.285714 987.428571a36.571429 36.571429 0 0 0-36.571428-36.571428H36.571429a36.571429 36.571429 0 0 0 0 73.142857h1097.142857a36.571429 36.571429 0 0 0 36.571428-36.571429z m-219.428571-146.285714v-512a36.571429 36.571429 0 0 0-36.571429-36.571428h-219.428571a36.571429 36.571429 0 0 0-36.571429 36.571428v512a36.571429 36.571429 0 0 0 36.571429 36.571429h219.428571a36.571429 36.571429 0 0 0 36.571429-36.571429z m-438.857143 0V36.571429a36.571429 36.571429 0 0 0-36.571429-36.571429h-219.428571a36.571429 36.571429 0 0 0-36.571429 36.571429v804.571428a36.571429 36.571429 0 0 0 36.571429 36.571429h219.428571a36.571429 36.571429 0 0 0 36.571429-36.571429z" fill="#666666" p-id="1663"></path></svg>`;
|
|
const alignCenterHorizontallySvg = `<svg t="1725534379860" class="icon" viewBox="0 0 1243 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2250" width="100%"><path d="M548.571429 472.356571h146.285714V231.643429a36.571429 36.571429 0 0 1 36.571428-36.571429h219.428572a36.571429 36.571429 0 0 1 36.571428 36.571429v240.713142h179.785143a39.643429 39.643429 0 0 1 0 79.286858H987.428571v240.713142a36.571429 36.571429 0 0 1-36.571428 36.571429h-219.428572a36.571429 36.571429 0 0 1-36.571428-36.571429V551.643429h-146.285714V950.857143a36.571429 36.571429 0 0 1-36.571429 36.571428H292.571429a36.571429 36.571429 0 0 1-36.571429-36.571428V551.643429H76.214857a39.643429 39.643429 0 1 1 0-79.286858H256V73.142857A36.571429 36.571429 0 0 1 292.571429 36.571429h219.428571a36.571429 36.571429 0 0 1 36.571429 36.571428v399.213714z" fill="#666666" p-id="2251"></path></svg>`;
|
|
const alignCenterVerticallySvg = `<svg t="1725534363707" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1809" width="100%"><path d="M477.312 576V448H266.688a32 32 0 0 1-32-32v-192a32 32 0 0 1 32-32h210.624V34.688a34.688 34.688 0 0 1 69.376 0V192h210.624a32 32 0 0 1 32 32v192a32 32 0 0 1-32 32H546.688v128H896a32 32 0 0 1 32 32v192a32 32 0 0 1-32 32H546.688v157.312a34.688 34.688 0 1 1-69.376 0V832H128a32 32 0 0 1-32-32v-192A32 32 0 0 1 128 576h349.312z" fill="#666666" p-id="1810"></path></svg>`;
|
|
const alignLeftSvg = `<svg t="1725534370541" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2103" width="100%"><path d="M96 0a32 32 0 0 1 32 32v960a32 32 0 0 1-64 0V32A32 32 0 0 1 96 0z m128 192h448a32 32 0 0 1 32 32v192a32 32 0 0 1-32 32h-448a32 32 0 0 1-32-32v-192a32 32 0 0 1 32-32z m0 384h704a32 32 0 0 1 32 32v192a32 32 0 0 1-32 32h-704a32 32 0 0 1-32-32v-192a32 32 0 0 1 32-32z" fill="#666666" p-id="2104"></path></svg>`;
|
|
const alignRightSvg = `<svg t="1725534384109" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2397" width="100%"><path d="M928 0a32 32 0 0 1 32 32v960a32 32 0 0 1-64 0V32a32 32 0 0 1 32-32z m-576 192h448a32 32 0 0 1 32 32v192a32 32 0 0 1-32 32h-448a32 32 0 0 1-32-32v-192a32 32 0 0 1 32-32z m-256 384h704a32 32 0 0 1 32 32v192a32 32 0 0 1-32 32H96a32 32 0 0 1-32-32v-192A32 32 0 0 1 96 576z" fill="#666666" p-id="2398"></path></svg>`;
|
|
const alignTopSvg = `<svg t="1725534367556" class="icon" viewBox="0 0 1170 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1956" width="100%"><path d="M1170.285714 36.571429a36.571429 36.571429 0 0 1-36.571428 36.571428H36.571429a36.571429 36.571429 0 0 1 0-73.142857h1097.142857a36.571429 36.571429 0 0 1 36.571428 36.571429z m-219.428571 146.285714v512a36.571429 36.571429 0 0 1-36.571429 36.571428h-219.428571a36.571429 36.571429 0 0 1-36.571429-36.571428v-512a36.571429 36.571429 0 0 1 36.571429-36.571429h219.428571a36.571429 36.571429 0 0 1 36.571429 36.571429z m-438.857143 0v804.571428a36.571429 36.571429 0 0 1-36.571429 36.571429h-219.428571a36.571429 36.571429 0 0 1-36.571429-36.571429v-804.571428a36.571429 36.571429 0 0 1 36.571429-36.571429h219.428571a36.571429 36.571429 0 0 1 36.571429 36.571429z" fill="#666666" p-id="1957"></path></svg>`;
|
|
const horizontalDistributionSvg = `<svg t="1725534354023" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1515" width="100%"><path d="M96 0a32 32 0 0 1 32 32v960a32 32 0 0 1-64 0V32A32 32 0 0 1 96 0z m832 0a32 32 0 0 1 32 32v960a32 32 0 0 1-64 0V32a32 32 0 0 1 32-32zM384 800v-576a32 32 0 0 1 32-32h192a32 32 0 0 1 32 32v576a32 32 0 0 1-32 32h-192a32 32 0 0 1-32-32z" fill="#666666" p-id="1516"></path></svg>`;
|
|
const verticalDistributionSvg = `<svg t="1725534350231" class="icon" viewBox="0 0 1170 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1368" width="100%"><path d="M1170.285714 36.571429a36.571429 36.571429 0 0 1-36.571428 36.571428H36.571429a36.571429 36.571429 0 0 1 0-73.142857h1097.142857a36.571429 36.571429 0 0 1 36.571428 36.571429z m0 950.857142a36.571429 36.571429 0 0 1-36.571428 36.571429H36.571429a36.571429 36.571429 0 0 1 0-73.142857h1097.142857a36.571429 36.571429 0 0 1 36.571428 36.571428zM256 365.714286h658.285714a36.571429 36.571429 0 0 1 36.571429 36.571428v219.428572a36.571429 36.571429 0 0 1-36.571429 36.571428h-658.285714a36.571429 36.571429 0 0 1-36.571429-36.571428v-219.428572a36.571429 36.571429 0 0 1 36.571429-36.571428z" fill="#666666" p-id="1369"></path></svg>`;
|
|
const equalWidthSvg = `<svg t="1725606034670" class="icon" viewBox="0 0 1088 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7213" width="100%"><path d="M978.24 480a42.688 42.688 0 0 1-42.688 42.688H172.928a42.688 42.688 0 0 1-42.688-42.688V213.312c0-23.552 19.072-42.624 42.688-42.624h762.624c23.552 0 42.688 19.072 42.688 42.624V480z" fill="#666666" p-id="7214"></path><path d="M256.96 734.144c0-14.08 11.456-25.6 25.6-25.6h543.36a25.6 25.6 0 0 1 0 51.2h-543.36a25.6 25.6 0 0 1-25.6-25.6z" fill="#666666" p-id="7215"></path><path d="M136.64 745.216a12.8 12.8 0 0 1 0-22.144l184.192-106.368a12.8 12.8 0 0 1 19.2 11.072v212.736a12.8 12.8 0 0 1-19.2 11.072l-184.192-106.368zM971.84 745.216a12.8 12.8 0 0 0 0-22.144l-184.256-106.368a12.8 12.8 0 0 0-19.2 11.072v212.736a12.8 12.8 0 0 0 19.2 11.072l184.256-106.368z" fill="#666666" p-id="7216"></path></svg>`
|
|
const equalHeightSvg = `<svg t="1725606224564" class="icon" viewBox="0 0 1088 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7790" width="100%"><path d="M572.16 936a42.688 42.688 0 0 1-42.688-42.688V130.688c0-23.616 19.136-42.688 42.688-42.688h266.688c23.552 0 42.624 19.072 42.624 42.688v762.624a42.688 42.688 0 0 1-42.624 42.688H572.16z" fill="#666666" p-id="7791"></path><path d="M318.016 214.72c14.08 0 25.6 11.456 25.6 25.6v543.36a25.6 25.6 0 1 1-51.2 0v-543.36c0-14.144 11.456-25.6 25.6-25.6z" fill="#666666" p-id="7792"></path><path d="M306.944 94.4a12.8 12.8 0 0 1 22.144 0l106.368 184.192a12.8 12.8 0 0 1-11.072 19.2H211.648a12.8 12.8 0 0 1-11.072-19.2l106.368-184.192zM306.944 929.6a12.8 12.8 0 0 0 22.144 0l106.368-184.192a12.8 12.8 0 0 0-11.072-19.2H211.648a12.8 12.8 0 0 0-11.072 19.2l106.368 184.192z" fill="#666666" p-id="7793"></path></svg>`
|
|
|
|
const current_node_list = []; // 存储已选中的节点
|
|
|
|
const ButtonManager = {
|
|
isInitialized: false, // 检查是否已经初始化
|
|
buttonContainer: null, // 保存按钮容器
|
|
contextMenu: null, // 右键菜单
|
|
isPermanent: true, // 是否为驻留按钮
|
|
initialX: 0, // 初始位置X
|
|
initialY: 0, // 初始位置Y
|
|
dragStartX: 0, // 拖拽开始时的X
|
|
dragStartY: 0, // 拖拽开始时的Y
|
|
isDragging: false, // 检查是否正在拖拽
|
|
|
|
// 初始化按钮
|
|
init() {
|
|
if (this.isInitialized) return; // 如果已经初始化过,不再重复创建
|
|
|
|
// 使用 CSS 定义 hover 效果和所有样式
|
|
const style = document.createElement('style');
|
|
style.textContent = `
|
|
#alignment-buttons {
|
|
position: absolute;
|
|
top: 20px;
|
|
right: 10px;
|
|
left: unset;
|
|
bottom: unset;
|
|
display: flex;
|
|
background: #333333;
|
|
padding: 4px;
|
|
border-radius: 4px;
|
|
z-index: 999;
|
|
width: 290px;
|
|
white-space: nowrap; /* 禁止换行,确保按钮在同一行显示 */
|
|
}
|
|
.custom-button {
|
|
width: 25px;
|
|
height: 25px;
|
|
background-size: contain;
|
|
background-repeat: no-repeat;
|
|
background-position: center;
|
|
background-color: #333333;
|
|
border: none;
|
|
cursor: pointer;
|
|
padding: 4px;
|
|
border-radius: 4px;
|
|
transition: background-color 0.3s ease;
|
|
}
|
|
.custom-button:hover {
|
|
background-color: #555555;
|
|
}
|
|
.divider {
|
|
width: 3.2px;
|
|
height: 15px;
|
|
background-color: #262626;
|
|
margin: 5px 4px;
|
|
border-radius: 9px;
|
|
cursor: grab;
|
|
}
|
|
.divider:active {
|
|
cursor: grabbing;
|
|
}
|
|
`;
|
|
document.head.appendChild(style);
|
|
|
|
// 创建按钮容器
|
|
this.buttonContainer = document.createElement('div');
|
|
this.buttonContainer.id = 'alignment-buttons';
|
|
|
|
// 从 localStorage 恢复位置
|
|
this.restorePosition();
|
|
|
|
document.body.appendChild(this.buttonContainer);
|
|
|
|
// 创建按钮并分配功能
|
|
const buttons = this.getButtons();
|
|
buttons.forEach(btn => {
|
|
if (btn.type === 'divider') {
|
|
// 创建分割线
|
|
const divider = document.createElement('div');
|
|
divider.classList.add('divider');
|
|
// 添加拖拽功能
|
|
divider.addEventListener('mousedown', this.onDragStart.bind(this));
|
|
document.addEventListener('mousemove', this.onDragging.bind(this));
|
|
document.addEventListener('mouseup', this.onDragEnd.bind(this));
|
|
|
|
this.buttonContainer.appendChild(divider);
|
|
} else {
|
|
// 创建按钮
|
|
const button = document.createElement('button');
|
|
button.id = btn.id;
|
|
button.classList.add('custom-button');
|
|
button.innerHTML = btn.svg;
|
|
button.addEventListener('click', btn.action);
|
|
this.buttonContainer.appendChild(button);
|
|
}
|
|
});
|
|
|
|
this.isInitialized = true; // 标记已经初始化
|
|
this.showContextMenu()
|
|
|
|
this.isPermanent = localStorage.getItem('NodeAlignerIsPermanent') == '1';
|
|
this.isPermanent ? this.show() : this.hide();
|
|
},
|
|
|
|
// 获取按钮配置
|
|
getButtons() {
|
|
return [
|
|
/* 左对齐 */
|
|
{ id: 'alignLeft', svg: alignLeftSvg, action: this.alignLeft.bind(this) },
|
|
/* 竖向居中对齐 */
|
|
{ id: 'alignCenterVertically', svg: alignCenterVerticallySvg, action: this.alignCenterVertically.bind(this) },
|
|
/* 右对齐 */
|
|
{ id: 'alignRight', svg: alignRightSvg, action: this.alignRight.bind(this) },
|
|
// 分割线
|
|
{ type: 'divider' },
|
|
/* 顶部对齐 */
|
|
{ id: 'alignTop', svg: alignTopSvg, action: this.alignTop.bind(this) },
|
|
/* 横向居中对齐 */
|
|
{ id: 'alignCenterHorizontally', svg: alignCenterHorizontallySvg, action: this.alignCenterHorizontally.bind(this) },
|
|
/* 底部对齐 */
|
|
{ id: 'alignBottom', svg: alignBottomSvg, action: this.alignBottom.bind(this) },
|
|
// 分割线
|
|
{ type: 'divider' },
|
|
/* 横向分布 */
|
|
{ id: 'horizontalDistribution', svg: horizontalDistributionSvg, action: this.horizontalDistribution.bind(this) },
|
|
/* 竖向分布 */
|
|
{ id: 'verticalDistribution', svg: verticalDistributionSvg, action: this.verticalDistribution.bind(this) },
|
|
// 分割线
|
|
{ type: 'divider' },
|
|
/* 等宽 */
|
|
{ id: 'equalWidth', svg: equalWidthSvg, action: this.equalWidth.bind(this) },
|
|
/* 等高 */
|
|
{ id: 'equalHeight', svg: equalHeightSvg, action: this.equalHeight.bind(this) },
|
|
];
|
|
},
|
|
// 显示右键菜单
|
|
showContextMenu() {
|
|
// 创建右键菜单元素
|
|
this.contextMenu = document.createElement('div');
|
|
this.contextMenu.id = 'context-menu';
|
|
this.contextMenu.style.display = 'none'; // 初始设置为不显示
|
|
this.contextMenu.innerHTML = `
|
|
<button id="pin-mode">驻留</button>
|
|
<button id="toggle-on-select">选中后显示</button>
|
|
`;
|
|
this.buttonContainer.appendChild(this.contextMenu);
|
|
|
|
// 绑定右键菜单显示事件
|
|
this.buttonContainer.addEventListener('contextmenu', (event) => {
|
|
event.preventDefault();
|
|
this.contextMenu.style.display = 'block';
|
|
this.contextMenu.style.left = `${event.pageX}px`;
|
|
this.contextMenu.style.top = `${event.pageY}px`;
|
|
});
|
|
|
|
// 绑定菜单项的点击事件
|
|
this.contextMenu.querySelector('#pin-mode').addEventListener('click', () => {
|
|
// 实现固定模式的逻辑
|
|
this.contextMenu.style.display = 'none'; // 隐藏右键菜
|
|
this.isPermanent = true;
|
|
localStorage.setItem('NodeAlignerIsPermanent', '1');
|
|
this.restorePosition();
|
|
});
|
|
this.contextMenu.querySelector('#toggle-on-select').addEventListener('click', () => {
|
|
// 实现选中后显示模式的逻辑
|
|
this.buttonContainer.style.display = 'none'; // 默认不显示按钮容器
|
|
this.contextMenu.style.display = 'none'; // 隐藏右键菜单
|
|
this.isPermanent = false;
|
|
localStorage.setItem('NodeAlignerIsPermanent', '0');
|
|
});
|
|
},
|
|
// 显示按钮
|
|
show() {
|
|
this.buttonContainer.style.display = 'flex'; // 显示按钮容器
|
|
},
|
|
|
|
// 隐藏按钮
|
|
hide() {
|
|
this.buttonContainer.style.display = 'none'; // 隐藏按钮容器
|
|
},
|
|
setPosition(x, y) {
|
|
this.buttonContainer.style.left = `${x}px`;
|
|
this.buttonContainer.style.top = `${y}px`;
|
|
},
|
|
// 开始拖拽
|
|
onDragStart(e) {
|
|
if (e.target.classList.contains('divider')) {
|
|
this.isDragging = true;
|
|
this.initialX = e.clientX;
|
|
this.initialY = e.clientY;
|
|
const rect = this.buttonContainer.getBoundingClientRect();
|
|
this.dragStartX = rect.left;
|
|
this.dragStartY = rect.top;
|
|
// 锁定宽度和高度,防止拖拽时改变
|
|
this.buttonContainer.style.width = `${rect.width}px`;
|
|
this.buttonContainer.style.height = `${rect.height}px`;
|
|
}
|
|
},
|
|
|
|
// 拖拽中
|
|
onDragging(e) {
|
|
if (this.isDragging) {
|
|
const deltaX = e.clientX - this.initialX;
|
|
const deltaY = e.clientY - this.initialY;
|
|
this.buttonContainer.style.left = `${this.dragStartX + deltaX}px`;
|
|
this.buttonContainer.style.top = `${this.dragStartY + deltaY}px`;
|
|
}
|
|
},
|
|
// 结束拖拽
|
|
onDragEnd() {
|
|
if (this.isDragging) {
|
|
this.isDragging = false;
|
|
|
|
// 获取按钮容器的位置信息
|
|
const rect = this.buttonContainer.getBoundingClientRect();
|
|
const windowWidth = window.innerWidth;
|
|
const windowHeight = window.innerHeight;
|
|
|
|
// 计算距离四个边的距离
|
|
const distanceToTop = rect.top;
|
|
const distanceToBottom = windowHeight - rect.bottom;
|
|
const distanceToLeft = rect.left;
|
|
const distanceToRight = windowWidth - rect.right;
|
|
|
|
// 选择两个最近的边
|
|
let top = 'unset';
|
|
let bottom = 'unset';
|
|
let left = 'unset';
|
|
let right = 'unset';
|
|
|
|
if (distanceToTop < distanceToBottom) {
|
|
top = `${distanceToTop}px`;
|
|
} else {
|
|
bottom = `${distanceToBottom}px`;
|
|
}
|
|
|
|
if (distanceToLeft < distanceToRight) {
|
|
left = `${distanceToLeft}px`;
|
|
} else {
|
|
right = `${distanceToRight}px`;
|
|
}
|
|
|
|
// 更新样式使其根据距离四边的情况固定
|
|
this.buttonContainer.style.top = top;
|
|
this.buttonContainer.style.bottom = bottom;
|
|
this.buttonContainer.style.left = left;
|
|
this.buttonContainer.style.right = right;
|
|
|
|
// 保存位置到 localStorage
|
|
localStorage.setItem('NodeAlignerButtonContainerPosition', JSON.stringify({ top, left, right, bottom }));
|
|
|
|
// 恢复自动宽度和高度
|
|
this.buttonContainer.style.width = 'auto';
|
|
this.buttonContainer.style.height = 'auto';
|
|
}
|
|
},
|
|
// 恢复位置
|
|
restorePosition() {
|
|
const savedPosition = JSON.parse(localStorage.getItem('NodeAlignerButtonContainerPosition'));
|
|
if (savedPosition) {
|
|
this.buttonContainer.style.top = savedPosition.top;
|
|
this.buttonContainer.style.bottom = savedPosition.bottom;
|
|
this.buttonContainer.style.left = savedPosition.left;
|
|
this.buttonContainer.style.right = savedPosition.right;
|
|
}
|
|
},
|
|
// 获取当前选中的节点
|
|
getSelectedNodes() {
|
|
return current_node_list.filter(node => node.is_selected === true);
|
|
},
|
|
|
|
// 执行对齐操作的通用方法
|
|
alignNodesByProperty(prop, value) {
|
|
const nodes = this.getSelectedNodes();
|
|
if (nodes.length > 0) {
|
|
nodes.forEach(node => {
|
|
node.pos[prop] = value;
|
|
});
|
|
LGraphCanvas.active_canvas.setDirty(true, true); // 重新渲染 canvas
|
|
}
|
|
},
|
|
|
|
// 左对齐
|
|
alignLeft() {
|
|
const selectedNodes = this.getSelectedNodes();
|
|
if (selectedNodes.length === 0) {
|
|
// 如果没有选中任何节点,重置视图位置和缩放比例
|
|
const canvas = LGraphCanvas.active_canvas;
|
|
if (canvas) {
|
|
canvas.ds.offset = [80, 140]; // 重置视图位置
|
|
canvas.ds.scale = 1; // 重置缩放比例
|
|
canvas.setDirty(true, true);
|
|
}
|
|
} else if (selectedNodes.length === 1) {
|
|
selectedNodes[0].pos[0] = 0;
|
|
} else if (selectedNodes.length > 1) {
|
|
const leftMost = Math.min(...selectedNodes.map(node => node.pos[0]));
|
|
this.alignNodesByProperty(0, leftMost);
|
|
}
|
|
LGraphCanvas.active_canvas.setDirty(true, true);
|
|
},
|
|
// 右对齐
|
|
alignRight() {
|
|
const rightMost = Math.max(...this.getSelectedNodes().map(node => node.pos[0] + node.size[0]));
|
|
this.getSelectedNodes().forEach(node => {
|
|
node.pos[0] = rightMost - node.size[0];
|
|
});
|
|
LGraphCanvas.active_canvas.setDirty(true, true);
|
|
},
|
|
// 顶部对齐
|
|
alignTop() {
|
|
const selectedNodes = this.getSelectedNodes();
|
|
if (selectedNodes.length === 1) {
|
|
selectedNodes[0].pos[1] = 0;
|
|
} else if (selectedNodes.length > 1) {
|
|
const topMost = Math.min(...selectedNodes.map(node => node.pos[1]));
|
|
this.alignNodesByProperty(1, topMost);
|
|
}
|
|
LGraphCanvas.active_canvas.setDirty(true, true);
|
|
},
|
|
|
|
// 底部对齐
|
|
alignBottom() {
|
|
const bottomMost = Math.max(...this.getSelectedNodes().map(node => node.pos[1] + node.size[1]));
|
|
this.getSelectedNodes().forEach(node => {
|
|
node.pos[1] = bottomMost - node.size[1];
|
|
});
|
|
LGraphCanvas.active_canvas.setDirty(true, true);
|
|
},
|
|
|
|
// 水平居中对齐
|
|
alignCenterHorizontally() {
|
|
const centerY = this.calculateCenter(1);
|
|
this.getSelectedNodes().forEach(node => {
|
|
node.pos[1] = centerY - node.size[1] / 2;
|
|
});
|
|
LGraphCanvas.active_canvas.setDirty(true, true);
|
|
},
|
|
|
|
// 垂直居中对齐
|
|
alignCenterVertically() {
|
|
const centerX = this.calculateCenter(0);
|
|
this.getSelectedNodes().forEach(node => {
|
|
node.pos[0] = centerX - node.size[0] / 2;
|
|
});
|
|
LGraphCanvas.active_canvas.setDirty(true, true);
|
|
},
|
|
|
|
// 计算节点的中心坐标
|
|
calculateCenter(axis) {
|
|
const nodes = this.getSelectedNodes();
|
|
const min = Math.min(...nodes.map(node => node.pos[axis]));
|
|
const max = Math.max(...nodes.map(node => node.pos[axis] + node.size[axis]));
|
|
return (min + max) / 2;
|
|
},
|
|
|
|
// 横向分布
|
|
horizontalDistribution() {
|
|
this.distributeNodes(0);
|
|
},
|
|
|
|
// 纵向分布
|
|
verticalDistribution() {
|
|
this.distributeNodes(1);
|
|
},
|
|
|
|
// 等宽
|
|
equalWidth() {
|
|
this.equalSize(0);
|
|
},
|
|
|
|
// 等高
|
|
equalHeight() {
|
|
this.equalSize(1);
|
|
},
|
|
|
|
// 通用的节点尺寸调整
|
|
equalSize(axis) {
|
|
const nodes = this.getSelectedNodes();
|
|
if (nodes.length > 0) {
|
|
// 找到节点中最大的尺寸
|
|
const maxSize = Math.max(...nodes.map(node => node.size[axis]));
|
|
nodes.forEach(node => {
|
|
node.size[axis] = maxSize; // 设置所有节点的大小为最大值
|
|
});
|
|
LGraphCanvas.active_canvas.setDirty(true, true);
|
|
}
|
|
},
|
|
|
|
// 通用的节点分布方法
|
|
distributeNodes(axis) {
|
|
const nodes = this.getSelectedNodes();
|
|
|
|
if (nodes.length > 1) {
|
|
// 按照节点在 axis 轴上的位置(高低)进行排序
|
|
nodes.sort((a, b) => a.pos[axis] - b.pos[axis]);
|
|
|
|
// 获取最小和最大的位置范围
|
|
const min = Math.min(...nodes.map(node => node.pos[axis]));
|
|
const max = Math.max(...nodes.map(node => node.pos[axis] + node.size[axis]));
|
|
|
|
// 计算节点的总尺寸
|
|
const totalSize = nodes.reduce((sum, node) => sum + node.size[axis], 0);
|
|
|
|
// 计算间距
|
|
const spacing = (max - min - totalSize) / (nodes.length - 1);
|
|
|
|
// 初始化当前分布位置
|
|
let current = min;
|
|
|
|
// 遍历排序后的节点,按顺序分布
|
|
nodes.forEach(node => {
|
|
node.pos[axis] = current; // 设置当前节点位置
|
|
current += node.size[axis] + spacing; // 更新下一个节点位置
|
|
});
|
|
|
|
// 重新渲染画布
|
|
LGraphCanvas.active_canvas.setDirty(true, true);
|
|
}
|
|
}
|
|
};
|
|
|
|
function pollForCanvas() {
|
|
const canvas = document.querySelector('canvas#graph-canvas');
|
|
if (canvas) {
|
|
ButtonManager.init();
|
|
// 监听左键单击事件
|
|
canvas.addEventListener('click', function (event) {
|
|
event.preventDefault();
|
|
console.log(event);
|
|
// console.log(event);
|
|
|
|
// 获取当前的 `LGraphCanvas` 数据
|
|
const current_node = event.target.data?.current_node;
|
|
|
|
// 判断 `current_node` 是否存在
|
|
if (current_node !== null && current_node !== undefined) {
|
|
// 判断 `current_node` 是否已经在 `current_node_list` 中
|
|
const nodeExists = current_node_list.some(node => node.id === current_node.id);
|
|
if (!nodeExists) {
|
|
// 如果当前节点不存在列表中,则添加
|
|
current_node_list.push(current_node);
|
|
}
|
|
} else {
|
|
// 如果没有选中的节点,清空列表
|
|
current_node_list.length = 0;
|
|
if (!ButtonManager.isPermanent) ButtonManager.hide();
|
|
}
|
|
|
|
if (!ButtonManager.isPermanent) {
|
|
const selectedNodes = current_node_list.filter(node => node.is_selected === true);
|
|
if (selectedNodes.length >= 2) {
|
|
ButtonManager.show();
|
|
ButtonManager.setPosition(event.layerX, event.layerY - 40)
|
|
}
|
|
}
|
|
|
|
});
|
|
} else {
|
|
setTimeout(pollForCanvas, 1000); // 每隔 1 秒尝试查找一次
|
|
}
|
|
}
|
|
|
|
// 启动轮询查找
|
|
pollForCanvas();
|
|
|