feat: 拓扑编辑代码优化
This commit is contained in:
File diff suppressed because it is too large
Load Diff
151
src/views/monitor/topology-build/hooks/useEdge.ts
Normal file
151
src/views/monitor/topology-build/hooks/useEdge.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
import { message, Form } from 'ant-design-vue/lib';
|
||||
import { reactive, watch } from 'vue';
|
||||
import { graphG6 } from './useGraph';
|
||||
|
||||
/**图边内置边类型 */
|
||||
export const edgeTypeOptions = [
|
||||
{
|
||||
value: 'line',
|
||||
label: '直线,连接两个节点的直线',
|
||||
},
|
||||
{
|
||||
value: 'polyline',
|
||||
label: '折线,多段线段构成的折线,连接两个端点',
|
||||
},
|
||||
{
|
||||
value: 'arc',
|
||||
label: '圆弧线,连接两个节点的一段圆弧',
|
||||
},
|
||||
{
|
||||
value: 'quadratic',
|
||||
label: '二阶贝塞尔曲线,只有一个控制点的曲线',
|
||||
},
|
||||
{
|
||||
value: 'cubic',
|
||||
label: '三阶贝塞尔曲线,有两个控制点的曲线',
|
||||
},
|
||||
{
|
||||
value: 'cubic-vertical',
|
||||
label: '垂直方向的三阶贝塞尔曲线',
|
||||
},
|
||||
{
|
||||
value: 'cubic-horizontal',
|
||||
label: '水平方向的三阶贝塞尔曲线',
|
||||
},
|
||||
{
|
||||
value: 'loop',
|
||||
label: '自环',
|
||||
},
|
||||
];
|
||||
|
||||
/**图边标签文本位置 */
|
||||
export const edgePositionOptions = [
|
||||
{
|
||||
value: 'start',
|
||||
label: '开头',
|
||||
},
|
||||
{
|
||||
value: 'middle',
|
||||
label: '中间',
|
||||
},
|
||||
{
|
||||
value: 'end',
|
||||
label: '末尾',
|
||||
},
|
||||
];
|
||||
|
||||
/**边信息状态类型 */
|
||||
type EdgeStateType = {
|
||||
/**图边原始数据 */
|
||||
origin: Record<string, any>;
|
||||
/**图边表单数据 */
|
||||
form: Record<string, any>;
|
||||
};
|
||||
|
||||
/**边信息状态 */
|
||||
export let edgeState: EdgeStateType = reactive({
|
||||
origin: {},
|
||||
form: {
|
||||
id: '',
|
||||
source: '',
|
||||
target: '',
|
||||
type: 'polyline',
|
||||
style: {
|
||||
offset: 20,
|
||||
radius: 2,
|
||||
stroke: '#ffffff',
|
||||
lineWidth: 1,
|
||||
cursor: 'pointer',
|
||||
},
|
||||
label: '',
|
||||
labelCfg: {
|
||||
refX: 0,
|
||||
refY: 0,
|
||||
position: 'middle',
|
||||
autoRotate: false,
|
||||
style: {
|
||||
fill: '#ffffff',
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**图边对话框内表单属性和校验规则 */
|
||||
export const edgeStateForm = Form.useForm(
|
||||
edgeState.form,
|
||||
reactive({
|
||||
id: [{ required: true, message: '边唯一 ID' }],
|
||||
source: [{ required: true, message: '起始点 id' }],
|
||||
target: [{ required: true, message: '结束点 id' }],
|
||||
type: [{ required: true, message: 'line' }],
|
||||
})
|
||||
);
|
||||
|
||||
/**图边编辑监听更新视图 */
|
||||
watch(edgeState.form, edge => {
|
||||
const info = JSON.parse(JSON.stringify(edge));
|
||||
const edgeId = info.id;
|
||||
if (edgeId) {
|
||||
graphG6.value.clearItemStates(edgeId, 'selected');
|
||||
graphG6.value.updateItem(edgeId, info);
|
||||
}
|
||||
});
|
||||
|
||||
/**图边新增或更新 */
|
||||
export function handleOkEdge() {
|
||||
const edge = JSON.parse(JSON.stringify(edgeState.form));
|
||||
if (!edge.id) {
|
||||
message.warn({
|
||||
content: `边元素ID错误`,
|
||||
duration: 2,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// graphG6.value.removeItem(edge.id);
|
||||
// edge.id = `${edge.source}~${Date.now()}~${edge.target}`;
|
||||
// graphG6.value.addItem('edge', edge);
|
||||
const item = graphG6.value.findById(edge.id);
|
||||
if (item) {
|
||||
graphG6.value.updateItem(item, edge);
|
||||
} else {
|
||||
edge.id = `${edge.source}~${Date.now()}~${edge.target}`;
|
||||
graphG6.value.addItem('edge', edge);
|
||||
}
|
||||
edgeStateForm.resetFields();
|
||||
edgeState.origin = {};
|
||||
return true;
|
||||
}
|
||||
|
||||
/**图边取消还原 */
|
||||
export function handleCancelEdge() {
|
||||
const origin = JSON.parse(JSON.stringify(edgeState.origin));
|
||||
if (origin.id) {
|
||||
graphG6.value.updateItem(origin.id, origin);
|
||||
// graphG6.value.removeItem(edgeOrigin.id);
|
||||
// graphG6.value.addItem('edge', edgeOrigin);
|
||||
edgeStateForm.resetFields();
|
||||
edgeState.origin = {};
|
||||
}
|
||||
}
|
||||
422
src/views/monitor/topology-build/hooks/useGraph.ts
Normal file
422
src/views/monitor/topology-build/hooks/useGraph.ts
Normal file
@@ -0,0 +1,422 @@
|
||||
import {
|
||||
Graph,
|
||||
GraphData,
|
||||
ICanvas,
|
||||
IShapeBase,
|
||||
Item,
|
||||
Menu,
|
||||
Tooltip,
|
||||
} from '@antv/g6';
|
||||
import { ref } from 'vue';
|
||||
|
||||
/**图实例对象 */
|
||||
export const graphG6 = ref<any>(null);
|
||||
|
||||
/**图事件变更 */
|
||||
export const graphEvent = ref<{
|
||||
type: string;
|
||||
target: HTMLElement | (IShapeBase & ICanvas);
|
||||
item: Item | null;
|
||||
}>();
|
||||
|
||||
/**图画布右击菜单 */
|
||||
const graphCanvasMenu = new Menu({
|
||||
offsetX: 6,
|
||||
offseY: 10,
|
||||
itemTypes: ['canvas'],
|
||||
getContent(evt) {
|
||||
return `
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 140px;
|
||||
"
|
||||
>
|
||||
<div id="show" style="cursor: pointer; margin-bottom: 2px">
|
||||
1. 显示所有隐藏项
|
||||
</div>
|
||||
</div>`;
|
||||
},
|
||||
handleMenuClick(target, item) {
|
||||
console.log(target, item);
|
||||
const targetId = target.id;
|
||||
switch (targetId) {
|
||||
case 'show':
|
||||
// 显示节点
|
||||
graphG6.value.getNodes().forEach((node: any) => {
|
||||
if (!node.isVisible()) {
|
||||
graphG6.value.showItem(node);
|
||||
graphG6.value.refreshItem(node);
|
||||
}
|
||||
});
|
||||
// 显示边
|
||||
graphG6.value.getEdges().forEach((edge: any) => {
|
||||
if (!edge.isVisible()) {
|
||||
graphG6.value.showItem(edge);
|
||||
graphG6.value.refreshItem(edge);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
/**图节点右击菜单 */
|
||||
const graphNodeMenu = new Menu({
|
||||
offsetX: 6,
|
||||
offseY: 10,
|
||||
itemTypes: ['node'],
|
||||
getContent(evt) {
|
||||
console.log(evt);
|
||||
return `
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 140px;
|
||||
background: #e6f7ff;
|
||||
"
|
||||
>
|
||||
<div id="edit" style="cursor: pointer; margin-bottom: 2px">
|
||||
1. 编辑
|
||||
</div>
|
||||
<div id="hide" style="cursor: pointer; margin-bottom: 2px">
|
||||
2. 隐藏
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
handleMenuClick(target, item) {
|
||||
console.log(target, item);
|
||||
const targetId = target.id;
|
||||
switch (targetId) {
|
||||
case 'edit':
|
||||
graphEvent.value = { type: `nodeMenu-${targetId}`, target, item };
|
||||
break;
|
||||
case 'hide':
|
||||
graphG6.value.hideItem(item);
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
/**图节点展示 */
|
||||
const graphNodeTooltip = new Tooltip({
|
||||
offsetX: 10,
|
||||
offsetY: 20,
|
||||
getContent(e: any) {
|
||||
const outDiv = document.createElement('div');
|
||||
outDiv.style.width = '180px';
|
||||
outDiv.innerHTML = `
|
||||
<h4>自定义tooltip</h4>
|
||||
<ul>
|
||||
<li>Label: ${e.item.getModel().label || e.item.getModel().id}</li>
|
||||
</ul>`;
|
||||
return outDiv;
|
||||
},
|
||||
itemTypes: ['node'],
|
||||
});
|
||||
|
||||
/**图边右击菜单 */
|
||||
const graphEdgeMenu = new Menu({
|
||||
offsetX: 6,
|
||||
offseY: 10,
|
||||
itemTypes: ['edge'],
|
||||
getContent(evt) {
|
||||
console.log(evt);
|
||||
return `
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 140px;
|
||||
background: #e6f7ff;
|
||||
"
|
||||
>
|
||||
<div id="edit" style="cursor: pointer; margin-bottom: 2px">
|
||||
1. 编辑
|
||||
</div>
|
||||
<div id="hide" style="cursor: pointer; margin-bottom: 2px">
|
||||
2. 隐藏
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
handleMenuClick(target, item) {
|
||||
console.log(target, item);
|
||||
const targetId = target.id;
|
||||
switch (targetId) {
|
||||
case 'edit':
|
||||
graphEvent.value = { type: `edgeMenu-${targetId}`, target, item };
|
||||
break;
|
||||
case 'hide':
|
||||
graphG6.value.hideItem(item);
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
/**图边展示 */
|
||||
const graphEdgeTooltip = new Tooltip({
|
||||
offsetX: 10,
|
||||
offsetY: 20,
|
||||
getContent(e: any) {
|
||||
const outDiv = document.createElement('div');
|
||||
outDiv.style.width = '180px';
|
||||
outDiv.innerHTML = `
|
||||
<h4>graphEdgeTooltip</h4>
|
||||
<ul>
|
||||
<li>Label: ${e.item.getModel().label || e.item.getModel().id}</li>
|
||||
</ul>`;
|
||||
return outDiv;
|
||||
},
|
||||
itemTypes: ['edge'],
|
||||
});
|
||||
|
||||
/**图绑定事件 */
|
||||
function fnGraphEvent(graph: Graph) {
|
||||
// 调用 graph.add / graph.addItem 方法之后触发
|
||||
graph.on('afteradditem', evt => {
|
||||
fnSelectSourceTargetOptionsData();
|
||||
});
|
||||
|
||||
// 鼠标进入节点事件
|
||||
graph.on('edge:mouseenter', (ev: any) => {
|
||||
// 获得鼠标当前目标边
|
||||
const edge = ev.item;
|
||||
// 该边的起始点
|
||||
const source = edge.getSource();
|
||||
// 该边的结束点
|
||||
const target = edge.getTarget();
|
||||
// 先将边提前,再将端点提前。这样该边两个端点还是在该边上层,较符合常规。
|
||||
// edge.toFront();
|
||||
// source.toFront();
|
||||
// target.toFront();
|
||||
});
|
||||
|
||||
graph.on('edge:mouseleave', (ev: any) => {
|
||||
// 获得图上所有边实例
|
||||
const edges = graph.getEdges();
|
||||
// 遍历边,将所有边的层级放置在后方,以恢复原样
|
||||
// edges.forEach(edge => {
|
||||
// edge.toBack();
|
||||
// });
|
||||
});
|
||||
|
||||
graph.on('node:mouseenter', evt => {
|
||||
// 获得鼠标当前目标节点
|
||||
const node = evt.item;
|
||||
// 获取该节点的所有相关边
|
||||
const edges = node && graph.getEdges();
|
||||
// 遍历相关边,将所有相关边提前,再将相关边的两个端点提前,以保证相关边的端点在边的上方常规效果
|
||||
// edges.forEach((edge: any) => {
|
||||
// edge.toFront();
|
||||
// edge.getSource().toFront();
|
||||
// edge.getTarget().toFront();
|
||||
// });
|
||||
// graphEvent.value = {
|
||||
// type: 'node:mouseenter',
|
||||
// target: evt.target,
|
||||
// item: evt.item,
|
||||
// };
|
||||
});
|
||||
|
||||
graph.on('node:mouseleave', (ev: any) => {
|
||||
// 获得图上所有边实例
|
||||
const edges = graph.getEdges();
|
||||
// 遍历边,将所有边的层级放置在后方,以恢复原样
|
||||
// edges.forEach(edge => {
|
||||
// edge.toBack();
|
||||
// });
|
||||
});
|
||||
}
|
||||
|
||||
/**图元素选择开始结束点 */
|
||||
export const selectSourceTargetOptions = ref<Record<string, any>[]>([]);
|
||||
|
||||
/**
|
||||
* 图元素选择开始结束点数据获取
|
||||
*/
|
||||
function fnSelectSourceTargetOptionsData() {
|
||||
// 节点
|
||||
graphG6.value.getNodes().forEach((node: any) => {
|
||||
const info = JSON.parse(JSON.stringify(node.getModel()));
|
||||
selectSourceTargetOptions.value.push({
|
||||
value: info.id,
|
||||
label: info.label,
|
||||
info,
|
||||
});
|
||||
});
|
||||
// 框
|
||||
graphG6.value.getCombos().forEach((combo1: any) => {
|
||||
const info = JSON.parse(JSON.stringify(combo1.getModel()));
|
||||
selectSourceTargetOptions.value.push({
|
||||
value: info.id,
|
||||
label: info.label,
|
||||
info,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**图数据渲染 */
|
||||
export function handleRanderGraph(container: HTMLElement, data: GraphData) {
|
||||
if (!container) return;
|
||||
const { clientHeight, clientWidth } = container;
|
||||
|
||||
const graph = new Graph({
|
||||
container: container,
|
||||
width: clientWidth,
|
||||
height: clientHeight,
|
||||
animate: true,
|
||||
fitCenter: true,
|
||||
modes: {
|
||||
// default: [
|
||||
// // 允许拖拽画布、放缩画布、拖拽节点
|
||||
// 'drag-canvas',
|
||||
// 'zoom-canvas',
|
||||
// 'drag-node',
|
||||
// ],
|
||||
default: [
|
||||
{
|
||||
type: 'click-select',
|
||||
selectEdge: true,
|
||||
},
|
||||
'drag-combo',
|
||||
{
|
||||
type: 'drag-node',
|
||||
onlyChangeComboSize: true,
|
||||
},
|
||||
'drag-canvas',
|
||||
'zoom-canvas',
|
||||
'collapse-expand-combo',
|
||||
],
|
||||
edit: [
|
||||
{
|
||||
type: 'click-select',
|
||||
selectEdge: true,
|
||||
},
|
||||
{
|
||||
type: 'drag-node',
|
||||
shouldEnd: (e: any) => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{ type: 'drag-combo' },
|
||||
'drag-canvas',
|
||||
'zoom-canvas',
|
||||
{ type: 'create-edge', key: 'alt' },
|
||||
],
|
||||
},
|
||||
groupByTypes: false,
|
||||
// layout: {
|
||||
// type: 'dagre',
|
||||
// sortByCombo: false,
|
||||
// ranksep: 10,
|
||||
// nodesep: 10,
|
||||
// },
|
||||
// 全局节点 矩形
|
||||
defaultNode: {
|
||||
type: 'rect',
|
||||
size: [80, 40],
|
||||
style: {
|
||||
radius: 8,
|
||||
// fill: '#ffffff',
|
||||
stroke: '#ffffff',
|
||||
lineWidth: 1,
|
||||
cursor: 'pointer',
|
||||
},
|
||||
labelCfg: {
|
||||
position: 'center',
|
||||
offset: 0,
|
||||
style: {
|
||||
fill: '#000000',
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
},
|
||||
},
|
||||
icon: {
|
||||
show: false,
|
||||
img: '/svg/service.svg',
|
||||
width: 25,
|
||||
height: 25,
|
||||
offset: 20, // triangle 特有
|
||||
},
|
||||
direction: 'up', // triangle 三角形的方向
|
||||
},
|
||||
// 全局边 三次贝塞尔曲线
|
||||
defaultEdge: {
|
||||
type: 'polyline',
|
||||
style: {
|
||||
offset: 20, // 拐弯处距离节点最小距离
|
||||
radius: 2, // 拐弯处的圆角弧度,若不设置则为直角
|
||||
stroke: '#ffffff',
|
||||
lineWidth: 1,
|
||||
cursor: 'pointer',
|
||||
},
|
||||
labelCfg: {
|
||||
refX: 0,
|
||||
refY: 0,
|
||||
position: 'middle',
|
||||
autoRotate: false,
|
||||
style: {
|
||||
fill: '#ffffff',
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
},
|
||||
},
|
||||
},
|
||||
// defaultEdge: {
|
||||
// type: 'line',
|
||||
// },
|
||||
// 全局框节点 矩形
|
||||
defaultCombo: {
|
||||
type: 'rect', // Combo 类型
|
||||
size: [40, 40],
|
||||
style: {
|
||||
fillOpacity: 0.1,
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
graphCanvasMenu,
|
||||
graphNodeMenu,
|
||||
graphNodeTooltip,
|
||||
graphEdgeMenu,
|
||||
graphEdgeTooltip,
|
||||
],
|
||||
});
|
||||
graph.data(data);
|
||||
graph.render();
|
||||
|
||||
// 图绑定事件
|
||||
fnGraphEvent(graph);
|
||||
|
||||
graphG6.value = graph;
|
||||
|
||||
// 图元素选择开始结束点数据
|
||||
fnSelectSourceTargetOptionsData();
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
/**图模式选择项 */
|
||||
export const graphModeOptions = [
|
||||
{
|
||||
value: 'default',
|
||||
label: '默认',
|
||||
},
|
||||
{
|
||||
value: 'edit',
|
||||
label: '编辑',
|
||||
},
|
||||
];
|
||||
|
||||
/**图模式选择项 */
|
||||
export const graphMode = ref<string>('default');
|
||||
|
||||
/**图模式改变 default | edit */
|
||||
export function handleChangeMode(value: any) {
|
||||
console.log(value, JSON.parse(JSON.stringify(graphG6.value.save())));
|
||||
graphG6.value.setMode(value);
|
||||
graphMode.value = graphG6.value.getCurrentMode();
|
||||
}
|
||||
294
src/views/monitor/topology-build/hooks/useNode.ts
Normal file
294
src/views/monitor/topology-build/hooks/useNode.ts
Normal file
@@ -0,0 +1,294 @@
|
||||
import { message, Form } from 'ant-design-vue/lib';
|
||||
import { reactive, watch } from 'vue';
|
||||
import { graphG6 } from './useGraph';
|
||||
|
||||
/**图节点内置边类型 */
|
||||
export const nodeTypeOptions = [
|
||||
{
|
||||
value: 'circle',
|
||||
label: '圆形',
|
||||
},
|
||||
{
|
||||
value: 'rect',
|
||||
label: '矩形',
|
||||
},
|
||||
{
|
||||
value: 'ellipse',
|
||||
label: '椭圆',
|
||||
},
|
||||
{
|
||||
value: 'diamond',
|
||||
label: '菱形',
|
||||
},
|
||||
{
|
||||
value: 'triangle',
|
||||
label: '三角形',
|
||||
},
|
||||
{
|
||||
value: 'star',
|
||||
label: '星形',
|
||||
},
|
||||
{
|
||||
value: 'image',
|
||||
label: '图片',
|
||||
},
|
||||
{
|
||||
value: 'donut',
|
||||
label: '面包圈',
|
||||
},
|
||||
];
|
||||
|
||||
/**图节点标签文本位置 */
|
||||
export const nodePositionOptions = [
|
||||
{
|
||||
value: 'top',
|
||||
label: '上',
|
||||
},
|
||||
{
|
||||
value: 'left',
|
||||
label: '左',
|
||||
},
|
||||
{
|
||||
value: 'right',
|
||||
label: '右',
|
||||
},
|
||||
{
|
||||
value: 'bottom',
|
||||
label: '下',
|
||||
},
|
||||
{
|
||||
value: 'center',
|
||||
label: '居中',
|
||||
},
|
||||
];
|
||||
|
||||
/**图节点三角形方向 */
|
||||
export const nodeDirectionOptions = [
|
||||
{ value: 'up', label: '向上' },
|
||||
{ value: 'down', label: '向下' },
|
||||
{ value: 'left', label: '向左' },
|
||||
{ value: 'right', label: '向右' },
|
||||
];
|
||||
|
||||
/**图节点图片裁剪的形状 */
|
||||
export const nodeImageClipCfgOptions = [
|
||||
{ value: 'circle', label: '圆形' },
|
||||
{ value: 'rect', label: '矩形' },
|
||||
{ value: 'ellipse', label: '椭圆' },
|
||||
];
|
||||
|
||||
/**图节点图片来源 */
|
||||
export const nodeImageOptions = [
|
||||
{ value: '/svg/base.svg', label: '基站' },
|
||||
{ value: '/svg/cloud.svg', label: '云' },
|
||||
{ value: '/svg/service.svg', label: '服务器' },
|
||||
{ value: '/svg/service_db.svg', label: '数据服务器' },
|
||||
];
|
||||
|
||||
/**图节点信息状态类型 */
|
||||
type NodeStateType = {
|
||||
/**图节点原始数据 */
|
||||
origin: Record<string, any>;
|
||||
/**图节点表单数据 */
|
||||
form: Record<string, any>;
|
||||
};
|
||||
|
||||
/**图节点信息状态 */
|
||||
export let nodeState: NodeStateType = reactive({
|
||||
origin: {},
|
||||
form: {
|
||||
id: '',
|
||||
x: 0,
|
||||
y: 0,
|
||||
type: 'circle',
|
||||
size: [0],
|
||||
anchorPoints: false,
|
||||
style: {
|
||||
fill: '#ffffff',
|
||||
stroke: '#ffffff',
|
||||
lineWidth: 1,
|
||||
},
|
||||
label: '',
|
||||
labelCfg: {
|
||||
position: 'center',
|
||||
offset: 0,
|
||||
style: {
|
||||
fill: '#000000',
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**图节点对话框内表单属性和校验规则 */
|
||||
export const nodeStateForm = Form.useForm(
|
||||
nodeState.form,
|
||||
reactive({
|
||||
id: [{ required: true, message: '节点唯一 ID' }],
|
||||
type: [{ required: true, message: 'line' }],
|
||||
})
|
||||
);
|
||||
|
||||
/**图节点编辑监听更新视图 */
|
||||
watch(nodeState.form, node => {
|
||||
const info = JSON.parse(JSON.stringify(node));
|
||||
const nodeId = info.id;
|
||||
if (nodeId) {
|
||||
// 图片类型需要移除style属性,避免填充
|
||||
if (info.type === 'image') {
|
||||
Reflect.deleteProperty(info, 'style');
|
||||
}
|
||||
graphG6.value.clearItemStates(nodeId, 'selected');
|
||||
graphG6.value.updateItem(nodeId, info);
|
||||
// 三角和图片的样式变更需要重绘才生效
|
||||
if (info.type === 'triangle' || info.type === 'image') {
|
||||
graphG6.value.read(graphG6.value.save());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**图节点类型输入限制 */
|
||||
export function handleTypeChange(type: any) {
|
||||
// 设置图标属性
|
||||
if (['circle', 'ellipse', 'diamond', 'star', 'donut'].includes(type)) {
|
||||
const origin = nodeState.origin;
|
||||
if (origin.icon) {
|
||||
nodeState.form = Object.assign(nodeState.form, {
|
||||
icon: origin.icon,
|
||||
});
|
||||
} else {
|
||||
nodeState.form = Object.assign(nodeState.form, {
|
||||
icon: {
|
||||
show: false,
|
||||
img: '',
|
||||
width: 25,
|
||||
height: 25,
|
||||
},
|
||||
});
|
||||
}
|
||||
} else if (type === 'triangle') {
|
||||
// 三角
|
||||
const origin = nodeState.origin;
|
||||
if (origin.icon) {
|
||||
nodeState.form = Object.assign(nodeState.form, {
|
||||
direction: origin.direction || 'up', // triangle 三角形的方向
|
||||
icon: Object.assign({ offset: 20 }, origin.icon),
|
||||
});
|
||||
} else {
|
||||
nodeState.form = Object.assign(nodeState.form, {
|
||||
direction: 'up', // triangle 三角形的方向
|
||||
icon: {
|
||||
show: false,
|
||||
img: '/svg/service.svg',
|
||||
width: 25,
|
||||
height: 25,
|
||||
offset: 20, // triangle 特有
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
// 设置图片属性
|
||||
if (type === 'image') {
|
||||
const origin = nodeState.origin;
|
||||
if (origin.img) {
|
||||
nodeState.form = Object.assign(nodeState.form, {
|
||||
img: origin.img,
|
||||
clipCfg: origin.clipCfg,
|
||||
});
|
||||
} else {
|
||||
nodeState.form = Object.assign(nodeState.form, {
|
||||
img: '/svg/service.svg',
|
||||
clipCfg: {
|
||||
show: false,
|
||||
width: 0,
|
||||
height: 0,
|
||||
type: 'circle',
|
||||
},
|
||||
});
|
||||
}
|
||||
Reflect.deleteProperty(nodeState.form, 'style');
|
||||
} else {
|
||||
// 当切换非图片时补充style属性
|
||||
if (!Reflect.has(nodeState.form, 'style')) {
|
||||
nodeState.form = Object.assign(nodeState.form, {
|
||||
style: {
|
||||
fill: '#ffffff',
|
||||
stroke: '#ffffff',
|
||||
lineWidth: 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**图节点大小输入限制 */
|
||||
export function handleSizeChange(value: any) {
|
||||
// 处理格式
|
||||
let intArr: number[] = [];
|
||||
for (const v of value) {
|
||||
const intV = parseInt(v);
|
||||
if (!isNaN(intV)) {
|
||||
intArr.push(intV);
|
||||
}
|
||||
}
|
||||
// 节点类型限制size
|
||||
const nodeType = nodeState.form.type;
|
||||
switch (nodeType) {
|
||||
case 'circle':
|
||||
case 'star':
|
||||
case 'donut':
|
||||
intArr = intArr.slice(0, 1);
|
||||
break;
|
||||
case 'rect':
|
||||
case 'ellipse':
|
||||
case 'diamond':
|
||||
case 'triangle':
|
||||
case 'image':
|
||||
intArr = intArr.slice(0, 2);
|
||||
break;
|
||||
}
|
||||
nodeState.form.size = intArr;
|
||||
}
|
||||
|
||||
/**图节点新增或更新 */
|
||||
export function handleOkNode() {
|
||||
const node = JSON.parse(JSON.stringify(nodeState.form));
|
||||
if (!node.id) {
|
||||
message.warn({
|
||||
content: `节点元素ID错误`,
|
||||
duration: 2,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// graphG6.value.removeItem(node.id);
|
||||
// graphG6.value.addItem('node', node);
|
||||
const item = graphG6.value.findById(node.id);
|
||||
if (item) {
|
||||
graphG6.value.updateItem(item, node);
|
||||
} else {
|
||||
graphG6.value.addItem('node', node);
|
||||
}
|
||||
// 三角和图片的样式变更需要重绘才生效
|
||||
if (node.type === 'triangle' || node.type === 'image') {
|
||||
graphG6.value.read(graphG6.value.save());
|
||||
}
|
||||
nodeStateForm.resetFields();
|
||||
nodeState.origin = {};
|
||||
return true;
|
||||
}
|
||||
|
||||
/**图节点取消还原 */
|
||||
export function handleCancelNode() {
|
||||
const origin = JSON.parse(JSON.stringify(nodeState.origin));
|
||||
if (origin.id) {
|
||||
graphG6.value.updateItem(origin.id, origin);
|
||||
// 三角和图片的样式变更需要重绘才生效
|
||||
if (origin.type === 'triangle' || origin.type === 'image') {
|
||||
graphG6.value.read(graphG6.value.save());
|
||||
}
|
||||
console.log(JSON.parse(JSON.stringify(nodeState.form)));
|
||||
nodeStateForm.resetFields();
|
||||
nodeState.origin = {};
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user