vue实现点对点连线
实现点对点连线的基本思路
在Vue中实现点对点连线通常需要结合HTML5的Canvas或SVG技术。核心步骤包括定义点的坐标、绘制连线逻辑以及动态更新连线状态。
使用Canvas实现
通过Canvas的API绘制线段,适用于需要高性能或复杂交互的场景。
<template>
<canvas ref="canvas" @mousedown="handleMouseDown" @mousemove="handleMouseMove" @mouseup="handleMouseUp"></canvas>
</template>
<script>
export default {
data() {
return {
points: [],
isDrawing: false,
startPoint: null
};
},
mounted() {
this.initCanvas();
},
methods: {
initCanvas() {
const canvas = this.$refs.canvas;
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
this.ctx = canvas.getContext('2d');
},
handleMouseDown(e) {
this.isDrawing = true;
const rect = e.target.getBoundingClientRect();
this.startPoint = { x: e.clientX - rect.left, y: e.clientY - rect.top };
},
handleMouseMove(e) {
if (!this.isDrawing) return;
const rect = e.target.getBoundingClientRect();
const endPoint = { x: e.clientX - rect.left, y: e.clientY - rect.top };
this.ctx.clearRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height);
this.ctx.beginPath();
this.ctx.moveTo(this.startPoint.x, this.startPoint.y);
this.ctx.lineTo(endPoint.x, endPoint.y);
this.ctx.stroke();
},
handleMouseUp(e) {
this.isDrawing = false;
const rect = e.target.getBoundingClientRect();
const endPoint = { x: e.clientX - rect.left, y: e.clientY - rect.top };
this.points.push({ start: this.startPoint, end: endPoint });
}
}
};
</script>
使用SVG实现
SVG更适合需要矢量图形且支持DOM操作的场景,例如动态修改连线样式或绑定事件。
<template>
<svg ref="svg" @mousedown="handleMouseDown" @mousemove="handleMouseMove" @mouseup="handleMouseUp">
<line v-for="(line, index) in lines" :key="index"
:x1="line.start.x" :y1="line.start.y"
:x2="line.end.x" :y2="line.end.y"
stroke="black" stroke-width="2" />
</svg>
</template>
<script>
export default {
data() {
return {
lines: [],
isDrawing: false,
currentLine: null
};
},
methods: {
handleMouseDown(e) {
this.isDrawing = true;
const svg = this.$refs.svg;
const point = this.getSVGPoint(e, svg);
this.currentLine = { start: point, end: point };
},
handleMouseMove(e) {
if (!this.isDrawing) return;
const svg = this.$refs.svg;
this.currentLine.end = this.getSVGPoint(e, svg);
},
handleMouseUp(e) {
this.isDrawing = false;
this.lines.push({ ...this.currentLine });
this.currentLine = null;
},
getSVGPoint(e, svg) {
const pt = svg.createSVGPoint();
pt.x = e.clientX;
pt.y = e.clientY;
return pt.matrixTransform(svg.getScreenCTM().inverse());
}
}
};
</script>
动态绑定数据驱动的连线
若需根据数据动态生成连线,可结合Vue的响应式特性更新连线。
<template>
<svg>
<line v-for="(connection, index) in connections" :key="index"
:x1="getNodeX(connection.from)" :y1="getNodeY(connection.from)"
:x2="getNodeX(connection.to)" :y2="getNodeY(connection.to)"
stroke="blue" stroke-width="2" />
</svg>
</template>
<script>
export default {
data() {
return {
nodes: [
{ id: 1, x: 50, y: 50 },
{ id: 2, x: 150, y: 150 }
],
connections: [
{ from: 1, to: 2 }
]
};
},
methods: {
getNodeX(id) {
const node = this.nodes.find(n => n.id === id);
return node ? node.x : 0;
},
getNodeY(id) {
const node = this.nodes.find(n => n.id === id);
return node ? node.y : 0;
}
}
};
</script>
使用第三方库(如D3.js)
对于复杂拓扑关系,可使用D3.js等库简化实现。
<template>
<div ref="graphContainer"></div>
</template>
<script>
import * as d3 from 'd3';
export default {
mounted() {
this.initD3Graph();
},
methods: {
initD3Graph() {
const data = {
nodes: [{ id: 1 }, { id: 2 }],
links: [{ source: 1, target: 2 }]
};
const svg = d3.select(this.$refs.graphContainer)
.append('svg')
.attr('width', 300)
.attr('height', 300);
const simulation = d3.forceSimulation(data.nodes)
.force('link', d3.forceLink(data.links).id(d => d.id));
const link = svg.append('g')
.selectAll('line')
.data(data.links)
.enter()
.append('line')
.attr('stroke', 'black');
simulation.on('tick', () => {
link
.attr('x1', d => d.source.x)
.attr('y1', d => d.source.y)
.attr('x2', d => d.target.x)
.attr('y2', d => d.target.y);
});
}
}
};
</script>
注意事项
- 性能优化:频繁重绘时建议使用Canvas,静态或少量连线可用SVG。
- 坐标转换:确保鼠标事件坐标转换为画布或SVG的局部坐标。
- 响应式设计:监听窗口大小变化时需重新计算画布尺寸。
以上方法可根据实际需求选择,数据驱动的场景推荐结合Vue的响应式系统与SVG/D3.js实现。







