| | |
| | | <template> |
| | | <div v-loading="firstLoading" class="h-full w-full bg-white relative"> |
| | | <div class="h-full w-full" ref="graphRef"></div> |
| | | <div v-loading="firstLoading" class="h-full w-full bg-white relative flex flex-col"> |
| | | <!-- <div class="toolbar flex-0 border-x-0 border-b border-t-0 border-gray-200 border-solid flex-items-center"> |
| | | <span> |
| | | æ ¼å¼ |
| | | </span> |
| | | </div> --> |
| | | <div class="graph flex-auto"> |
| | | <div class="h-full" ref="graphRef"></div> |
| | | |
| | | <div |
| | | class="absolute left-4 top-4 z-10 w-16 divide-y-[1.5px] divide-solid divide-gray-100 rounded-lg" |
| | |
| | | <el-input v-model="searchValue" @input="debounceSearch" placeholder="è¾å
¥æ¥æ¾å
容" v-elInputFocus></el-input> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="absolute right-2 top-4 py-7 px-5 rounded-lg w-96" style="box-shadow: 0 0 15px #dbdee6" v-if="layoutIsShow"> |
| | | <span |
| | | class="absolute ywifont ywicon-guanbi right-4 top-4 cursor-pointer hover:bg-gray-200 active:bg-gray-300" |
| | | @click="closeLayout" |
| | | ></span> |
| | | <div class="flex-column"> |
| | | <span class="mb-5">å¸å±</span> |
| | | |
| | | <el-select v-model="activeLayout" @change="layoutChange"> |
| | | <el-option |
| | | v-for="item in Object.keys(customLayoutMap)" |
| | | :key="item" |
| | | :value="parseInt(item)" |
| | | :label="customLayoutMap[item]" |
| | | ></el-option> |
| | | </el-select> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import { Graph, GraphOptions, treeToGraphData } from '@antv/g6'; |
| | | import { defaultsDeep } from 'lodash'; |
| | | import { onMounted, ref } from 'vue'; |
| | | import { CustomLayout, OrgTreeItem, customLayoutMap, getLayoutType } from './types'; |
| | | import { getMetricAgentListByPost, getMetricNameListByPost } from '/@/api/metrics'; |
| | | import router from '/@/router'; |
| | | import { DeepPartial } from '/@/utils/types'; |
| | | import { deepClone } from '/@/utils/other'; |
| | | const graphRef = ref<HTMLDivElement>(null); |
| | | |
| | | let graph: Graph; |
| | | const firstLoading = ref(false); |
| | | |
| | | const agentId = router.currentRoute.value.query.id as string; |
| | | type OrgTreeItem = { |
| | | treeId: string; |
| | | logicId: string; |
| | | model: any; |
| | | type: 'agent' | 'metrics' | 'dimension'; |
| | | label: string; |
| | | level: number; |
| | | children?: OrgTreeItem[]; |
| | | }; |
| | | |
| | | const convertOrgTreeToTreeNode = (orgTreeData: OrgTreeItem) => { |
| | | const treeData = { |
| | | id: orgTreeData.treeId, |
| | |
| | | }; |
| | | return treeData; |
| | | }; |
| | | const enum CustomLayout { |
| | | /** @description ç´§åæ å¸å± n <= 30*/ |
| | | NormalTree, |
| | | /** @description åç´ç´§åæ ï¼æ ¹èç¹å¨ä¸é´ 30 < n <= 50*/ |
| | | Vertical, |
| | | /** @description è¾å°ç´§åæ ï¼> 50 */ |
| | | Radial, |
| | | } |
| | | |
| | | const getLayoutType = (maxLeafLen: number) => { |
| | | if (maxLeafLen > 50) { |
| | | return CustomLayout.Radial; |
| | | } else if (30 < maxLeafLen) { |
| | | return CustomLayout.Vertical; |
| | | } else { |
| | | return CustomLayout.NormalTree; |
| | | } |
| | | }; |
| | | const getLayoutOption = (layoutType: CustomLayout) => { |
| | | let option: DeepPartial<GraphOptions> = {}; |
| | | switch (layoutType) { |
| | | case CustomLayout.Radial: |
| | | option = { |
| | | autoFit: 'view', |
| | | // autoFit: 'view', |
| | | edge: { |
| | | type: 'cubic-radial', |
| | | }, |
| | |
| | | } |
| | | return option; |
| | | }; |
| | | |
| | | const graphRender = async() => { |
| | | await graph.render(); |
| | | if (activeLayout.value === CustomLayout.Radial) { |
| | | selfAdapt(); |
| | | } |
| | | }; |
| | | const rebuildGraph = (extraOption: DeepPartial<GraphOptions>) => { |
| | | const finalOptions = defaultsDeep(extraOption, commonOption); |
| | | graph.setOptions(finalOptions); |
| | | graphRender(); |
| | | }; |
| | | |
| | | let commonOption: GraphOptions; |
| | | const initGraph = async (orgTreeData: OrgTreeItem, layoutType: CustomLayout) => { |
| | | const treeNodeData = convertOrgTreeToTreeNode(orgTreeData); |
| | | |
| | | const commonOption: GraphOptions = { |
| | | commonOption = { |
| | | container: graphRef.value, |
| | | data: treeToGraphData(treeNodeData), |
| | | node: { |
| | |
| | | |
| | | const finalOption: GraphOptions = defaultsDeep(extraOption, commonOption); |
| | | graph = new Graph(finalOption); |
| | | window.graph = graph; |
| | | graph.render(); |
| | | graphRender(); |
| | | }; |
| | | |
| | | const getLeaf = (item) => { |
| | |
| | | |
| | | //#region ====================== å·¥å
·æ ====================== |
| | | const enum ToolBarType { |
| | | /** @description å¸å± */ |
| | | Layout, |
| | | /** @description æç´¢ */ |
| | | Search, |
| | | /** @description æ¾å¤§ */ |
| | | ZoomIn, |
| | | /** @description ç¼©å° */ |
| | | ZoomOut, |
| | | /** @description èªéåº */ |
| | | Reset, |
| | | } |
| | | type ToolBarItem = { |
| | |
| | | type: ToolBarType; |
| | | }; |
| | | const toolBarFunList: ToolBarItem[] = [ |
| | | // { |
| | | // icon: 'sousuo', |
| | | // label: 'æç´¢', |
| | | // type: ToolBarType.Search, |
| | | // }, |
| | | { |
| | | icon: 'sousuo', |
| | | label: 'æç´¢', |
| | | type: ToolBarType.Search, |
| | | icon: 'buju', |
| | | label: 'å¸å±', |
| | | type: ToolBarType.Layout, |
| | | }, |
| | | { |
| | | icon: 'fangda', |
| | |
| | | const ZOOM_OFFSET = 0.15; |
| | | const toolBarItemClick = (item: ToolBarItem) => { |
| | | switch (item.type) { |
| | | case ToolBarType.Layout: |
| | | layoutIsShow.value = true; |
| | | break; |
| | | case ToolBarType.Search: |
| | | searchIsShow.value = true; |
| | | break; |
| | |
| | | searchIsShow.value = false; |
| | | }; |
| | | //#endregion |
| | | |
| | | //#region ====================== å¸å± ====================== |
| | | const layoutIsShow = ref(false); |
| | | const closeLayout = () => { |
| | | layoutIsShow.value = false; |
| | | }; |
| | | const activeLayout = ref<CustomLayout>(); |
| | | const layoutChange = (layoutType: CustomLayout) => { |
| | | const extraOption = getLayoutOption(layoutType); |
| | | rebuildGraph(extraOption); |
| | | }; |
| | | //#endregion |
| | | onMounted(async () => { |
| | | if (!agentId) return; |
| | | firstLoading.value = true; |
| | |
| | | }); |
| | | setTimeout(() => { |
| | | const layoutType = getLayoutType(maxLevelNodeCount); |
| | | activeLayout.value = layoutType; |
| | | initGraph(orgTreeData as OrgTreeItem, layoutType); |
| | | |
| | | // initEvent(); |