Skip to content

x6 html shape without foreignObject. x6-html-shape, x6-react-shape, x6-vue-shape, x6-svelte-shape all in one!

License

Notifications You must be signed in to change notification settings

lloydzhou/x6-html-shape

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

87 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

x6-html-shape

html shape for @antv/x6

NPM Package npm bundle size npm MIT License

image

online demo

svelte codesandbox demo

vue codesandbox demo

react codesandbox demo

image

example

import { register } from "x6-html-shape";

register({
  shape: "html-shape-for-react",
  render: (node, graph, container) => {
    const root = createRoot(container);
    root.render(<CustomComponent node={node} />);
    return () => root.unmount();
  },
  width: 100,
  height: 40
});


const graph = new Graph({
  container: this.container,
  background: {
    color: "#F2F7FA"
  }
});

graph.addNode({
  shape: "html-shape-for-react",
  x: 100,
  y: 200,
  label: 'rect', 
})

事件穿透

  1. 由于DOM层级关系,html-shape实现的节点总是在svg上层
  2. 通过给x6-html-shape-container设置pointer-events: none屏蔽这一层的交互,使得鼠标事件能穿透到svg内部节点。但是x6-html-shape-node内部有一些元素是需要交互的,所以给节点打开
  3. 至于事件穿透使用forwardEvent将节点内部的鼠标事件转发到对应的x6-node内部
export function forwardEvent(eventType, fromElement, toElement) {
  fromElement.addEventListener(eventType, function (event) {
    toElement.dispatchEvent(new event.constructor(event.type, event));
    event.preventDefault();
    event.stopPropagation();
  });
}

react

react18

import createRender from 'x6-html-shape/dist/react'

const render = createRender(Component)

register({
  shape: 'react18-node',
  render,
  width: 100,
  height: 40,
})

react17

import createRender from 'x6-html-shape/dist/react17'

const render = createRender(Component)

register({
  shape: 'react17-node',
  render,
  width: 100,
  height: 40,
})

react-portal

import { register } from 'x6-html-shape'
import createRender from 'x6-html-shape/dist/portal'
// 1. createRender using Component
 const [render, Provider] = createRender(Component)
2. register node
register({
  shape: 'react-portal-node',
  render,
  width: 100,
  height: 40,
})

// 3.render Provider in react app before call graph.addNode
 <Provider />
// 4. add Node
graph.addNode({
  shape: 'react-portal-node',
  id: 'node1',
  label: 'node1',
  x: 100,
  y: 100,
})

vue

vue3

import createRender from 'x6-html-shape/dist/vue'

const render = createRender(Component)

register({
  shape: 'vue3-node',
  render,
  width: 100,
  height: 40,
})

vue2

import createRender from 'x6-html-shape/dist/vue2'

const render = createRender(Component)

register({
  shape: 'vue2-node',
  render,
  width: 100,
  height: 40,
})

vue3-teleport

import { register } from 'x6-html-shape'
import createRender from 'x6-html-shape/dist/teleport'
// 1. createRender using Component
 const [render, Provider] = createRender(Component)
2. register node
register({
  shape: 'vue3-teleport-node',
  render,
  width: 100,
  height: 40,
})

// 3.render Provider in react app before call graph.addNode
 <Provider />
// 4. add Node
graph.addNode({
  shape: 'vue3-teleport-node',
  id: 'vue3-teleport-node',
  label: 'vue3 teleport node',
  x: 100,
  y: 100,
})

svelte

import { register } from 'x6-html-shape'
import createRender from 'x6-html-shape/dist/svelte'
// 1. createRender using Component
 const render = createRender(Component)
2. register node
register({
  shape: 'svelte-node',
  render,
  width: 100,
  height: 40,
})

// 3. add Node
graph.addNode({
  shape: 'svelte-node',
  label: 'svelte node',
  x: 100,
  y: 100,
})