MxGraphContainer.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. <template>
  2. <div ref="graphContainerRef" class="mxgraph-container"></div>
  3. </template>
  4. <script setup lang="ts">
  5. import { myMxGraph, myMxRubberband, myMxConstants, myMxEvent, myMxPopupMenu } from '@/graph/mxGraph'
  6. const graphContainerRef = ref<HTMLElement | null>(null)
  7. const graphInstance = ref<InstanceType<typeof myMxGraph> | null>(null)
  8. provide('mxgraph-instance', graphInstance)
  9. function initGraph(container: HTMLElement): InstanceType<typeof myMxGraph> {
  10. const graph = new myMxGraph(container)
  11. // 基本配置
  12. graph.setPanning(true)
  13. graph.setConnectable(true)
  14. new myMxRubberband(graph)
  15. // 配置样式
  16. configureStyles(graph)
  17. // 设置事件监听
  18. setupGraphListeners(graph)
  19. // 添加上下文菜单
  20. setupContextMenu(graph)
  21. // 初始示例图形
  22. createSampleGraph(graph)
  23. return graph
  24. }
  25. function configureStyles(graph: InstanceType<typeof myMxGraph>) {
  26. const style = graph.getStylesheet().getDefaultVertexStyle()
  27. Object.assign(style, {
  28. [myMxConstants.STYLE_SHAPE]: myMxConstants.SHAPE_RECTANGLE,
  29. [myMxConstants.STYLE_STROKECOLOR]: '#2d8cf0',
  30. [myMxConstants.STYLE_FILLCOLOR]: '#ffffff',
  31. [myMxConstants.STYLE_FONTCOLOR]: '#333333',
  32. [myMxConstants.STYLE_STROKEWIDTH]: 2
  33. })
  34. const edgeStyle = graph.getStylesheet().getDefaultEdgeStyle()
  35. Object.assign(edgeStyle, {
  36. [myMxConstants.STYLE_ENDARROW]: myMxConstants.ARROW_CLASSIC,
  37. [myMxConstants.STYLE_STROKECOLOR]: '#666666',
  38. [myMxConstants.STYLE_STROKEWIDTH]: 2
  39. })
  40. }
  41. function setupGraphListeners(graph: InstanceType<typeof myMxGraph>) {
  42. graph
  43. .getSelectionModel()
  44. .addListener(myMxConstants.EVENT_CHANGE, (_sender: unknown, evt: any) => {
  45. const cells = evt.getProperty('added')
  46. console.log('Selected cells:', cells)
  47. })
  48. graph.addListener(myMxConstants.EVENT_DOUBLE_CLICK, (_sender: unknown, evt: any) => {
  49. const cell = evt.getProperty('cell')
  50. if (cell) {
  51. const newValue = prompt('输入新值:', graph.convertValueToString(cell) || '')
  52. if (newValue !== null) {
  53. graph.getModel().setValue(cell, newValue)
  54. }
  55. }
  56. })
  57. }
  58. function setupContextMenu(graph: InstanceType<typeof myMxGraph>) {
  59. myMxEvent.disableContextMenu(graph.container)
  60. graph.addListener(myMxConstants.EVENT_CONTEXT_MENU, (_sender: unknown, evt: any) => {
  61. const cell = evt.getProperty('cell')
  62. evt.preventDefault()
  63. if (!cell) return
  64. const menu = new myMxPopupMenu((menu: any) => {
  65. menu.addItem('删除', null, () => {
  66. graph.removeCells([cell])
  67. })
  68. menu.addItem('复制', null, () => {
  69. graph.setSelectionCell(graph.cloneCell(cell))
  70. })
  71. })
  72. const pt = myMxEvent.getClientXY(evt.getEvent())
  73. menu.popup(pt.x, pt.y, null, evt.getEvent())
  74. })
  75. }
  76. function createSampleGraph(graph: InstanceType<typeof myMxGraph>) {
  77. const parent = graph.getDefaultParent()
  78. graph.getModel().beginUpdate()
  79. try {
  80. const v1 = graph.insertVertex(parent, null, '开始', 20, 20, 80, 40)
  81. const v2 = graph.insertVertex(parent, null, '步骤1', 20, 80, 80, 40)
  82. const v3 = graph.insertVertex(parent, null, '结束', 20, 140, 80, 40)
  83. graph.insertEdge(parent, null, '', v1, v2)
  84. graph.insertEdge(parent, null, '', v2, v3)
  85. } finally {
  86. graph.getModel().endUpdate()
  87. }
  88. }
  89. onMounted(async () => {
  90. if (graphContainerRef.value) {
  91. graphInstance.value = initGraph(graphContainerRef.value)
  92. }
  93. })
  94. </script>
  95. <style lang="scss" scoped>
  96. .mxgraph-container {
  97. flex: 1;
  98. height: calc(100vh - 90px);
  99. background: url('@/assets/graph/images/grid.gif');
  100. }
  101. </style>