不爱贞子爱爽子
バキューン

关系图的操作,官网 https://www.relation-graph.com/#/docs/start-vue3

1.安装relation-graph-vue3

参照官网

2.图形显示

<template>
  <div>
    <div style="border: #efefef solid 1px; height: calc(100vh - 100px);width: 100%;">
      <relation-graph ref="graphRef$" :options="options" />
    </div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue'
import RelationGraph from 'relation-graph-vue3'
const graphRef$ = ref<RelationGraph>()
const options = {
  defaultExpandHolderPosition: 'right'
}
onMounted(() => {
  const jsonData = {
    rootId: 'a',
    nodes: [
      { id: 'a', text: 'a', },
      { id: 'b', text: 'b', },
      { id: 'c', text: 'c', },
      { id: 'd', text: 'd', },
      { id: 'e', text: 'e', },
      { id: 'f', text: 'f', },
    ],
    lines: [
      { from: 'a', to: 'b', },
      { from: 'a', to: 'c', },
      { from: 'a', to: 'd', },
      { from: 'a', to: 'e', },
      { from: 'a', to: 'f', },
    ],
  }
  // The node and line in the above data can refer to the options in "Node" and "Link & Line" for configuration.
  // Node: https://www.relation-graph.com/#/docs/node
  // Link & Line: https://www.relation-graph.com/#/docs/link
  graphRef$.value.setJsonData(jsonData)
  // The graphRef$.value.setJsonData(jsonData, callback) method is a convenient method that is equivalent to the following code:
  //  const graphInstance = graphRef$.value.getInstance(); //获取实例
  //  graphInstance.addNodes(jsonData.nodes); //添加节点
  //  graphInstance.addLines(jsonData.lines); // 添加关系
  //  graphInstance.rootNode = graphInstance.getNodeById(jsonData.rootId); 获取跟节点
  //  await graphInstance.doLayout(); // Layout using the layouter set in graphOptions  重绘
  //  await graphInstance.moveToCenter(); // Find the center based on node distribution and center the view 视角居中
  //  await graphInstance.zoomToFit(); // Zoom to fit, so that all nodes can be displayed in the visible area 缩放到合适大小
})
</script>

3.添加节点

 const graphInstance = graphRef.value?.getInstance();
                graphInstance.addNodes([
                    {
                        id: id,
                        text: `${name}${nodes.length + 1}`,
                        color: "#09819C", // dragObj.value == "fx" ? "#09819C" : "#7FAE1B",
                        x: canvasCoordinate.x,
                        y: canvasCoordinate.y,
                        data: {
                            type: dragObj.value,
                            name1: i18n.global.t('mechanism_model.export') + `${nodes1.length + 1}`,
                            dataType: 'float'
                        },
                    },
                    // {
                    //     id: id1,
                    //     text: '输出',
                    //     color: "#EE914D", // dragObj.value == "fx" ? "#09819C" : "#7FAE1B",
                    //     data: {
                    //         type: '输出'
                    //     },
                    // },
                ]);

4.添加关系

const graphInstance = graphRef.value?.getInstance(); 
graphInstance.addLines([
                        {
                            from: id, //起点
                            to: id1 //终点
                        }
                    ])

5.移出节点

const graphInstance = graphRef.value.getInstance();
graphInstance.removeNodeById(currentObject.value.id); //移除

6.解除关系

const graphInstance = graphRef.value?.getInstance();
graphInstance.removeLinkById(currentObject.value.seeks_id);

7.鼠标右键弹窗

 

  <RelationGraph ref="graphRef" :options="graphOptions" :on-node-click="onNodeClick"
                        @contextmenu="onContextmenu">
                        <template #graph-plug>
                            <div v-if="isShowNodeTipsPanel && route.query.type !== 'view'" :style="{
                                left: nodeMenuPanelPosition.x + 'px',
                                top: nodeMenuPanelPosition.y + 'px',
                            }" class="c-right-menu-panel" style="min-width: 240px">
                               删除
                                
                            </div>
                            <!-- <RGEditingConnectController /> -->
                        </template>
    
                    </RelationGraph>


    const onContextmenu = ($event, objectType, object) => {
        // node 右键菜单
        const graphInstance = graphRef.value?.getInstance();
        currentObjectType.value = objectType;
        currentObject.value = object;
        const _base_position = graphInstance?.getBoundingClientRect();
        isShowNodeTipsPanel.value = true;
        nodeMenuPanelPosition.value.x = $event.clientX - _base_position.x + 10;
        nodeMenuPanelPosition.value.y = $event.clientY - _base_position.y + 10;
        const hideContentMenu = () => {
            isShowNodeTipsPanel.value = false;
            document.body.removeEventListener("click", hideContentMenu);
        };
        document.body.addEventListener("click", hideContentMenu);
    };



 

8.碰撞检测 node1和node2 重叠

import {
    RGNodesAnalyticUtils,
} from "relation-graph-vue3";
const { RGNodesAnalytic } = RGNodesAnalyticUtils;
const nodeBox = {
       el: node1.el,
       x: newX,
       y: newY,
};
const shapeA =node1.nodeShape || graphInstance?.options.defaultNodeShape || 0;
const shapeB = node2.nodeShape || graphInstance?.options.defaultNodeShape || 0;
const overlap = RGNodesAnalytic.shapesOverlap(nodeBox, node2, shapeA, shapeB);
            if (overlap) {
                //重叠
            }

 

9.拖拽添加

9.1.拖拽部分就使用正常的拖拽

