【G6】G6学习笔记(三)

前言

  • 上一篇已经可以修改label以及一些配置属性方面的东西,但是增加删除节点,增加删除线没写,这篇来探究下如何实现。

切换模式

  • 其实不切换模式也可以弄,官方给的例子是切换模式做,因为点击行为做出了改变。
  • 主要就是注册行为,当切换到该模式下点击然后要拿到graph,调用graph的addItem,拿到鼠标位置增加新节点
G6.registerBehavior('click-add-node', {
  // Set the events and the corresponding responsing function for this behavior
  getEvents() {
    // The event is canvas:click, the responsing function is onClick
    return {
      'canvas:click': 'onClick',
    };
  },
  // Click event
  onClick(ev) {
    const self = this;
    const graph = self.graph;
    // Add a new node
    graph.addItem('node', {
      x: ev.canvasX,
      y: ev.canvasY,
      id: `node-${addedCount}`, // Generate the unique id
    });
    addedCount++;
  },
});
  • 增加边的例子稍微复杂一点:
G6.registerBehavior('click-add-edge', {
  // Set the events and the corresponding responsing function for this behavior
  getEvents() {
    return {
      'node:click': 'onClick', // The event is canvas:click, the responsing function is onClick
      mousemove: 'onMousemove', // The event is mousemove, the responsing function is onMousemove
      'edge:click': 'onEdgeClick', // The event is edge:click, the responsing function is onEdgeClick
    };
  },
  // The responsing function for node:click defined in getEvents
  onClick(ev) {
    const self = this;
    const node = ev.item;
    const graph = self.graph;
    // The position where the mouse clicks
    const point = { x: ev.x, y: ev.y };
    const model = node.getModel();
    if (self.addingEdge && self.edge) {
      graph.updateItem(self.edge, {
        target: model.id,
      });

      self.edge = null;
      self.addingEdge = false;
    } else {
      // Add anew edge, the end node is the current node user clicks
      self.edge = graph.addItem('edge', {
        source: model.id,
        target: model.id,
      });
      self.addingEdge = true;
    }
  },
  // The responsing function for mousemove defined in getEvents
  onMousemove(ev) {
    const self = this;
    // The current position the mouse clicks
    const point = { x: ev.x, y: ev.y };
    if (self.addingEdge && self.edge) {
      // Update the end node to the current node the mouse clicks
      self.graph.updateItem(self.edge, {
        target: point,
      });
    }
  },
  // The responsing function for edge:click defined in getEvents
  onEdgeClick(ev) {
    const self = this;
    const currentEdge = ev.item;
    if (self.addingEdge && self.edge === currentEdge) {
      self.graph.removeItem(self.edge);
      self.edge = null;
      self.addingEdge = false;
    }
  },
});

完整示例:

let addedCount = 0;
// Register a custom behavior: add a node when user click the blank part of canvas
G6.registerBehavior("click-add-node", {
	// Set the events and the corresponding responsing function for this behavior
	getEvents() {
		// The event is canvas:click, the responsing function is onClick
		return {
			"canvas:click": "onClick",
		};
	},
	// Click event
	onClick(ev: IG6GraphEvent) {
		const self = this;
		const graph = self.graph as Graph;
		// Add a new node
		graph.addItem("node", {
			x: ev.canvasX,
			y: ev.canvasY,
			id: `node-${addedCount}`, // Generate the unique id
		});
		addedCount++;
	},
});
// Register a custom behavior: click two end nodes to add an edge
G6.registerBehavior("click-add-edge", {
	// Set the events and the corresponding responsing function for this behavior
	getEvents() {
		return {
			"node:click": "onClick", // The event is canvas:click, the responsing function is onClick
			mousemove: "onMousemove", // The event is mousemove, the responsing function is onMousemove
			"edge:click": "onEdgeClick", // The event is edge:click, the responsing function is onEdgeClick
		};
	},
	// The responsing function for node:click defined in getEvents
	onClick(ev: IG6GraphEvent) {
		const self = this;
		const node = ev.item;
		const graph = self.graph as Graph;
		// The position where the mouse clicks
		//const point = { x: ev.x, y: ev.y };
		const model = node!.getModel();
		if (self.addingEdge && self.edge) {
			graph.updateItem(self.edge as IEdge, {
				target: model.id,
			});

			self.edge = null;
			self.addingEdge = false;
		} else {
			// Add anew edge, the end node is the current node user clicks
			self.edge = graph.addItem("edge", {
				source: model.id,
				target: model.id,
			});
			self.addingEdge = true;
		}
	},
	// The responsing function for mousemove defined in getEvents
	onMousemove(ev: IG6GraphEvent) {
		const self = this;
		// The current position the mouse clicks
		const graph = self.graph as Graph;
		const point = { x: ev.x, y: ev.y };
		if (self.addingEdge && self.edge) {
			// Update the end node to the current node the mouse clicks
			graph.updateItem(self.edge as IEdge, {
				target: point,
			});
		}
	}, // The responsing function for edge:click defined in getEvents
	onEdgeClick(ev: IG6GraphEvent) {
		const self = this;
		const currentEdge = ev.item;
		const graph = self.graph as Graph;
		if (self.addingEdge && self.edge === currentEdge) {
			graph.removeItem(self.edge as IEdge);
			self.edge = null;
			self.addingEdge = false;
		}
	},
});

