likes
comments
collection
share

ant-G6 使用vue组件自定义节点

作者站长头像
站长
· 阅读数 5

ant-G6 使用vue组件自定义节点

前言

依稀记得很久之前,用 ant-G6 开发了公司业务系统中的血缘视图。但是 ant-G6 却不能使用 当前流行的框架来实现自定义节点,这很大程度上限制了开发的可行性。最初我使用 提供的 rect,circle,image 等来实现业务效果。后来对 Vue 的了解上,发现并实践出了以下方法。

核心解决方案

本质上是使用 vue 的 render 渲染函数 和 h 函数,将vue的组件渲染为html,最终截取出来作为 G6 的节点使用。

自定义节点组件

// Node.vue

<template>
  <div
    :class="[$style['node'], isCenter ? $style['is-center'] : '']"
    role="button"
  >
    <ElIcon :class="$style['icon']" class="yg-icon mx-4">
      <component :is="icons['ai-search']"></component>
    </ElIcon>
    <span :class="$style['title']">{{ title || '' }}</span>
  </div>
</template>

<script lang="ts" setup>
// 自己封装导出图标,修改后使用
import icons from './icons';
// 
import { ElIcon } from '@element-plus';

const props = withDefaults(
  defineProps<{ isCenter?: boolean; title?: string }>(),
  {
    isCenter: true,
    title: '',
  }
);
</script>

<style lang="scss" module>
@use '@insight/ui/scss/config' as *;
@use '@insight/ui/scss/mixins' as *;
.node {
  height: 40px;
  width: 180px;
  display: flex;
  align-items: center;
  user-select: none;
  // background-color: var(--el-color-primary-light-5);
  background-color: #e4f0fa;
  color: var(--el-content-text-color-default);

  &.is-center {
    // background-color: var(--el-color-primary-light-3);
    background-color: rgb(22, 135, 232);
    color: var(--el-color-white);
  }

  &::before {
    content: '';
    width: 2px;
    height: 100%;
    background-color: var(--el-color-primary);
  }
}

.icon {
  color: var(--el-color-primary);
}

.title {
  display: inline-block;
  max-width: 120px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
</style>

Vue 组件转化为Html的 hooks

// index.ts

/**
 * Vue组件转换为Html字符串 hooks
**/
const useComponentHtmlString = () => {
  const $iconContainer = document.createElement('div');

  const getCustomNodeHtml = (
    nodeProps?: Partial<InstanceType<typeof Node>>
  ) => {
    render(vueH(Node, nodeProps), $iconContainer);
    return $iconContainer.innerHTML;
  };

  return {
    getCustomNodeHtml,
  };
};

使用

registerNodeimport G6, {
  type GraphData,
  type NodeConfig,
  type ComboConfig,
  Graph,
  type INode,
  type IEdge,
  type Item,
} from '@antv/g6';


const { getCustomNodeHtml } = useComponentHtmlString();

自定义节点方法
G6.registerNode(
    'card-node',
    {
      draw: function drawShape(cfg, group) {
        // cfg 参数中包含节点的配置信息
        const rect = cfg.rect as Rect;
        const { width: w, height: h } = cfg.rect as Rect;
        const isField = rect.isField || false;
        const isCenter = rect.isCenter || false;
        const displayName = cfg.displayName as string;

        group.addShape('dom', {
          zIndex: 9,
          attrs: {
            height: 40,
            width: 180,
            x: 0,
            y: 0,
            opacity: 1,
            html: getCustomNodeHtml({ title: displayName, isCenter: isCenter }),
            cursor: 'pointer',
          },
          draggable: true,
          name: 'card-node',
        });

        group.addShape('rect', {
          zIndex: 1,
          attrs: {
            x: 0,
            y: 0,
            height: 40,
            width: 180,
            fill: 'transparent',
            opacity: 1,
            stroke: '',
          },
          name: 'rect-shape-border',
        });

        const shape = group.addShape('rect', {
          zIndex: 1,
          attrs: {
            height: 40,
            width: 180,
            x: 0,
            y: 0,
            fill: 'transparent',
            opacity: 1,
          },
          name: 'card-node-header-drag',
          draggable: true,
        });
        
        // more ...
        
        return shape
      }
    }
  )

注意点

  1. 虽然使用渲染函数可以实现自定义节点,和复杂的交互功能,但是一些节点的交互和自定义状态需要配合 ant-G6 的 nodeStateStyles 等等参数使用。
  2. 在 registerNode 的 draw 方法中,第一个参数 cfg 也包含了自定义节点配置的相关信息,可以基于 节点的dom 和rect 等布局框架实现自定义效果。
转载自:https://juejin.cn/post/7347165355587158053
评论
请登录