123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- <template>
- <div class="relation-chart" ref="ref_main">
- <div class="chart" id="container"/>
- </div>
- </template>
- <script setup lang="ts">
- import {getCurrentInstance, onMounted, reactive, ref, watch} from "vue";
- import {Graph} from "@antv/g6";
- const emit = defineEmits(['chartPage'])
- const {proxy} = getCurrentInstance()
- const props = defineProps({
- data: {}
- })
- const state: any = reactive({
- resizeObserver: <any>null,
- })
- const ref_main = ref()
- const setNodes = (data) => {
- data.nodes.forEach(v => {
- v.style = {
- badge: true,
- badges:[{text: String(v.num), placement: 'top-right', offsetX: -10, offsetY: 10}],
- // icon: false,
- iconSrc: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
- }
- })
- }
- const setEdges = (data) => {
- data.edges.forEach(v => {
- v.style = {
- labelText: '关系描述'
- }
- })
- }
- const initChart = () => {
- if (props.data?.nodes?.length > 0) {
- const data = JSON.parse(JSON.stringify(props.data))
- setNodes(data)
- setEdges(data)
- const mainColor = getComputedStyle(document.documentElement).getPropertyValue('--cus-main-color')
- const mainColorHex2 = getComputedStyle(document.documentElement).getPropertyValue('--cus-main-color-hex-2')
- const graph = new Graph({
- container: 'container',
- data,
- // autoResize: true,
- autoFit: 'view',
- behaviors: ['drag-canvas', 'drag-element', 'zoom-canvas', {
- type: 'click-select',
- degree: 1,
- enable: (event) => event.targetType === "node",
- }],
- layout: {
- type: 'radial',
- focusNode: '3',
- linkDistance: 200,
- preventOverlap: true,
- unitRadius: 200,
- maxPreventOverlapIteration: 100,
- strictRadial: false
- },
- node: {
- style: {
- // circle
- size: (v) => v.weight,
- fill: 'transparent',
- lineWidth: 2,
- stroke: mainColor,
- // label
- label: true,
- labelPlacement: 'bottom',
- labelText: (v) => v.name,
- labelFill: '#ffffff',
- labelPadding: [4, 10],
- labelBackground: true,
- labelBackgroundFill: mainColor,
- labelBackgroundRadius: 2,
- labelFontSize: 14,
- labelOffsetY: 6,
- // badge
- badgeFontSize: 12,
- badgePadding: [2, 4, 0, 4],
- badgeBackgroundFill: mainColor,
- halo: false,
- haloLineDash: 0,
- haloLineWidth: 12,
- haloStrokeOpacity: 0.25,
- },
- state: {
- selected: {
- lineWidth: 4,
- stroke: mainColor,
- labelFontSize: 14,
- labelFontWeight: 'normal',
- }
- }
- },
- edge: {
- style: {
- endArrow: true,
- endArrowType: 'triangle',
- endArrowSize: 8,
- stroke: mainColor,
- labelAutoRotate: false,
- labelFill: '#ffffff',
- labelPadding: [2, 4, 0, 4],
- labelBackground: true,
- labelBackgroundFill: mainColor,
- labelBackgroundRadius: 20,
- labelFontSize: 12,
- halo: true,
- haloLineDash: 4,
- haloLineWidth: 2,
- },
- state: {
- selected: {
- labelFontSize: 12,
- labelFontWeight: 'normal'
- }
- }
- },
- } as any);
- graph.render();
- graph.on('node:click', (e) => {
- emit('chartPage', e.target.id)
- })
- state.resizeObserver = new ResizeObserver((entries) => {
- for (const entry of entries) {
- graph && graph?.resize()
- }
- })
- state.resizeObserver.observe(ref_main.value);
- }
- }
- watch(() => props.data, () => {
- initChart()
- })
- onMounted(() => {
- return () => {
- state.resizeObserver?.unobserve(ref_main?.value)
- state.resizeObserver?.disconnect()
- }
- })
- </script>
- <style lang="scss" scoped>
- .relation-chart {
- width: 100%;
- height: 100%;
- background-color: rgba(var(--cus-main-color-rgb), 0.1);
- .chart {
- width: 100%;
- height: 100%;
- }
- }
- </style>
|