可在canvas上实时绘制mediastream视频流并叠加涂鸦——先用getusermedia获取流并绑定video(设playsinline、muted、autoplay),再用requestanimationframe逐帧drawimage到canvas,同时监听鼠标/触控事件在顶层canvas绘制路径,通过双canvas结构分离视频与涂鸦图层,支持清除、合成导出及移动端适配。

可以在Canvas上实时绘制MediaStream视频流的叠加图形,实现画中画涂鸦效果——关键在于将视频帧逐帧渲染到Canvas,再在其上用2D绘图API进行手绘或标注。
获取并播放视频流(本地或远程)
使用navigator.mediaDevices.getUserMedia()获取摄像头流,或用new MediaStream()组合多个轨道。将流赋给元素,并设playsinline muted autoplay确保移动端兼容:
- 避免直接在上绘制,而是将其作为Canvas的图像源
- 设置video.width和video.height为实际分辨率,防止Canvas拉伸失真
- 若需画中画,可创建两个:主画面+小窗(如右上角150×120px),分别绑定不同Canvas
将视频帧绘制到Canvas并启用涂鸦
用requestAnimationFrame循环调用ctx.drawImage(video, ...)把当前帧画入Canvas;同时监听鼠标/触控事件,在同一Canvas上绘制路径:
- 开启ctx.lineCap = 'round'和ctx.lineJoin = 'round'让笔迹更自然
- 记录isDrawing状态,mousedown/touchstart时开始路径,mousemove/touchmove时lineTo,mouseup/touchend时stroke
- 为画中画小窗单独准备一个Canvas(如miniCanvas),仅绘制缩略视频+简单标注(如红框、文字),不响应复杂涂鸦
分离视频与涂鸦图层(提升性能与复用性)
推荐双Canvas结构:底层Canvas持续绘制视频帧,顶层Canvas仅处理用户涂鸦。这样可随时清除涂鸦(topCtx.clearRect())而不影响视频,也便于导出带标注的视频帧:
- 顶层Canvas设pointer-events: none可穿透点击到底层,但涂鸦需设pointer-events: auto
- 导出涂鸦结果时,用compositeCanvas.getContext('2d').drawImage(底层Canvas, 0, 0); compositeCanvas.getContext('2d').drawImage(顶层Canvas, 0, 0)合成
- 若需保存为图片,调用compositeCanvas.toDataURL('image/png')即可
适配移动设备与手势操作
移动端需处理touch事件并适配屏幕密度(devicePixelRatio)。避免用clientX/Y直接计算坐标,应转换为Canvas逻辑坐标:
- 获取Canvas真实像素尺寸:canvas.width = canvas.clientWidth * window.devicePixelRatio
- 触摸点坐标换算:const rect = canvas.getBoundingClientRect(); const x = (touch.clientX - rect.left) * ratio
- 支持双指缩放画中画窗口?可监听touchstart双指距离,结合transform: scale()调整miniCanvas容器
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