div :title="name" draggable="true" @dragstart="(e) => onDragStart(e, dataRef)"
                                            @drag="(e) => onDraging(e, dataRef)" :style="{ width: '200px' }" style="
                                    white-space: nowrap;
                                    overflow: hidden;
                                    text-overflow: ellipsis;
                                ">
                                            {{ name }}
                                        </div>

const onDragStart = (e, node) => {
    // 拖拽
    dragObj.value = '';
    // 判断是否在虚拟测点list里面
    if (vPonitList.value.findIndex(point => point.key == node.key) == -1) {
        node.shadowId = selectAsset.value.id;
        dragObj.value = node;
    } else {
        message.error(i18n.global.t('mechanism_model.config_input_error'))
    }
}
const onDraging = (e, node) => {
    // 拖拽ing
    // 验证是否重叠
   if (vPonitList.value.findIndex(point => point.key == node.key) == -1) {
        emits('checkOverlap', e)
    }
}

 

9.2.拖拽完成

 <div class="editor" @drop="onDrop" @dragover.prevent> 
<RelationGraph ref="graphRef" :options="graphOptions" :on-node-click="onNodeClick"
                        @contextmenu="onContextmenu">
                        <template #graph-plug>
                            <div v-if="isShowNodeTipsPanel && route.query.type !== 'view'" :style="{
                                left: nodeMenuPanelPosition.x + 'px',
                                top: nodeMenuPanelPosition.y + 'px',
                            }" class="c-right-menu-panel" style="min-width: 240px">
                               
                                
                            </div>
                            <!-- <RGEditingConnectController /> -->
                        </template>
    
                    </RelationGraph>
</div>

const onDrop = (event) => {
        //获取详情
        newNodePos.value.x = event.x;
        newNodePos.value.y = event.y;
        // 开始添加节点
        _startAddNode();
    }


    const _startAddNode = async () => {
        // name 根据类型产生
        let name = 1111// 拖拽添加节点
        const graphInstance = graphRef.value?.getInstance();
        // 唯一id
        let id = uuidv4();
        // 获取有多少个公式
        let nodes = graphInstance.getNodes().filter(node => node.data?.type == dragObj.value)
        if (graphInstance) {
      //坐标转换 const canvasCoordinate
= graphInstance.getCanvasCoordinateByClientCoordinate({ x: newNodePos.value.x, y: newNodePos.value.y, }); // 输入框和公式不一样 拖动公式默认会带出来一个输出框 let arr = [ { id: id, text: `${name}${nodes.length + 1}`, color: "#7FAE1B", x: canvasCoordinate.x, y: canvasCoordinate.y, data: { type: dragObj.value, }, }, ] graphInstance.addNodes(arr); // 聚焦到这个id // await graphInstance.focusNodeById(id); // 聚焦第一个 } dragObj.value = ""; };

10.节点插槽 显示自己定义的内容

 <RelationGraph ref="graphRef" :options="graphOptions" :on-node-click="onNodeClick"
                        @contextmenu="onContextmenu" @canvas-click="onCanvasClick" :on-node-dragging="onNodeDragging"
                        :on-node-drag-start="onNodeDragStart" :on-node-drag-end="onNodeDragEnd">
                        <template #node="{ node }">
                            <div class="my-node p-2">
                                <div class="flex items-start mt-1">
                                    <img class="me-2" draggable="false" :src="FxWSvg" v-if="node.data?.type == 'fx'">
                                    <img class="me-2" draggable="false" :src="setParamterWSvg"
                                        v-else-if="node.data?.type == 'paramter'">
                                    <img class="me-2" draggable="false" :src="physicsPointWSvg"
                                        v-else-if="node.data?.type == 'point'">
                                    <img class="me-2" draggable="false" :src="exportSvg"
                                        v-else-if="node.data?.type == '输出'">
                                </div>
                                <div style="word-break: break-all;">
                                {{ node["text"] }}
                                </div>
                     <div class="line-create" @click.stop="createLineFromNode" v-if="node.data?.type !== 'fx' && route.query.type != 'view'" :style="{ display: 'none', backgroundColor: '#65DF2A', height: '20px', width: '20px', borderRadius: '50%', position: 'absolute', right: '-10px', bottom: '10px', zIndex: 999, padding: '2px', }"></div> <!-- 描述信息 --> <div class="node-description"> {{ node.data?.description }} </div> </div> </template> </RelationGraph >

 

11.配置信息 详细参考官网

    const graphOptions = {
        debug: false,
        allowSwitchLineShape: true,
        // allowSwitchJunctionPoint: true,
        allowShowDownloadButton: false,
        defaultJunctionPoint: "border",
        defaultNodeBorderWidth: 0,
        defaultLineColor: "#09819C",
        defaultLineShape: 4, // 备选 1 2 4 5 6 
        defaultNodeShape: 1,
        defaultLineTextOffset_x: 2,
        defaultLineTextOffset_y: -3,
        layout: {
            layoutName: "tree",
            from: "left",
            "min_per_width": "80",
            "max_per_width": "300",
            "min_per_height": "160",
            "max_per_height": "180"
        },
    };

12.页面优化

12.1内容太多显示不完 缩放

const graphInstance = graphRef.value?.getInstance();
// 聚焦中心点
await graphInstance.moveToCenter();
// 调整视角 显示所有内容
await graphInstance.zoomToFit();

12.2 聚焦某个节点  比如搜索后定位到

const graphInstance = graphRef.value?.getInstance();
await graphInstance.focusNodeById(id)

12.3 刷新

const graphInstance = graphRef.value?.getInstance();
await graphInstance.refresh()

 显示效果还算不错 可以去试试 部分高级内容需要会员哦

 

posted on 2025-06-13 16:38  不爱贞子爱爽子  阅读(768)  评论(0)    收藏  举报

! !