Open wangtao-bugkiller opened 1 week ago
是想在拖动的过程中实时的更新这个节点将要插入的位置,每次一插入临时节点就卡死了
const treeLayout = { type: 'mindmap', direction: 'LR', getHeight: node => { const { images, title, id } = node; let textArr = splitTitle(title); let textHeight = textArr.length * 26 + 20; if (images && images?.length > 0) { textArr += 52; }
return textHeight;
},
getWidth: node => {
const { depth, images, marks, nodeType, title } = node;
const textWidth = depth === 0 ? getTextSize(title, 30)[0] : getTextSize(title, 22)[0];
// 对 marks 进行边界条件检查
let tagsWidth = getTagListLength(marks);
const nodeTypeWidth = nodeType === 'CATA' ? 30 : 0;
const imageLength = images ? images.length * 52 : 0;
// 确保 textWidth 的值在合理的范围内,以避免潜在的计算错误
const adjustedTextWidth = textWidth > 800 ? 900 : textWidth;
const width = Math.max(adjustedTextWidth + tagsWidth + nodeTypeWidth, imageLength);
return width;
},
getVGap: d => {
const { children, depth, images } = d;
if (Array.isArray(images) && images.length > 0) {
return 40;
}
return 20;
},
getHGap: d => {
const { children, depth } = d;
if (!depth) {
return 60;
}
const times = {
0: 10,
1: 9,
2: 7,
3: 6,
};
if (children && children.length > 0) {
return children.length * (times[depth] || 6) + (children.length < 5 ? 40 : 10);
}
return 30;
},
getSide: node => {
return 'right';
},
}; const renderG6 = () => { const grid = new G6.Grid(); const minimap = new G6.Minimap({ size: [150, 150], className: 'g6-minimap', type: 'delegate', hideEdge: true, });
const container = document.getElementById('xmindContainer');
const width = container.getBoundingClientRect().width;
const height = container.getBoundingClientRect().height;
setDivWH({ width, height });
mindMapTree = new G6.TreeGraph({
container: 'xmindContainer',
width,
height,
// fitView: true,
fitCenter: true,
enabledStack: true,
maxStep: 20,
// autoRefresh: true,
// fitViewPadding: [10, 20],
layout: treeLayout,
defaultEdge: {
type: 'cubic-horizontal',
style: {
lineWidth: 2,
stroke: '#CED4D9',
},
},
animate: false,
animateCfg: {
duration: 300, // Number,一次动画的时长
},
defaultNode: {
type: 'dice-mind-map-root',
},
minZoom: 0.5,
modes: {
default: [
{
type: 'drag-node',
enableDelegate: true,
enableStack: false,
enableDebounce: true,
// shouldUpdate: function(e, self) {
// return true;
// },
},
{
type: 'collapse-expand',
onChange: function onChange(item, collapsed) {
const data = item.get('model');
data.collapsed = collapsed;
return true;
},
shouldBegin: (e, self) => {
return false;
},
},
'wheel-scroll',
'scroll-canvas',
'dice-mindmap',
'dice-mindmap-drag',
{
type: 'click-select',
trigger: 'shift',
shouldBegin: (e, self) => {
const actionsList = ['expand', 'collapse', 'deleteTargetTag'];
const nameList = ['collapse-icon'];
const status = e.item?._cfg?.states || [];
const action = e.target?.cfg?.action || '';
const regex = /previewPic(\d+)/;
const match = action.match(regex);
const regexDel = /deletePic(\d+)/;
const matchDel = action.match(regexDel);
const name = e.target?.cfg?.name || '';
if (
(nameList.includes(name) || match || matchDel || actionsList.includes(action)) &&
status.includes('selected')
)
return false;
return true;
},
},
{
type: 'brush-select',
trigger: 'drag',
includeEdges: false,
},
],
},
plugins: [minimap, grid],
});
mindMapTree.data(dataTransform(xmindData || {}));
mindMapTree.render(); };
麻烦帮忙看下,拖拽改变节点的顺序,得有一个临时节点在拖拽过程中实时插入图里显示当前插入位置,就像xmind 软件里面拖拽节点的功能那样,我在插入临时节点的时候渲染就卡住了,不知道怎么解决
麻烦帮忙看一下
Describe the bug / 问题描述
脑图里面拖拽节点的时候,去插入一个临时节点来显示当前插入的位置,总是卡死无法继续
Reproduction link / 重现链接
No response
Steps to Reproduce the Bug or Issue / 重现步骤
let dragNodeOriPos, minDisNode, minDisNodeId, dragRect, insertPos, insertIndex, lastInsertPostion, lastMinDisNode, lastMinDisNodeId, targetIndex, newParentId, newParentNode, targetInsertIndex, targetParentID;
/**
@returns {boolean|Object} - 如果没有碰撞返回false,如果发生碰撞返回包含插入位置和碰撞状态的对象 */ const collide = (node, rect, x, y) => { // 如果节点不存在,直接返回false if (!node) return false;
// 获取节点的边界框,并添加padding以扩大碰撞检测范围 var nodeBBox = node.getBBox(), padding = 10, expandedNodeBBox = { x: nodeBBox.minX - padding, y: nodeBBox.minY - padding, width: nodeBBox.width + 2 padding, height: nodeBBox.height + 2 padding, }, // 构造拖动矩形的边界框,高度翻倍以适应特定的碰撞检测需求 draggedRect = { x: rect.x - padding, y: rect.y - padding, width: rect.width + 2 padding, height: 2 rect.height, };
// 判断拖动过程中是否与其他结点发生碰撞 var isColliding = expandedNodeBBox.x < draggedRect.x + draggedRect.width && expandedNodeBBox.x + expandedNodeBBox.width > draggedRect.x && expandedNodeBBox.y < draggedRect.y + draggedRect.height && expandedNodeBBox.y + expandedNodeBBox.height > draggedRect.y;
// 如果发生碰撞,根据拖动位置确定插入位置 if (isColliding) { var insertPosition = x > nodeBBox.maxX ? 'right' : x < nodeBBox.maxX && x > nodeBBox.minX ? y > nodeBBox.centerY ? 'bottom' : 'top' : 'left'; // 返回插入位置和碰撞状态 return { insertPos: insertPosition, collide: true }; }
// 如果没有碰撞,返回false return false; };
/**
@returns {Object} 返回一个对象,包含新父节点和目标索引 */ const traversNodes = (item, callback) => { // 初始化新节点和新索引变量 let newNode, newIndex = 0;
// 获取需要查找的节点的ID const id = item.getID();
// 使用G6工具类的树遍历方法,从保存的思维导图树结构中从上至下查找节点 G6.Util.traverseTreeUp(mindMapTree.save(), function(node, parent, index) { // 当找到节点ID匹配的节点时,保存该节点及其索引,并停止继续遍历 if (node.id === id) { newNode = node; newIndex = index; return false; } else { // 如果当前节点不匹配,继续遍历下一个节点 return true; } });
// 返回结果对象,包含找到的节点和其索引位置 return { newParentNode: newNode, targetIndex: newIndex, }; };
const traversRootNodes = e => { var found = false, nodeId = e.getID(); // 遍历树的根节点以判断是否为根节点 G6.Util.traverseTree(mindMapTree.save(), function(node, isRoot) { if (!isRoot || node.id !== nodeId) { found = true; return false; } }); return found; };
const registerBehavior = () => { G6.registerBehavior('dice-mindmap', { getEvents() { return { 'node:click': 'clickNode', 'node:dblclick': 'editNode', 'node:mouseenter': 'hoverNode', 'node:mouseleave': 'hoverNodeOut', }; }, clickNode(evt) { const model = evt.item.get('model'); const name = evt.target.get('action') || ''; const parent = evt.item.get('parent'); const { x, y, images } = model; const image = Array.isArray(images) ? [...images] : []; const point = mindMapTree.getCanvasByPoint(x, y); setNodeContextMenuX(point.x); setNodeContextMenuY(point.y + 40); if (model.id !== currentNode?.get('model')?.id) { setShowDeleteMenu(false); } setCurrentNode(evt); const regex = /previewPic(\d+)/; const match = name.match(regex); const regexDel = /deletePic(\d+)/; const matchDel = name.match(regexDel);
}, editNode(evt) { handleEditNode(evt, true, false); }, hoverNode(evt) { try { mindMapTree.setItemState(evt.item, 'hover', true); } catch (error) { console.log(error); } }, hoverNodeOut(evt) { try { mindMapTree.setItemState(evt.item, 'hover', false); } catch (error) { console.log(error); } }, });
G6.registerBehavior('dice-mindmap-drag', { getEvents() { return { 'node:dragstart': 'handleItemDragStart', 'node:drag': 'handleItemDrag', 'node:dragend': 'handleItemDragEnd', }; },
handleItemDragStart(evt) { if (!isEditMode()) return; const { item, x, y } = evt; const model = item.get('model'); if (model.id === 'RootNode') { return; } minDisNode = null; dragNodeOriPos = { x: model.x, y: model.y }; const { minX, minY, width, height } = item.getBBox(); dragRect = { deltaX: x - minX, deltaY: y - minY, width, height, }; if (!model.collapsed && model.children && model.children.length > 0) { model.collapsed = true; mindMapTree.setItemState(item, 'collapsed', true); mindMapTree.refreshItem(item); }
},
/**
@param {Object} evt - 拖拽事件对象,包含拖拽的相关信息 */ handleItemDrag(evt) { // 获取当前拖拽项的模型信息 const model = evt.item.get('model'); if (model.id === 'RootNode') { return; } // 计算拖拽项的临时位置和中心点坐标 const tempBox = { width: dragRect.width, height: dragRect.height, x: evt.x - dragRect.deltaX, y: evt.y - dragRect.deltaY, centerX: evt.x - dragRect.deltaX + dragRect.width / 2, centerY: evt.y - dragRect.deltaY + dragRect.height / 2, };
// 初始化最近距离节点变量 minDisNode = null;
// 遍历思维导图树,检查拖拽节点与现有节点是否发生碰撞 G6.Util.traverseTreeUp(mindMapTree.save(), function(node) { // 跳过当前拖拽节点和临时节点 if (node.id === model.id || node.id === 'temp') { return true; }
// 获取当前遍历的节点对象 const currentNode = mindMapTree.findById(node.id);
// 检查当前节点与拖拽节点是否发生碰撞 const hascollided = collide(currentNode, tempBox, evt.x, evt.y); if (hascollided) { // 如果发生碰撞,更新最近距离节点及其状态 minDisNode = currentNode; minDisNodeId = node.id; insertPos = hascollided.insertPos; console.log(hascollided, node.title); return false; } });
// 如果找到最近距离节点,更新其子节点或调整节点位置 if (minDisNode) { const minx = minDisNode.getBBox().minX; mindMapTree.findDataById('temp') && mindMapTree.removeChild('temp', false); const tempNode = { id: 'temp', type: 'dice-mind-map-temp', title: '', };
// 根据拖拽位置更新节点或调整节点位置 if (minx <= evt.x) { if (minDisNodeId === lastMinDisNodeId && lastInsertPostion === insertPos) { return; }
} else { if (minDisNodeId === lastMinDisNodeId && lastInsertPostion === insertPos) { return; }
}
// 更新拖拽项的位置 evt.item.updatePosition({ x: dragRect.deltaX, y: dragRect.deltaY, });
// 更新最近距离节点及其插入位置的缓存 lastMinDisNodeId = minDisNodeId; lastInsertPostion = insertPos; } }, handleItemDragEnd(evt) {}, }); };
G6 Version / G6 版本
4.x
Operating System / 操作系统
macOS
Browser / 浏览器
Chrome
Additional context / 补充说明
No response