fix: 拓扑图基础

This commit is contained in:
TsMask
2023-12-07 20:15:18 +08:00
parent e92004a69a
commit 3fa2cffc82
2 changed files with 581 additions and 0 deletions

View File

@@ -0,0 +1,513 @@
<template>
<div>
<div ref="g6Dom" :style="{ height: height, width: width }"></div>
<button @click="actions['Enable/Disable Node States'].Breathing()">
Breathing()
</button>
<button @click="actions['Enable/Disable Node States'].Scaling()">
Scaling()
</button>
<button @click="actions['Enable/Disable Edge States'].Growing()">
Growing()
</button>
<button @click="actions['Enable/Disable Edge States'].Running()">
Running()
</button>
</div>
</template>
<script lang="ts" setup>
import { nextTick, watch, onMounted, onBeforeUnmount, ref } from 'vue';
import { Graph, extend, Extensions } from '@antv/g6';
const props = defineProps({
/**
* 图表主题
*
* 'dark' | 'light'
*/
theme: {
type: String,
default: 'light', // 'dark' | 'light'
},
/**宽度默认100% */
width: {
type: String,
default: '100%',
},
/**高度 */
height: {
type: String,
default: '500px',
},
});
const g6Dom = ref<HTMLElement | undefined>(undefined);
const ExtGraph = extend(Graph, {
// layouts: {
// dagre: Extensions.DagreLayout,
// },
edges: {
'polyline-edge': Extensions.PolylineEdge,
'custom-edge': Extensions.CubicEdge,
},
});
const data = {
nodes: [
{
id: '0',
data: {
label: 'A0',
x: 110,
y: 110,
},
},
// B
{
id: '1',
data: {
label: 'B1',
parentId: 'B',
x: 110,
y: 350,
},
},
{
id: '2',
data: {
label: 'B2',
parentId: 'B',
x: 220,
y: 350,
},
},
{
id: '3',
data: {
label: 'B3',
parentId: 'A',
x: 360,
y: 350,
},
},
// C
{
id: '4',
data: {
label: 'C1',
parentId: 'C',
x: 360,
y: 150,
},
},
{
id: '5',
data: {
label: 'C2',
parentId: 'C',
x: 460,
y: 150,
},
},
],
edges: [
{
id: 'edge-102',
source: '0',
target: '1',
data: {
type: 'custom-edge',
animates: {
update: [
{
// 在 selected 和 active 状态变化导致的 haloShape opacity 变化时,使 opacity 带动画地更新
fields: ['opacity'],
shapeId: 'haloShape',
states: ['selected', 'active'],
duration: 500,
},
],
},
},
},
{
id: 'edge-161',
source: '0',
target: '2',
data: {},
},
{
id: 'edge-253',
source: '0',
target: 'A',
data: {
keyShape: {
endArrow: true,
},
labelShape: {
text: 'asdf-arrow',
},
},
},
{
id: 'edge-237',
source: '1',
target: '4',
data: {
type: 'polyline-edge',
keyShape: {
endArrow: true,
routeCfg: {
/**
* 目前支持正交路由 'orth' 和地铁路由 'er'
*/
// name: 'er',
/**
* 是否开启自动避障,默认为 false
* Whether to enable automatic obstacle avoidance, default is false
*/
enableObstacleAvoidance: true,
},
/**
* 拐弯处的圆角弧度,默认为直角,值为 0
* The radius of the corner rounding, defaults to a right angle
*/
// radius: 20,
/**
* 拐弯处距离节点最小距离, 默认为 2
* Minimum distance from the node at the corner, default is 5.
*/
// offset: 0,
/**
* 控制点数组,不指定时根据 A* 算法自动生成折线。若指定了,则按照 controlPoints 指定的位置进行弯折
* An array of control points that, when not specified, automatically generates the bends according to the A* algorithm. If specified, bends are made at the position specified by controlPoints.
*/
// controlPoints: [],
},
},
},
{
id: 'edge-133',
source: '2',
target: '4',
data: {
type: 'polyline-edge',
keyShape: {
/**
* 拐弯处的圆角弧度,默认为直角
*/
radius: 20,
/**
* 拐弯处距离节点最小距离, 默认为 5
*/
// offset: 0,
/**
* 控制点数组,不指定时根据 A* 算法自动生成折线。若指定了,则按照 controlPoints 指定的位置进行弯折
*/
controlPoints: [
{ x: 220, y: 220 },
{ x: 300, y: 130 },
],
},
},
},
{
id: 'edge-320',
source: '2',
target: '5',
data: {
keyShape: {
endArrow: true,
},
labelShape: {
text: 'edge-arrow',
},
},
},
{
id: 'edge-355',
source: '3',
target: '4',
data: {
keyShape: {
endArrow: true,
},
labelShape: {
text: 'asdf-arrow',
},
},
},
],
combos: [
{
id: 'A',
data: {
text: 'combo A',
},
},
{
id: 'B',
data: {
label: 'combo B',
},
},
{
id: 'C',
data: {
label: 'combo C',
},
},
],
};
let graph: any = null;
/**初始化渲染图表 */
function initChart() {
if (!g6Dom.value) return;
graph = new ExtGraph({
container: g6Dom.value,
height: 500,
plugins: [
{
// lod-controller will be automatically assigned to graph with `disableLod: false` to graph if it is not configured as following
type: 'lod-controller',
disableLod: true,
},
],
modes: {
default: [
{
type: 'drag-node',
enableTransient: false,
updateComboStructure: false,
},
{
type: 'click-select',
itemTypes: ['node', 'edge', 'combo'],
},
{
type: 'drag-combo',
enableTransient: true,
updateComboStructure: true,
},
// 'drag-combo',
'drag-canvas',
// 'click-select',
'zoom-canvas',
],
},
theme: {
type: 'spec',
base: 'light',
specification: {
node: {
dataTypeField: 'parentId',
},
},
},
node: model => {
const { id, data } = model;
return {
id,
data: {
...data,
type: 'rect-node',
keyShape: {
width: 60,
height: 30,
radius: 8,
},
labelShape: {
position: 'center',
text: data.label,
},
animates: {
update: [
{
fields: ['opacity'],
shapeId: 'haloShape',
states: ['breathing'],
iterations: Infinity,
direction: 'alternate',
duration: 500,
},
{
fields: ['lineWidth'],
shapeId: 'keyShape',
states: ['breathing'],
iterations: Infinity,
direction: 'alternate',
duration: 500,
},
{
fields: ['height'],
shapeId: 'keyShape',
states: ['scaling'],
iterations: Infinity,
direction: 'alternate',
duration: 500,
},
],
},
},
};
},
edge: {
type: 'custom-edge',
animates: {
update: [
{
fields: ['lineDash'],
shapeId: 'keyShape',
states: ['growing', 'running'],
iterations: Infinity,
duration: 2000,
},
{
fields: ['offsetDistance'],
shapeId: 'buShape',
states: ['circleRunning'],
iterations: Infinity,
duration: 2000,
},
],
},
},
combo: model => {
const { id, data } = model;
return {
id,
data: {
...data,
type: 'rect-combo',
keyShape: {
opacity: 0.8,
padding: [20, 20, 20, 20],
radius: 8,
},
labelShape: {
text: data.label,
offsetY: 8,
},
labelBackgroundShape: {},
animates: {
update: [
{
fields: ['width', 'height', 'x', 'y'],
shapeId: 'keyShape',
},
],
},
},
};
},
nodeState: {
breathing: {
haloShape: {
opacity: 0.25,
lineWidth: 20,
visible: true,
},
keyShape: {
stroke: '#000',
lineWidth: 4,
},
},
scaling: {
keyShape: {
r: 24,
width: 48,
height: 48,
},
},
},
edgeState: {
growing: {
keyShape: {
lineWidth: 2,
lineDash: ['100%', 0],
},
},
running: {
keyShape: {
lineWidth: 2,
lineDash: [2, 2],
// TODO: lineDashOffset
},
},
},
data,
});
}
const actions = {
'Enable/Disable Node States': {
Breathing: () => {
graph.getAllNodesData().forEach(node => {
if (graph.getItemState(node.id, 'breathing')) {
graph.setItemState(node.id, 'breathing', false);
} else {
graph.setItemState(node.id, 'scaling', false);
graph.setItemState(node.id, 'breathing', true);
}
});
},
Scaling: () => {
graph.getAllNodesData().forEach(node => {
if (graph.getItemState(node.id, 'scaling')) {
graph.setItemState(node.id, 'scaling', false);
} else {
graph.setItemState(node.id, 'breathing', false);
graph.setItemState(node.id, 'scaling', true);
}
});
},
},
'Enable/Disable Edge States': {
Growing: () => {
graph.getAllEdgesData().forEach(edge => {
if (graph.getItemState(edge.id, 'growing')) {
graph.setItemState(edge.id, 'growing', false);
} else {
graph.setItemState(edge.id, 'running', false);
graph.setItemState(edge.id, 'growing', true);
}
});
},
Running: () => {
graph.getAllEdgesData().forEach(edge => {
if (graph.getItemState(edge.id, 'running')) {
graph.setItemState(edge.id, 'running', false);
} else {
graph.setItemState(edge.id, 'growing', false);
graph.setItemState(edge.id, 'running', true);
}
});
},
},
};
watch(
() => props.option,
val => {
// if (val) {
// nextTick(() => {
// initChart();
// });
// }
}
);
onMounted(() => {
nextTick(() => {
initChart();
});
});
onBeforeUnmount(() => {});
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,68 @@
<script setup lang="ts">
import { reactive, onMounted } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import ChartGraphG6 from '@/components/ChartGraphG6/index.vue';
import useI18n from '@/hooks/useI18n';
const { t } = useI18n();
/**查询全部网元数据列表 */
function fnGetList() {}
onMounted(() => {});
</script>
<template>
<PageContainer>
<a-card
:bordered="false"
:body-style="{ marginBottom: '24px', paddingBottom: 0 }"
>
<!-- 表格搜索栏 -->
<a-form name="queryParams" layout="horizontal">
<a-row :gutter="16">
<a-col :lg="10" :md="10" :xs="24">
<a-form-item
:label="t('views.monitor.monitor.filter')"
name="neTypeSelect"
>
ssdf
</a-form-item>
</a-col>
<a-col :lg="6" :md="12" :xs="24">
<a-form-item>
<a-space :size="8">
<a-button type="primary" @click.prevent="fnGetList()">
<template #icon><SearchOutlined /></template>
{{ t('common.search') }}
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-row :gutter="16">
<a-col :lg="24" :md="24" :xs="24">
<a-card :bordered="false" :body-style="{ marginBottom: '24px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>asdf</template>
<!-- 插槽-卡片右侧 -->
<template #extra> adf </template>
<div class="chart">
<ChartGraphG6 :option="{}"></ChartGraphG6>
</div>
</a-card>
</a-col>
</a-row>
</PageContainer>
</template>
<style lang="less" scoped>
.chart {
width: 100%;
height: 500px;
background-color: rgb(238, 237, 237);
}
</style>