hookehuyr

fix

/*
* @Date: 2025-03-10 13:15:30
* @Date: 2025-03-13 18:34:16
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-03-13 16:20:00
* @LastEditTime: 2025-03-16 00:21:53
* @FilePath: /logic-flow2/src/router/index.js
* @Description: 文件描述
*/
......@@ -120,6 +120,11 @@ const router = createRouter({
name: 'dynamic-group',
component: () => import('../views/dynamic-group/index.vue')
},
{
path: '/api-graphModel',
name: 'api-graphModel',
component: () => import('../views/api/graphModel.vue')
},
]
})
......
/*
* @Date: 2025-03-13 16:11:47
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-03-13 17:09:32
* @LastEditTime: 2025-03-16 00:39:21
* @FilePath: /logic-flow2/src/views/adv-menu/customNode.js
* @Description: 文件描述
*/
......@@ -13,6 +13,15 @@ class CustomModel extends RectNodeModel {
const {
properties: { isDisabledNode },
} = this;
// 设置节点是否可以被连接
this.sourceRules.push({
message: "禁用节点不能作为连接源",
validate: () => !isDisabledNode
});
this.targetRules.push({
message: "禁用节点不能作为连接目标",
validate: () => !isDisabledNode
});
if (!isDisabledNode) {
// 单独为非禁用的元素设置菜单。
this.menu = [
......@@ -46,8 +55,15 @@ class CustomModel extends RectNodeModel {
// 添加 getNodeStyle 方法
getNodeStyle() {
const style = super.getNodeStyle();
style.stroke = "#1E90FF";
style.fill = "#F0F8FF";
const { isDisabledNode } = this.properties;
if (isDisabledNode) {
style.stroke = "#999999";
style.fill = "#f0f0f0";
style.strokeDasharray = "3 3";
} else {
style.stroke = "#1E90FF";
style.fill = "#F0F8FF";
}
return style;
}
}
......
<!--
* @Date: 2025-03-10 16:52:35
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-03-13 16:51:49
* @LastEditTime: 2025-03-16 00:45:35
* @FilePath: /logic-flow2/src/views/adv-menu/index.vue
* @Description: 拖拽面板
-->
......@@ -48,7 +48,8 @@ onMounted(() => {
nodes: [
{ id: "node1", type: "rect", x: 200, y: 100 },
{ id: "node2", type: "circle", x: 400, y: 100 },
{ id: "node3", type: "custom-node", x: 600, y: 100 },
{ id: "node3", type: "custom-node", x: 600, y: 100, properties: { isDisabledNode: true } },
{ id: "node4", type: "custom-node", x: 600, y: 300, properties: { isDisabledNode: false } },
],
edges: [{ id: "edge1", sourceNodeId: "node1", targetNodeId: "node2" }],
});
......
import { RectNode, RectNodeModel } from "@logicflow/core";
class CustomNodeModel extends RectNodeModel {
// 重写获取文本位置的方法
getTextStyle() {
const style = super.getTextStyle();
style.textWidth = 200; // 设置更大的文本宽度
return style;
}
}
class CustomNode extends RectNode {
// 扩大文本点击区域
getTextBBox() {
const { model } = this.props;
const { x, y, width, height } = model;
return {
x: x - width / 2,
y: y - height / 2,
width: width,
height: height,
};
}
}
export default {
type: "custom-rect",
view: CustomNode,
model: CustomNodeModel,
};
<template>
<div class="container">
<div ref="container" class="flow-container"></div>
</div>
</template>
<script setup>
import LogicFlow from "@logicflow/core";
import { MiniMap, Control } from "@logicflow/extension";
import CustomNode from './customNode';
const container = ref(null);
let lf = null;
onMounted(() => {
nextTick(() => {
lf = new LogicFlow({
container: container.value,
grid: true,
plugins: [MiniMap, Control],
width: container.value.offsetWidth,
height: container.value.offsetHeight
});
// 注册自定义节点
lf.register(CustomNode);
// 监听节点点击事件,点击时进入编辑模式
lf.on("node:click", ({ data }) => {
lf.graphModel.editText(data.id);
});
// 监听文本编辑完成事件
lf.on("text:update", ({ data }) => {
console.log("文本更新为:", data.text);
});
// 渲染初始数据
lf.render({
nodes: [
{
id: "node1",
type: "rect",
x: 100,
y: 100,
text: "点击编辑文本"
},
{
id: "node2",
type: "custom-rect", // 使用自定义节点类型
x: 200,
y: 200,
text: "点击编辑文本"
}
]
});
});
});
// 判断节点是否可连接
const checkNodeConnectable = (targetNode, sourceNode) => {
return targetNode.type === 'rect';
}
</script>
<style scoped>
.container {
width: 100vw;
height: 100vh;
}
.flow-container {
width: 100%;
height: 100%;
min-height: 500px;
}
</style>
<!--
* @Date: 2025-03-10 16:52:35
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-03-14 21:42:06
* @LastEditTime: 2025-03-15 19:24:15
* @FilePath: /logic-flow2/src/views/control.vue
* @Description: 拖拽面板
-->
......@@ -18,107 +18,72 @@ const container = ref(null);
let lf = null;
onMounted(() => {
lf = new LogicFlow({
container: container.value,
grid: true,
plugins: [MiniMap, Control],
});
lf.extension.control.addItem({
key: "mini-map",
iconClass: "custom-minimap",
title: "",
text: "导航",
onMouseEnter: (lf, ev) => {
const position = lf.getPointByClient(ev.x, ev.y);
lf.extension.miniMap.show(
position.domOverlayPosition.x - 120,
position.domOverlayPosition.y + 35
);
},
onClick: (lf, ev) => {
const position = lf.getPointByClient(ev.x, ev.y);
lf.extension.miniMap.show(
position.domOverlayPosition.x - 120,
position.domOverlayPosition.y + 35
);
},
});
// 添加克隆节点功能
lf.extension.control.addItem({
key: "clone-node",
iconClass: "custom-clone",
title: "克隆节点",
text: "克隆",
onClick: (lf, ev) => {
const nodes = lf.getSelectElements().nodes;
if (nodes.length) {
nodes.forEach((node) => {
const { x, y, type, properties } = node;
// 在原节点右侧50px处创建新节点
lf.addNode({
type,
x: x + 50,
y,
properties,
});
});
}
console.warn("克隆节点", lf.getGraphData());
},
});
nextTick(() => { // 使用 nextTick 确保 DOM 已挂载
lf = new LogicFlow({
container: container.value,
grid: true,
plugins: [MiniMap, Control],
});
// 监听锚点拖拽连线成功事件
lf.on("anchor:drop", ({ data, e }) => {
console.log("手动创建连线成功:", {
edgeId: data.id,
sourceNode: data.sourceNodeId,
targetNode: data.targetNodeId,
edgeType: data.type
});
});
// 添加修改节点ID功能
lf.extension.control.addItem({
key: "change-node-id",
iconClass: "custom-edit",
title: "修改节点ID",
text: "改ID",
onClick: (lf, ev) => {
const nodes = lf.getSelectElements().nodes;
if (nodes.length === 1) {
const node = nodes[0];
const newId = `node_${Date.now()}`; // 生成新ID
lf.changeNodeId(node.id, newId);
} else {
alert('请选择一个节点');
}
},
});
// 监听所有连线创建事件(包括手动和自动)
lf.on("edge:add", ({ data, e }) => {
console.log("连线创建事件:", {
edgeId: data.id,
sourceNode: data.sourceNodeId,
targetNode: data.targetNodeId,
edgeType: data.type,
isManual: e ? true : false, // render 时创建的边,e 为 undefined
createType: e ? '手动创建' : 'render创建'
});
console.log("监听到连线创建:", data);
});
// 添加获取节点信息功能
lf.extension.control.addItem({
key: "get-node-info",
iconClass: "custom-info",
title: "获取节点信息",
text: "节点信息",
onClick: (lf, ev) => {
const nodes = lf.getSelectElements().nodes;
if (nodes.length === 1) {
const node = nodes[0];
// 获取节点 model
const nodeModel = lf.getNodeModelById(node.id);
// 获取节点数据
const nodeData = lf.getNodeDataById(node.id);
// graphModel 的事件监听 - 更底层,返回原始数据
const { eventCenter } = lf.graphModel;
eventCenter.on("node:click", (args) => {
console.log("graphModel node:click", {
position: args.position, // 原始坐标
data: args.data, // 原始节点数据
e: args.e // 原始事件对象
});
});
console.log('节点Model:', nodeModel);
console.log('节点Data:', nodeData);
} else {
alert('请选择一个节点');
}
},
// LogicFlow 实例的事件监听 - 更上层,返回处理后的数据
lf.on("node:click", ({ data, e }) => {
console.log("lf node:click", {
id: data.id, // 节点ID
type: data.type, // 节点类型
properties: data.properties, // 节点属性
x: data.x, // 处理后的坐标
y: data.y
});
});
lf.extension.control.removeItem("mini-map");
lf.render({
nodes: [
{ id: "node1", type: "rect", x: 200, y: 100 },
{ id: "node2", type: "circle", x: 400, y: 100 },
],
// edges: [{ id: "edge1", sourceNodeId: "node1", targetNodeId: "node2", type: "polyline" }],
});
lf.render({
nodes: [
{ id: "node1", type: "rect", x: 200, y: 100 },
{ id: "node2", type: "circle", x: 400, y: 100 },
],
edges: [{ id: "edge1", sourceNodeId: "node1", targetNodeId: "node2" }],
// 然后手动添加边,这样会触发 edge:add 事件
lf.addEdge({
id: "edge2",
sourceNodeId: "node1",
targetNodeId: "node2",
type: "polyline"
});
});
});
</script>
......@@ -135,5 +100,6 @@ onMounted(() => {
flex: 1;
width: 100%;
height: 100%;
min-height: 500px; /* 可添加最小高度作为保底 */
}
</style>
......
<!--
* @Date: 2025-03-10 14:37:31
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-03-14 13:53:06
* @LastEditTime: 2025-03-16 00:22:53
* @FilePath: /logic-flow2/src/views/home.vue
* @Description: 文件描述
-->
......@@ -28,6 +28,7 @@
<el-button type="primary" @click="goTo('selection-select')">selection-select</el-button>
<el-button type="primary" @click="goTo('snapshot')">snapshot</el-button>
<el-button type="primary" @click="goTo('dynamic-group')">dynamic-group</el-button>
<el-button type="primary" @click="goTo('api-graphModel')">api-graphModel</el-button>
</template>
<script setup>
......