Fabric.js中如何实现无缩放的副画布显示?
解决Fabric.js双画布:主画布缩放绘图,副画布显示全局无缩放视图
嘿,我懂你的困扰了——你想要一个能缩放绘图的主画布,同时第二个画布始终显示它的完整无缩放全局视图,但现在副画布跟着主画布一起缩放了,对吧?问题出在你直接复制主画布的渲染像素数据,而主画布缩放后,渲染出来的内容已经是放大/缩小后的状态了。咱们用Fabric.js本身的对象机制来解决,会更靠谱!
问题根源
你之前用ctx1.getImageData()获取的是主画布经过缩放变换后的像素,所以副画布自然会显示缩放后的画面。正确的思路应该是让两个画布共享相同的对象集合,但副画布始终以1:1的比例渲染所有内容。
完整解决方案代码
<!DOCTYPE html> <html> <head> <style> canvas { border: 1px solid black; } #static { position: relative; top: -300px; left: 500px; } </style> </head> <body> This is interactive canvas <canvas id="scale" width="300" height="300"></canvas> <canvas id="static" width="300" height="300"></canvas> <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.1/fabric.min.js"></script> <script> var c1 = document.getElementById("scale"); var c2 = document.getElementById("static"); // 主画布(支持缩放、绘图) var mainCanvas = new fabric.Canvas(c1, { isDrawingMode: true }); // 副画布(仅显示全局无缩放视图,禁用交互) var staticCanvas = new fabric.Canvas(c2, { selection: false, enableRetinaScaling: false }); // 同步背景图到副画布 fabric.Image.fromURL( "https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg", img => { img.scaleToWidth(mainCanvas.width); mainCanvas.setBackgroundImage(img); // 副画布也设置相同的背景图 staticCanvas.setBackgroundImage(img.clone()); mainCanvas.requestRenderAll(); staticCanvas.requestRenderAll(); }, { crossOrigin: "Anonymous" } ); // 主画布缩放逻辑(保持不变) mainCanvas.on('mouse:wheel', function(opt) { var delta = opt.e.deltaY; var pointer = mainCanvas.getPointer(opt.e); var zoom = mainCanvas.getZoom(); zoom = zoom + delta/200; if (zoom > 20) zoom = 20; if (zoom < 0.01) zoom = 0.01; mainCanvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom); opt.e.preventDefault(); opt.e.stopPropagation(); }); // 同步主画布的对象变化到副画布 function syncCanvasObjects() { // 清空副画布现有对象 staticCanvas.clear(); // 复制主画布的所有对象到副画布 mainCanvas.getObjects().forEach(obj => { staticCanvas.add(obj.clone()); }); // 副画布始终保持1倍缩放,并且视图居中 staticCanvas.setZoom(1); staticCanvas.renderAll(); } // 监听主画布的关键事件,实时同步 mainCanvas.on('object:added', syncCanvasObjects); mainCanvas.on('object:modified', syncCanvasObjects); mainCanvas.on('object:removed', syncCanvasObjects); mainCanvas.on('after:render', syncCanvasObjects); </script> </body> </html>
关键改动说明
- 创建独立的副画布实例:不用直接操作context,而是用Fabric.js的
Canvas类创建副画布,禁用交互避免误操作。 - 对象同步机制:监听主画布的
object:added/modified/removed事件,每次对象变化时,把主画布的所有对象克隆到副画布。 - 强制副画布缩放比例:副画布始终设置
zoom=1,确保显示的是原始尺寸的全局视图。 - 替换定时复制为事件驱动:相比
setInterval,事件驱动更高效,能精准捕捉画布变化时机。
这样一来,不管你在主画布怎么缩放、绘图,副画布都会实时显示完整的无缩放全局视图啦!
内容的提问来源于stack exchange,提问作者vinkovsky
相关产品推荐
相关产品推荐

