You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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();
  });
});

效果示意

效果示意图

任意形状裁剪适配

如果需要使用圆形、多边形等任意形状作为裁剪边界,只需修改两个地方:

  1. 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
});
  1. 裁剪逻辑中,在tempCtx.drawImage之前加入遮罩代码,将选框形状作为裁剪边界:
const path = marq_rect.toPathData();
const fabricPath = new fabric.Path(path);
fabricPath.render(ctx = tempCtx);
tempCtx.clip();

内容的提问来源于stack exchange,提问作者Faizan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 11:36:05