canvas实现类似思维导图的效果导图中的节点可以配合鼠标移动
和点击进行拖拽、放缩、添加、删除等操作。
要实现类似思维导图的效果,可以使用HTML5的canvas元素来绘制节点和连线。具体实现步骤如下:
-
创建canvas元素,并设置其宽高。可以使用CSS样式或JavaScript动态设置。
-
定义节点对象。节点包括位置、大小、颜色、文字等属性。可以使用JavaScript的类或对象来实现。
-
定义连线对象。连线包括起点、终点、线型、颜色等属性。可以使用JavaScript的类或对象来实现。
-
编写绘制函数。绘制函数根据节点和连线的属性,使用canvas的2D绘图API来绘制图形。
-
实现节点的拖拽、放缩、添加、删除等操作。可以使用JavaScript的事件处理函数来实现。
-
最后,将绘制函数和事件处理函数绑定到canvas元素上,就可以实现类似思维导图的效果了。
示例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Canvas Mind Map</title>
<style>
canvas {
width: 600px;
height: 400px;
border: 1px solid #ccc;
}
</style>
</head>
<body>
<canvas id="myCanvas"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 定义节点对象
class Node {
constructor(x, y, width, height, color, text) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = color;
this.text = text;
}
draw() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
ctx.fillStyle = '#fff';
ctx.fillText(this.text, this.x + this.width / 2, this.y + this.height / 2);
}
contains(x, y) {
return x >= this.x && x <= this.x + this.width && y >= this.y && y <= this.y + this.height;
}
}
// 定义连线对象
class Line {
constructor(startX, startY, endX, endY, color) {
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
this.color = color;
}
draw() {
ctx.beginPath();
ctx.moveTo(this.startX, this.startY);
ctx.lineTo(this.endX, this.endY);
ctx.strokeStyle = this.color;
ctx.stroke();
}
}
// 创建节点和连线数组
const nodes = [];
const lines = [];
// 添加节点和连线示例
const node1 = new Node(100, 100, 80, 40, '#f00', 'Node 1');
const node2 = new Node(300, 100, 80, 40, '#0f0', 'Node 2');
const line1 = new Line(node1.x + node1.width, node1.y + node1.height / 2, node2.x, node2.y + node2.height / 2, '#00f');
nodes.push(node1, node2);
lines.push(line1);
// 绘制函数
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
lines.forEach(line => line.draw());
nodes.forEach(node => node.draw());
}
// 事件处理函数
let dragging = false;
let resizing = false;
let startX, startY, nodeIndex, resizingIndex;
canvas.addEventListener('mousedown', function(e) {
startX = e.offsetX;
startY = e.offsetY;
nodeIndex = nodes.findIndex(node => node.contains(startX, startY));
resizingIndex = nodes.findIndex(node => startX >= node.x + node.width - 5 && startX <= node.x + node.width + 5 && startY >= node.y + node.height - 5 && startY <= node.y + node.height + 5);
if (nodeIndex !== -1) {
dragging = true;
} else if (resizingIndex !== -1) {
resizing = true;
}
});
canvas.addEventListener('mousemove', function(e) {
if (dragging) {
const node = nodes[nodeIndex];
node.x += e.offsetX - startX;
node.y += e.offsetY - startY;
startX = e.offsetX;
startY = e.offsetY;
draw();
} else if (resizing) {
const node = nodes[resizingIndex];
node.width += e.offsetX - startX;
node.height += e.offsetY - startY;
startX = e.offsetX;
startY = e.offsetY;
draw();
}
});
canvas.addEventListener('mouseup', function(e) {
dragging = false;
resizing = false;
});
canvas.addEventListener('dblclick', function(e) {
const newNode = new Node(e.offsetX, e.offsetY, 80, 40, '#000', 'New Node');
nodes.push(newNode);
draw();
});
// 初始化绘制
draw();
</script>
</body>
</html>
原文地址: http://www.cveoy.top/t/topic/brNM 著作权归作者所有。请勿转载和采集!