vue实现动态飞线
Vue 实现动态飞线的方法
动态飞线效果常用于数据可视化场景,例如地图上的连线动画。以下是几种实现方式:
使用 SVG 和 Vue 实现基础飞线
<template>
<svg width="500" height="300">
<path
:d="pathData"
fill="none"
stroke="#1890ff"
stroke-width="2"
/>
<circle
:cx="currentX"
:cy="currentY"
r="5"
fill="#f5222d"
/>
</svg>
</template>
<script>
export default {
data() {
return {
start: { x: 50, y: 50 },
end: { x: 450, y: 250 },
progress: 0
}
},
computed: {
pathData() {
const controlX = (this.start.x + this.end.x) / 2;
const controlY = (this.start.y + this.end.y) / 2 + 100;
return `M${this.start.x},${this.start.y} Q${controlX},${controlY} ${this.end.x},${this.end.y}`;
},
currentX() {
const t = this.progress;
return (1-t)*(1-t)*this.start.x + 2*(1-t)*t*((this.start.x+this.end.x)/2) + t*t*this.end.x;
},
currentY() {
const t = this.progress;
return (1-t)*(1-t)*this.start.y + 2*(1-t)*t*((this.start.y+this.end.y)/2+100) + t*t*this.end.y;
}
},
mounted() {
this.animate();
},
methods: {
animate() {
const duration = 2000;
const startTime = Date.now();
const update = () => {
const elapsed = Date.now() - startTime;
this.progress = Math.min(elapsed / duration, 1);
if (this.progress < 1) {
requestAnimationFrame(update);
} else {
this.progress = 0;
setTimeout(this.animate, 500);
}
};
requestAnimationFrame(update);
}
}
}
</script>
使用第三方库实现高级效果
- ECharts + Vue-ECharts
安装依赖:
npm install echarts vue-echarts
实现代码:
<template>
<v-chart
:option="option"
:init-options="initOptions"
autoresize
/>
</template>
<script>
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { LinesChart } from 'echarts/charts';
import {
GridComponent,
GeoComponent,
TooltipComponent
} from 'echarts/components';
import VChart from 'vue-echarts';
use([
CanvasRenderer,
LinesChart,
GridComponent,
GeoComponent,
TooltipComponent
]);
export default {
components: { VChart },
data() {
return {
initOptions: { renderer: 'canvas' },
option: {
series: [{
type: 'lines',
coordinateSystem: 'geo',
polyline: true,
data: [{
coords: [
[116.405285, 39.904989], // 北京
[121.4747, 31.2304] // 上海
],
lineStyle: {
color: '#a6c84c',
width: 2,
curveness: 0.2
},
effect: {
show: true,
period: 6,
trailLength: 0.7,
color: '#fff',
symbolSize: 3
}
}]
}]
}
}
}
}
</script>
使用 D3.js 实现自定义飞线
<template>
<div ref="chartContainer"></div>
</template>
<script>
import * as d3 from 'd3';
export default {
mounted() {
this.initChart();
},
methods: {
initChart() {
const width = 600;
const height = 400;
const svg = d3.select(this.$refs.chartContainer)
.append('svg')
.attr('width', width)
.attr('height', height);
const points = [
{ x: 100, y: 100 },
{ x: 500, y: 300 }
];
const lineGenerator = d3.line()
.curve(d3.curveBasis);
const path = svg.append('path')
.datum(points)
.attr('d', lineGenerator)
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 2);
const pathLength = path.node().getTotalLength();
svg.append('circle')
.attr('r', 5)
.attr('fill', 'red')
.attr('transform', `translate(${points[0].x},${points[0].y})`);
svg.append('circle')
.attr('r', 5)
.attr('fill', 'red')
.attr('transform', `translate(${points[1].x},${points[1].y})`);
const animate = () => {
svg.selectAll('.moving-circle').remove();
svg.append('circle')
.attr('class', 'moving-circle')
.attr('r', 5)
.attr('fill', 'orange')
.transition()
.duration(2000)
.attrTween('transform', function() {
return function(t) {
const point = path.node().getPointAtLength(t * pathLength);
return `translate(${point.x},${point.y})`;
};
})
.on('end', animate);
};
animate();
}
}
}
</script>
性能优化建议
- 对于大量飞线动画,考虑使用 WebGL 方案如 Three.js
- 使用 requestAnimationFrame 替代 setTimeout 实现动画
- 对静态元素使用 CSS transform 加速渲染
- 对不再需要的 DOM 元素及时清理
以上方案可根据具体需求选择,SVG 方案适合简单场景,ECharts 提供开箱即用的解决方案,D3.js 则提供最大灵活性。