// Initial data
const data = {
	nodes: [
		{
			id: "node1",
			x: 100,
			y: 200,
		},
		{
			id: "node2",
			x: 300,
			y: 200,
		},
		{
			id: "node3",
			x: 300,
			y: 300,
		},
	],
	edges: [
		{
			id: "edge1",
			target: "node2",
			source: "node1",
		},
	],
};

let graph: Graph;

function App() {
	const ref = useRef<HTMLDivElement>(null);

	useEffect(() => {
		graph = new G6.Graph({
			container: ref.current!,
			width: 800,
			height: 800,
			// The sets of behavior modes
			modes: {
				// Defualt mode
				default: ["drag-node", "click-select"],
				// Adding node mode
				addNode: ["click-add-node", "click-select"],
				// Adding edge mode
				addEdge: ["click-add-edge", "click-select"],
			},
			// The node styles in different states
			nodeStateStyles: {
				// The node styles in selected state
				selected: {
					stroke: "#666",
					lineWidth: 2,
					fill: "steelblue",
				},
			},
		});
		graph.data(data);
		graph.render();
	}, []);

	return (
		<div>
			<button onClick={() => graph.setMode("addNode")}>添加节点</button>
			<button onClick={() => graph.setMode("addEdge")}>添加边</button>
			<button onClick={() => graph.setMode("default")}>默认模式</button>
			<div ref={ref}></div>
		</div>
	);
}
export default App;
  • 注意!这种在缩放画布中添加节点会对不上号,所以要拿鼠标位置转换成画布位置:
  • 把上述click进行修改:
	onClick(ev: IG6GraphEvent) {
		const self = this;
		const graph = self.graph as Graph;
		// Add a new node
		const { x, y } = graph.getPointByClient(ev.clientX, ev.clientY);
		graph.addItem("node", {
			x: x,
			y: y,
			id: `node-${addedCount}`, // Generate the unique id
		});
		addedCount++;
	},
  • 这个坐标系有点让人晕,按文档意思是pointx y 是canvas缩放后位置,拿直接拿xy带入就完了,但是实际不行,必须要转换一下。

删除节点与边

  • 和上面增加节点与边一样,调用graph的remove就ok,但是发现加入click-select模式卸载会报错。。后来大概研究了下,是因为节点卸载了后仍会继续触发click-select事件,然后事件获得的item没有cfg但存在。不加然后卸载比较好:
import React, { useRef, useEffect } from "react";
import G6, { Graph } from "@antv/g6";
import { IG6GraphEvent } from "@antv/g6/lib/types";
import { IEdge, INode } from "@antv/g6/lib/interface/item";

