在视频编辑器中,时间轴刻度尺是一个非常重要的组件,它能直观地展示视频的时间位置。今天我们来详细讲解一下时间轴刻度尺的实现原理。
核心实现
1. Canvas绘制基础
时间轴刻度尺使用Canvas实现,主要包含以下几个关键点:
js
const canvas = document.getElementById('time-ruler-canvas');
const ctx = canvas.getContext('2d');
canvas.width = timeline.lengthInpx; // 画布宽度根据时间轴长度动态设置
ctx.strokeStyle = '#353535'; // 设置刻度线颜色
2. 刻度绘制逻辑
刻度的绘制采用分级显示的方式:
-
普通刻度:3px高
-
5的倍数刻度:6px高
-
10的倍数刻度:16px高,并显示时间文本
具体实现代码:
js
function drawTick(tick, unit) {
let length = 3;
ctx.lineWidth = 1;
// 判断刻度等级
if (tick % 5 === 0) length = 6;
if (tick % 10 === 0) length = 16;
// 画刻度线
ctx.moveTo(tick * timeline.scale * unit, 0);
ctx.lineTo(tick * timeline.scale * unit, length);
ctx.stroke();
// 在10的倍数刻度处绘制时间文本
if (tick % 10 === 0) {
ctx.fillStyle = '#9f9f9f';
ctx.fillText(sec2hsm(tick * unit), tick * timeline.scale * unit + 2, length);
}
}
Tip: sec2hsm
是一个工具方法,把64s
转换成01:04
3. 比例尺算法
比例尺(scale)决定了时间轴的显示密度。在代码中,scale表示1秒在画布上占用的像素数。比如:
-
scale = 10 表示 1秒 = 10px
-
scale = 20 表示 1秒 = 20px
为了保证刻度的清晰可读,设计一个自适应的刻度单位池:
js
const unitPool = [
{ scale: 45, unit: 1/10 }, // 比例尺>=45px时,1个刻度表示0.1秒
{ scale: 20, unit: 1 }, // 比例尺>=20px时,1个刻度表示1秒
{ scale: 10, unit: 2 }, // 比例尺>=10px时,1个刻度表示2秒
{ scale: 4, unit: 3 }, // 比例尺>=4px时,1个刻度表示3秒
{ scale: 1, unit: 6 } // 比例尺>=1px时,1个刻度表示6秒
];
根据当前的scale值,自动选择合适的刻度单位:
js
const unit = unitPool.find((u) => u.scale <= timeline.scale).unit;
4. 缩放实现
缩放的实现主要依赖于Timeline类中的scale属性:
js
// Timeline.js
constructor(options) {
const defaults = {
scale: 10, // 默认10px = 1s
// ...其他属性
}
}
get lengthInpx() {
return this.end * this.scale * 1.2; // 时间轴总长度 = 总时长 * 比例尺 * 1.2
}
当用户进行缩放操作时,只需要改变scale值,TimeRuler组件会通过Vue的响应式系统自动重新渲染:
js
watch(() => timeline.lengthInpx, drawTimeRuler, {
immediate: true,
deep: true
});
为了优化性能,使用了throttle防抖处理,减少滚动鼠标滚轮时的触发间隔:
js
const drawTimeRuler = throttle(function () {
canvas.width = Math.min(timeline.lengthInpx, 65535) // 清除画布,宽度最大65535,超出会崩溃
ctx.strokeStyle = '#353535'
const unitPool = [
{ scale: 45, unit: 1 / 10 },
{ scale: 20, unit: 1 },
{ scale: 10, unit: 2 },
{ scale: 4, unit: 3 }, // 比例尺4px = 1s,则一个刻度表示3秒
{ scale: 1, unit: 6 } // 比例尺1px = 1s,则一个刻度表示6秒
]
const unit = unitPool.find((u) => u.scale <= timeline.scale).unit
const tickCount = canvas.width / timeline.scale / unit
for (let i = 0; i < tickCount; i++) {
drawTick(i, unit)
}
}, 200)
总结
时间轴刻度尺的实现核心在于:
-
使用Canvas进行高效绘制
-
采用分级刻度显示策略
-
动态比例尺算法
-
基于Vue的响应式更新机制