Implementing Drag-and-Drop Node Creation in AntV G6

AntV G6 is a graph visualization engine providing capabilities for drawing, layout, analysis, interaction, and animation of graphs. This guide explains how to imlpement a drag-and-drop interface to add nodes to a G6 graph from an external HTML panel.

Core Implementation Considerations

1. Coordinate System Transformation

In practical applications, the G6 canvas often does not occupy the full viewport. It may be positioned within a layout containing navigation bars or side panels. Additionally, if the canvas supports panning (drag-canvas) and zooming (zoom-canvas), the mapping between screen coordinates and the graph's internal coordinate system becomes non-trivial.

G6 provides the graph.getPointByClient(clientX, clientY) API to convert screen coordinates (relative to the viewport) to the canvas's internal coordinate system, accounting for current transformations like pan and zoom.

2. Native HTML Drag-and-Drop

The element palette is built with satndard HTML. To make elements draggable, set the draggable attribute to true. The dragend event listener can then capture the final screen coordinates when the user releases the mouse button, which is the ideal moment to create a new node on the graph.

Implementation Steps with Vue 3

The following steps outline the process:

  1. Initialize the G6 graph instance.
  2. Create an HTML-based node palette.
  3. Enable drag on palette elements using draggable="true".
  4. Listen for the dragend event on these elements.
  5. Within the event handler, convert the event's screen coordinates to graph coordinates using graph.getPointByClient().
  6. Add a new node to the graph using graph.addItem('node', model, stack).

Complete Vue Component Example

<template>
  <div class="container">
    <!-- Node Palette -->
    <div class="palette">
      <div
        v-for="shape in shapeTypes"
        :key="shape"
        class="palette-item"
      >
        <div
          :class="['shape-preview', shape]"
          draggable="true"
          @dragend="handleDrop(shape, $event)"
        ></div>
        <span class="shape-label">{{ shape }}</span>
      </div>
    </div>

    <!-- Graph Canvas Container -->
    <div id="graph-container" ref="canvasEl"></div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import G6 from '@antv/g6'

const canvasEl = ref(null)
const graphInstance = ref(null)

// Initial graph data
const initialData = {
  nodes: [
    { id: 'initial-node-1', x: 300, y: 200 },
    { id: 'initial-node-2', x: 600, y: 200 },
  ],
  edges: [
    { source: 'initial-node-1', target: 'initial-node-2' },
  ],
}

// Available node shapes for the palette
const shapeTypes = ['rectangle', 'circle']

function initializeGraph() {
  graphInstance.value = new G6.Graph({
    container: canvasEl.value,
    width: canvasEl.value.clientWidth,
    height: canvasEl.value.clientHeight,
    modes: {
      default: ['drag-canvas', 'zoom-canvas', 'drag-node'],
    },
  })

  graphInstance.value.data(initialData)
  graphInstance.value.render()
}

function handleDrop(shapeType, event) {
  // Convert screen coordinates from dragend event to graph coordinates
  const canvasPoint = graphInstance.value.getPointByClient(event.x, event.y)

  const newNodeModel = {
    id: `node-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
    label: `New ${shapeType}`,
    type: shapeType,
    x: canvasPoint.x,
    y: canvasPoint.y,
  }

  // Add the new node to the graph. The third argument (false) prevents adding to the undo/redo stack.
  graphInstance.value.addItem('node', newNodeModel, false)
}

onMounted(() => {
  initializeGraph()
})
</script>

<style scoped>
.container {
  display: flex;
  height: 100vh;
  position: relative;
}

#graph-container {
  flex: 1;
  border: 1px solid #e8e8e8;
}

.palette {
  position: absolute;
  left: 16px;
  top: 16px;
  background: white;
  border-radius: 6px;
  padding: 12px 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  z-index: 10;
}

.palette-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-bottom: 20px;
  cursor: grab;
  user-select: none;
}

.palette-item:last-child {
  margin-bottom: 0;
}

.shape-preview {
  width: 24px;
  height: 24px;
  border: 2px solid #1890ff;
  margin-bottom: 4px;
}

.shape-preview.rectangle {
  background-color: #f0f9ff;
}

.shape-preview.circle {
  border-radius: 50%;
  background-color: #f6ffed;
}

.shape-label {
  font-size: 12px;
  color: #666;
}
</style>

Key Implementation Details

  • Coordinate Conversion: The handleDrop function uses graphInstance.value.getPointByClient(event.x, event.y) to accurately place the new node at the drop location within the graph's coordinate space, regardless of canvas pan or zoom.
  • Node ID Generation: The example uses a combination of timestamp and random string to generate a sufficiently unique ID, minimizing collision risk.
  • Graph Interaction Modes: The configuration includes drag-canvas, zoom-canvas, and drag-node to provide a fully interactive graph experience alongside the drag-and-drop creation feature.
  • Visual Feedback: The palette uses CSS to visually distinguish between different node shapes (rectangle vs. circle) and provides a grab cursor.

Tags: AntV G6 Vue 3 Data Visualization Drag and Drop Graph Interaction

Posted on Tue, 21 Jul 2026 17:08:48 +0000 by ghgarcia