G6 Flow Engine Technical Document
Table of Contents
- Introduction
- Project Structure
- Core Architecture
- Graph Instance Management
- Node and Edge System
- Event Bus and State Management
- Interaction Component Design
- Data Transformation and Serialization
- Performance Optimization Strategy
- Troubleshooting Guide
- Summary
Introduction
The G6 Flow Engine is a process flow diagram design system built on AntV G6, designed specifically for MES (Manufacturing Execution System) process modeling. The engine provides complete graphical process design capabilities, supporting complex node types, custom behaviors, interactive menus, and toolbar functions.
The system adopts the Vue 3 Composition API architecture, combined with TypeScript for strong type support, achieving a highly modular component design. Through event-driven state management patterns, it ensures system extensibility and maintainability.
Project Structure
The G6 Flow Engine uses a clear layered architecture, with the main organizational structure as follows:
Chart Source
Section Source
Core Architecture
System Architecture Overview
The G6 Flow Engine adopts modern frontend architecture patterns, combining new features of Vue 3 to achieve efficient data flow management and component communication.
Chart Source
Module Dependency Relationship
There are clear dependency relationships between system modules, achieving loose coupling design through dependency injection and event bus:
Chart Source
Section Source
Graph Instance Management
Core Class Functionality
The Core class is the heart of the G6 Flow Engine, responsible for graph instance creation, configuration, and initialization. It provides a unified interface to manage different types of nodes and edges.
// Core node creation method
createNode({ label, type }: NodeItem, { x, y, properties }: PointType) {
const id = uuidv4()
return new Create({
id,
type,
label,
x,
y,
properties,
Name: label,
name: label,
})
}
// Default graph configuration
setDefaultProps() {
return {
fitCenter: true,
animate: true,
minZoom: 0.2,
maxZoom: 1.4,
defaultNode: {
type: NODES.ACTIVITIES,
labelCfg: {
style: {
fill: '#333',
fontSize: nodeFontSize,
textAlign: 'center',
textBaseline: 'middle',
fontWeight: 'bold',
},
},
},
defaultEdge: {
type: 'polyline',
labelCfg: {
style: {
fill: '#333',
stroke: '#aaa',
fontSize: fontSize - 2,
},
},
style: {
radius: 20,
offset: 45,
endArrow: true,
lineWidth: 3,
stroke: '#aaa',
},
},
}
}
Graph Instance Lifecycle Management
Chart Source
Section Source
Node and Edge System
Basic Node Component Encapsulation
The G6 Flow Engine implements a complete node component system, including Start Node, End Node, and Ordinary Node types.
Start Node (StartNode)
const StartNode: {
type: string
options: Record<string, any>
} = {
type: NODES.ACTIVITY,
options: {
drawShape(cfg: Record<string, any>, group: any) {
const rect = group.addShape('rect', {
attrs: {
x: -75 - x,
y: -25 - y,
width,
height,
radius: 10,
stroke: '#5B8FF9',
fill: '#C6E5FF',
lineWidth: 3,
},
name: 'rect-shape',
})
return rect
},
},
}
Ordinary Node (OrdinaryNode)
Ordinary nodes support dynamic icon loading and state style configuration:
const OrdinaryNode: {
type: string
options: Record<string, any>
} = {
type: NODES.ACTIVITIES,
options: {
drawShape(cfg: Record<string, any>, group: any) {
const type = cfg?.properties?.type
const isRoot = cfg?.isRoot
const rect = group.addShape('rect', {
zIndex: 1,
attrs: {
x: -width / 2,
y: -height / 2,
width,
height,
radius: 1,
stroke: '#5B8FF9',
fill: '#C6E5FF',
lineWidth: 2,
},
name: 'rect-shape',
})
group.addShape('image', {
zIndex: 100,
draggable: false,
attrs: {
x: -width / 2 + 1,
y: -height / 2 + 1,
radius: 1,
width: 20,
height: 20,
img: `/resources/assets/images/${isRoot ? NODES.ACTIVITY : type}.png`,
},
name: 'node-icon',
})
return rect
},
},
}
Node State Style System
Chart Source
Edge Configuration and Style
The system supports various edge types, including default edge styles and state styles:
defaultEdge: {
type: 'polyline',
labelCfg: {
style: {
fill: '#333',
stroke: '#aaa',
fontSize: fontSize - 2,
},
},
style: {
radius: 20,
offset: 45,
endArrow: true,
lineWidth: 3,
stroke: '#aaa',
},
},
edgeStateStyles: {
active: {
stroke: '#5a84ff',
lineWidth: 6,
'text-shape': {
fontSize: fontSize,
},
},
hover: {
stroke: '#5a84ff',
lineWidth: 6,
'text-shape': {
fontSize: fontSize,
},
},
},
Section Source
Event Bus and State Management
GraphEvent Class Design Principle
The GraphEvent class implements a complete event bus system, responsible for managing all user interaction events and state changes.
Chart Source
Event Listener Registration Mechanism
The GraphEvent class registers various event listeners during initialization:
init(graph: Graph, layout: Record<string, any>) {
this.graph = graph
this.layout = layout
// Canvas events
this.graph.on('canvas:contextmenu', this.onCanvasContextMenu)
// Touch events
this.graph.on('canvas:touchmove', this.onNodeTouchmove)
this.graph.on('node:touchstart', this.onNodeTouchStart)
this.graph.on('edge:touchstart', this.onNodeTouchStart)
this.graph.on('touchend', this.onNodeTouchEnd)
// Mouse events
this.graph.on('node:contextmenu', this.nodeContextMenu)
this.graph.on('edge:contextmenu', this.edgeContextMenu)
this.graph.on('node:mouseenter', (...arg) => this.nodeMouseOver(...arg, true))
this.graph.on('node:mouseleave', (...arg) => this.nodeMouseOver(...arg, false))
this.graph.on('edge:mouseenter', (...arg) => this.edgeMouseOver(...arg, true))
this.graph.on('edge:mouseleave', (...arg) => this.edgeMouseOver(...arg, false))
this.graph.on('edge:click', (...arg) => this.edgeClick(...arg))
// Special events
this.graph.on('aftercreateedge', this.onAfterCreateEdge)
}
State Storage System
Chart Source
Section Source
Interaction Component Design
Custom Menu System
The G6 Flow Engine implements a complete right-click menu system, supporting different context menus for nodes and edges.
// Menu item configuration
const contextMenu = computed<any[]>(() => {
if (graphEvent.isShowPassNode.value && graphEvent.type.value === 'canvas') {
return [{
type: 'view',
label: _t('Paste'),
fn: onPassNode,
divided: true,
disabled: false,
icon: 'files/pass',
}]
}
const menu: any[] = [{
type: 'view',
label: _t('View Properties'),
fn: onViewDialog,
divided: true,
disabled: false,
icon: 'viewProps',
}]
if (isEdit.value) {
if (graphEvent.type.value === 'node') {
menu.push({
label: _t('Copy'),
fn: onCopyNode,
divided: true,
icon: 'copy',
type: 'copy',
})
}
menu.push({
label: _t('Delete'),
fn: onDelete,
type: 'del',
divided: true,
disabled: false,
icon: 'delete-menu',
})
}
return menu
})
Toolbar Interaction Design
The toolbar provides standardized operation interfaces, supporting undo, redo, zoom, layout, and other functions:
Chart Source
Extension Interface Design
The system provides rich extension interfaces, allowing developers to add custom behaviors and layout transformations:
// Behavior mapping interface
export const behaviorMap: {
[key: string]: string
} = {
dragCanvas: 'drag-canvas',
dragNode: 'drag-node',
zoomCanvas: 'zoom-canvas',
clickSelect: 'click-select',
createEdge: 'create-edge',
}
// Custom behavior example
const customBehavior = {
type: 'custom-behavior',
trigger: 'click',
callback: (graph, e) => {
// Custom click logic
const node = graph.find('node', { id: e.item.get('id') })
if (node) {
// Execute custom operation
node.update({
style: { fill: '#ff0000' }
})
}
}
}
Section Source
Data Transformation and Serialization
JSON Schema Serialization Standard
The G6 Flow Engine implements a complete XML to JSON data conversion mechanism, supporting serialization of complex flowchart structures.
Chart Source
Core Data Transformation Algorithm
// XML to JSON conversion
export const getJsonByXml = (xml: string, name?: string) => {
const options = {
ignoreAttributes: false,
attributeNamePrefix: '@_',
}
const parser = new XMLParser(options)
try {
const json = parser.parse(xml)
xmlData.value = json
return json
} catch (error) {
const newXml = Core.createBaseXml(name)
const json = parser.parse(newXml)
xmlData.value = json
return json
}
}
// Flowchart data to XML
export const getFlowDataToXml = ({ nodes, edges }: FlowType) => {
const Activity: any[] = []
const Transition: any[] = []
const nodeMap: Record<string, any> = {}
nodes.forEach((item) => {
const obj: Record<string, any> = {}
Object.keys(item.properties || {}).forEach((key) => {
if (isFirstLetterUpperCase(key)) {
obj[key] = item.properties[key]
}
})
const oldId = item?.properties?.oldId
const flow = flowMap.get(oldId)
obj.Name = flow?.properties?.Name || item.properties.Name || ''
nodeMap[obj.Name] = {
x: item.x,
y: item.y,
}
Activity.push(obj)
})
edges.forEach((item) => {
const obj: Record<string, any> = {}
Object.keys(item?.properties || {}).forEach((key) => {
if (isFirstLetterUpperCase(key)) {
obj[key] = item.properties[key]
}
})
// Process condition data
const condition = item.properties?.Condition || {}
obj.Condition = handleConditionChildren(obj.Condition)
// Process source and target nodes
const oldSourceId = item.properties?.oldSourceId
const oldTargetId = item.properties?.oldTargetId
const flowSource = flowMap.get(oldSourceId)
const flowTarget = flowMap.get(oldTargetId)
obj.Source = flowSource?.properties?.Name || ''
obj.Sink = flowTarget?.properties?.Name || ''
Transition.push(obj)
})
return getXmlByJson(Activity, Transition, nodeMap)
}
Data Persistence Strategy in High Concurrency Scenarios
Chart Source
Section Source
Performance Optimization Strategy
Graph Data Caching Mechanism
The system implements a multi-layer caching mechanism to improve performance:
- Node Mapping Cache: Use Map structure to cache mapping from node ID to node object
- Edge Mapping Cache: Cache edge relationships for quick lookup
- XML Data Cache: Avoid repeated parsing of XML data
// Caching optimization example
const flowMap: Map<string, any> = new Map()
const flowNodeMap: Map<string, any> = new Map()
const edgeMap = new Map()
const nodeMap = new Map()
// Fast lookup using cache
const findNodeById = (id: string) => {
return flowNodeMap.get(id)
}
const findEdgeBySourceTarget = (source: string, target: string) => {
return edgeMap.get(`${source}-${target}`)
}
Memory Management Strategy
Batch Operation Optimization
For operations involving a large number of nodes and edges, the system provides a batch processing mechanism:
// Batch node addition
const batchAddNodes = (nodes: any[]) => {
const batchData = nodes.map(node => ({
id: node.id,
type: node.type,
x: node.x,
y: node.y,
properties: node.properties
}))
graph.batchAddItems('node', batchData)
}
// Batch edge addition
const batchAddEdges = (edges: any[]) => {
const batchData = edges.map(edge => ({
id: edge.id,
source: edge.source,
target: edge.target,
type: edge.type,
properties: edge.properties
}))
graph.batchAddItems('edge', batchData)
}
Troubleshooting Guide
Common Problem Diagnosis
1. Graph Instance Initialization Failure
Symptoms: Page shows blank or error Causes: G6 instance creation failed or configuration error Solutions:
// Check G6 version compatibility
console.log(G6.version)
// Verify container element existence
const container = document.getElementById('g6-container')
if (!container) {
throw new Error('G6 container element does not exist')
}
// Check configuration parameters
const config = {
container: 'g6-container',
width: 800,
height: 600,
...Core.prototype.setDefaultProps()
}
2. Node Drag and Drop Failure
Symptoms: Cannot drag nodes to canvas Causes: Event listener not registered correctly or insufficient permissions Solutions:
// Check edit mode
if (!isEdit.value) {
console.warn('Currently in read-only mode, cannot drag nodes')
return
}
// Verify event listener
const graph = g6RenderRef.value?.getGraph()
if (!graph) {
console.error('G6 instance not initialized')
return
}
// Rebind events
graph.on('node:dragstart', onDragstart)
graph.on('node:dragend', onDragend)
3. Data Save Failure
Symptoms: Save operation unresponsive or error Causes: Network issue or data format error Solutions:
// Add error handling
const graphSave = async (isTemp: boolean = false) => {
try {
const graph = g6RenderRef.value.getGraph()
const xml = generateFlowXml(graph)
if (!xml) {
throw new Error('Failed to generate XML data')
}
const data = {
...flowConfig,
content: xml,
version: flowConfig.version || 1,
}
await saveFlowData(data, isTemp)
ElMessage.success(_t('Save successful'))
} catch (error) {
console.error('Save failed:', error)
ElMessage.error(`Save failed: ${error.message}`)
}
}
Performance Issue Troubleshooting
1. Slow Rendering of Many Nodes
Diagnosis Method:
// Monitor rendering performance
const startTime = performance.now()
graph.render()
const endTime = performance.now()
console.log(`Rendering time: ${endTime - startTime}ms`)
// Check node count
const nodeCount = graph.getNodes().length
console.log(`Node count: ${nodeCount}`)
Optimization Scheme:
- Use virtual scrolling to reduce DOM nodes
- Implement node lazy loading mechanism
- Optimize node drawing algorithm
2. Memory Leak Detection
// Memory usage monitoring
const monitorMemory = () => {
if ('memory' in performance) {
const memoryInfo = (performance as any).memory
console.log('Memory usage:', {
usedJSHeapSize: memoryInfo.usedJSHeapSize,
totalJSHeapSize: memoryInfo.totalJSHeapSize,
jsHeapSizeLimit: memoryInfo.jsHeapSizeLimit
})
}
}
// Periodic check
setInterval(monitorMemory, 5000)
Section Source
Summary
The G6 Flow Engine is a fully functional and clearly architected process flow diagram design system. Through in-depth analysis of its core components and design patterns, we can see the following key features:
Technical Advantages
- Modular Design: Clear layered architecture makes the system easy to maintain and extend
- Event Driven: Comprehensive event bus system ensures loose coupling between components
- Type Safety: Strong type support from TypeScript improves code quality and development efficiency
- Performance Optimization: Multi-layer caching and batch operation mechanisms ensure good user experience
Architecture Highlights
- Core Class Unified Management: Provides consistent API interfaces and configuration management
- GraphEvent Event Bus: Complete user interaction event handling mechanism
- Store State Management: Reactive state management based on Vue 3
- Componentized Node System: Flexible node type extension capability
Extension Suggestions
- Plugin Architecture: Further abstract plugin interfaces to support more custom functions
- Theme System: Implement configurable theme system to support different visual styles
- Collaboration Features: Add real-time collaboration functions to support multi-user editing
- Mobile Optimization: Perform specialized interaction optimization for mobile devices
The G6 Flow Engine provides powerful process modeling capabilities for the MES system, and its design philosophy and implementation methods are worthy of reference and application in similar projects. Through continuous optimization and extension, the system can meet more complex business requirements and technical challenges.