模拟移动触摸设备时FabricJS渲染异常问题求助
问题背景
我使用ThreeJS管理canvas0(负责缩放、平移等交互),FabricJS负责canvas1的标注功能。Chrome浏览器鼠标操作下功能正常,但通过Chrome调试器的「Toggle Device Toolbar」模拟移动触摸设备时出现异常:绘制路径时实时渲染位置错误,结束触摸后路径位置才恢复正常。
经观察:FabricJS的lowerCanvas尺寸为代码定义的256256px,但upperCanvas(用于路径创建过程中实时渲染的画布)被莫名设置为512512px。页面刷新后upperCanvas尺寸偶尔正常(此时渲染正常),但多数时候尺寸异常,硬刷新无法解决。
复现步骤
- Chrome按F12打开调试器
- 点击「Toggle Device Toolbar」并选择模拟设备(如iPhone SE)
- 按F5刷新页面
- 在canvas0上进行绘制操作
核心疑问
- 是什么设置了upperCanvas为512*512px?
- 如何手动设置upperCanvas的尺寸?目前调用
fabricCanvas.setDimensions({width:256, height:256})仅能修改lowerCanvas的尺寸。
问题原因
FabricJS在触摸设备环境下,会自动根据**设备像素比(window.devicePixelRatio)**缩放upperCanvas的尺寸,以此适配高DPI屏幕。当Chrome模拟移动设备时,设备像素比被设置为2(例如iPhone SE的DPR为2),因此upperCanvas的尺寸会被自动放大为定义尺寸的2倍(256×2=512)。而代码未同步处理该缩放逻辑,导致实时渲染时坐标映射错误,触摸结束后FabricJS会重新计算坐标,所以位置恢复正常。
解决方案
1. 强制固定设备像素比
初始化FabricJS画布时,显式指定devicePixelRatio为1,阻止自动缩放upperCanvas:
const fabricCanvas = new fabric.Canvas('canvas1', { width: 256, height: 256, devicePixelRatio: 1 // 禁用自动DPI适配 });
2. 手动同步upperCanvas尺寸
若需要动态调整尺寸,可直接操作upperCanvas元素,同步修改其样式尺寸与画布内部尺寸:
// 获取upperCanvas元素 const upperCanvas = fabricCanvas.upperCanvasEl; // 设置样式尺寸(控制显示大小) upperCanvas.style.width = '256px'; upperCanvas.style.height = '256px'; // 设置画布内部像素尺寸(控制渲染精度) upperCanvas.width = 256; upperCanvas.height = 256; // 触发重绘确保生效 fabricCanvas.renderAll();
3. 同步ThreeJS与FabricJS的缩放比例
由于canvas0由ThreeJS管理存在缩放平移,需确保FabricJS的画布缩放与ThreeJS视图保持一致,避免触摸坐标偏移:
// 假设threeCamera是你的ThreeJS相机实例 const zoomLevel = threeCamera.zoom; fabricCanvas.setZoom(zoomLevel); // 可选:同步画布位置偏移 fabricCanvas.setViewportTransform([zoomLevel, 0, 0, zoomLevel, offsetX, offsetY]);
内容的提问来源于stack exchange,提问作者Avner Moshkovitz

