如何在Fabric.js中截取画布背景图指定区域生成可拖拽对象
Fabric.js 拖拽裁剪背景图并生成可移动裁剪对象实现方案
核心思路
你之前使用clipPath的方案是直接修改原背景图的裁剪属性,无法生成独立可拖拽的裁剪对象。正确的实现逻辑是:
- 绘制选框时保留原背景图不动
- 选框确认后,将选框覆盖的背景图区域导出为独立图像
- 把导出的图像作为新的fabric对象插入画布,实现拖拽功能
- 支持任意形状选框:仅需替换选框的构造类(如
fabric.Circle/fabric.Path),裁剪逻辑无需修改
完整实现代码
var marq_rect, isDown, origX, origY, bg_image; // 确保bg_image是你已经加载完成的背景图对象 var canvas = new fabric.Canvas('canvas', { preserveObjectStacking: true }); // 避免重复绑定事件,先解绑再绑定 canvas.off('mouse:down').on('mouse:down', function (o) { isDown = true; canvas.selection = false; var pointer = canvas.getPointer(o.e); origX = pointer.x; origY = pointer.y; // 这里可以替换为任意fabric形状类,比如fabric.Circle实现圆形裁剪 marq_rect = new fabric.Rect({ left: origX, top: origY, originX: 'left', originY: 'top', width: 0, height: 0, angle: 0, fill: 'rgba(0,0,0,0.1)', // 加半透明填充方便看选框范围 stroke: 'black', strokeDashArray: [2, 2], strokeWidth: 2, transparentCorners: false, selectable: false, id: 'marq_rect' }); canvas.add(marq_rect); }); canvas.off('mouse:move').on('mouse:move', function (o) { if (!isDown) return; var pointer = canvas.getPointer(o.e); marq_rect.set({ left: Math.min(origX, pointer.x), top: Math.min(origY, pointer.y), width: Math.abs(origX - pointer.x), height: Math.abs(origY - pointer.y) }); canvas.requestRenderAll(); }); canvas.off('mouse:up').on('mouse:up', function (o) { isDown = false; canvas.selection = true; // 选框太小不做裁剪处理 if (marq_rect.width < 5 || marq_rect.height < 5) { canvas.remove(marq_rect); return; } // 核心裁剪逻辑:导出选框区域的背景图像 // 先计算选框相对于背景图的坐标偏移 const rectLeft = marq_rect.left - bg_image.left; const rectTop = marq_rect.top - bg_image.top; // 创建临时canvas裁剪背景图 const tempCanvas = document.createElement('canvas'); tempCanvas.width = marq_rect.width; tempCanvas.height = marq_rect.height; const tempCtx = tempCanvas.getContext('2d'); // 绘制背景图的对应区域,兼容背景图缩放场景 tempCtx.drawImage( bg_image.getElement(), rectLeft / bg_image.scaleX, rectTop / bg_image.scaleY, marq_rect.width / bg_image.scaleX, marq_rect.height / bg_image.scaleY, 0, 0, marq_rect.width, marq_rect.height ); // 生成新的可拖拽图像对象 fabric.Image.fromURL(tempCanvas.toDataURL(), function(img) { img.set({ left: marq_rect.left, top: marq_rect.top, selectable: true, draggable: true }); canvas.add(img); // 移除选框 canvas.remove(marq_rect); canvas.requestRenderAll(); }); });
效果示意

任意形状裁剪适配
如果需要使用圆形、多边形等任意形状作为裁剪边界,只需修改两个地方:
mouse:down事件中,将new fabric.Rect替换为对应形状的构造类,比如圆形裁剪:
marq_rect = new fabric.Circle({ left: origX, top: origY, radius: 0, fill: 'rgba(0,0,0,0.1)', stroke: 'black', strokeDashArray: [2, 2], strokeWidth: 2, selectable: false });
- 裁剪逻辑中,在
tempCtx.drawImage之前加入遮罩代码,将选框形状作为裁剪边界:
const path = marq_rect.toPathData(); const fabricPath = new fabric.Path(path); fabricPath.render(ctx = tempCtx); tempCtx.clip();
内容的提问来源于stack exchange,提问作者Faizan
相关产品推荐
相关产品推荐