let addedCount = 0;
// Register a custom behavior: add a node when user click the blank part of canvas
G6.registerBehavior("click-add-node", {
	// Set the events and the corresponding responsing function for this behavior
	getEvents() {
		// The event is canvas:click, the responsing function is onClick
		return {
			"canvas:click": "onClick",
		};
	},
	// Click event
	onClick(ev: IG6GraphEvent) {
		const self = this;
		const graph = self.graph as Graph;
		// Add a new node
		const { x, y } = graph.getPointByClient(ev.clientX, ev.clientY);
		graph.addItem("node", {
			x: x,
			y: y,
			id: `node-${addedCount}`, // Generate the unique id
		});
		addedCount++;
	},
});
// Register a custom behavior: click two end nodes to add an edge
G6.registerBehavior("click-add-edge", {
	// Set the events and the corresponding responsing function for this behavior
	getEvents() {
		return {
			"node:click": "onClick", // The event is canvas:click, the responsing function is onClick
			mousemove: "onMousemove", // The event is mousemove, the responsing function is onMousemove
			"edge:click": "onEdgeClick", // The event is edge:click, the responsing function is onEdgeClick
		};
	},
	// The responsing function for node:click defined in getEvents
	onClick(ev: IG6GraphEvent) {
		const self = this;
		const node = ev.item;
		const graph = self.graph as Graph;
		// The position where the mouse clicks
		//const point = { x: ev.x, y: ev.y };
		const model = node!.getModel();
		if (self.addingEdge && self.edge) {
			graph.updateItem(self.edge as IEdge, {
				target: model.id,
			});

			self.edge = null;
			self.addingEdge = false;
		} else {
			// Add anew edge, the end node is the current node user clicks
			self.edge = graph.addItem("edge", {
				source: model.id,
				target: model.id,
			});
			self.addingEdge = true;
		}
	},
	// The responsing function for mousemove defined in getEvents
	onMousemove(ev: IG6GraphEvent) {
		const self = this;
		// The current position the mouse clicks
		const graph = self.graph as Graph;
		const point = { x: ev.x, y: ev.y };
		if (self.addingEdge && self.edge) {
			// Update the end node to the current node the mouse clicks
			graph.updateItem(self.edge as IEdge, {
				target: point,
			});
		}
	}, // The responsing function for edge:click defined in getEvents
	onEdgeClick(ev: IG6GraphEvent) {
		const self = this;
		const currentEdge = ev.item;
		const graph = self.graph as Graph;
		if (self.addingEdge && self.edge === currentEdge) {
			graph.removeItem(self.edge as IEdge);
			self.edge = null;
			self.addingEdge = false;
		}
	},
});

G6.registerBehavior("del-node-and-edge", {
	// Set the events and the corresponding responsing function for this behavior
	getEvents() {
		return {
			"node:click": "onClick", // The event is canvas:click, the responsing function is onClick
			"edge:click": "onEdgeClick", // The event is edge:click, the responsing function is onEdgeClick
		};
	},
	// The responsing function for node:click defined in getEvents
	onClick(ev: IG6GraphEvent) {
		const self = this;
		const node = ev.item;
		const graph = self.graph as Graph;
		// const itemController = graph.get("itemController");
		// itemController.removeItem(node);
		graph.removeItem(node as INode);
	},
	onEdgeClick(ev: IG6GraphEvent) {
		const self = this;
		const currentEdge = ev.item;
		const graph = self.graph as Graph;
		graph.removeItem(currentEdge as IEdge);
	},
});

// Initial data
const data = {
	nodes: [
		{
			id: "node1",
			x: 100,
			y: 200,
		},
		{
			id: "node2",
			x: 300,
			y: 200,
		},
		{
			id: "node3",
			x: 300,
			y: 300,
		},
	],
	edges: [
		{
			id: "edge1",
			target: "node2",
			source: "node1",
		},
	],
};

let graph: Graph;

function App() {
	const ref = useRef<HTMLDivElement>(null);

	useEffect(() => {
		graph = new G6.Graph({
			container: ref.current!,
			width: 800,
			height: 800,
			// The sets of behavior modes
			modes: {
				// Defualt mode
				default: [
					"drag-node",
					"click-select",
					"drag-canvas",
					"zoom-canvas",
				],
				// Adding node mode
				addNode: ["click-add-node", "click-select"],
				// Adding edge mode
				addEdge: ["click-add-edge", "click-select"],
				del: ["del-node-and-edge"],
			},
			// The node styles in different states
			nodeStateStyles: {
				// The node styles in selected state
				selected: {
					stroke: "#666",
					lineWidth: 2,
					fill: "steelblue",
				},
			},
		});
		graph.data(data);
		graph.render();
	}, []);

	return (
		<div>
			<button onClick={() => graph.setMode("addNode")}>添加节点</button>
			<button onClick={() => graph.setMode("addEdge")}>添加边</button>
			<button onClick={() => graph.setMode("default")}>默认模式</button>
			<button onClick={() => graph.setMode("del")}>删除模式</button>
			<div ref={ref}></div>
		</div>
	);
}
export default App;

你可能感兴趣的:(G6,可视化)